brintos

brintos / linux-shallow public Read only

0
0
Text · 5.2 KiB · 17d71ed Raw
208 lines · c
1// SPDX-License-Identifier: GPL-2.0+2/*3 * cpcihp_generic.c4 *5 * Generic port I/O CompactPCI driver6 *7 * Copyright 2002 SOMA Networks, Inc.8 * Copyright 2001 Intel San Luis Obispo9 * Copyright 2000,2001 MontaVista Software Inc.10 *11 * This generic CompactPCI hotplug driver should allow using the PCI hotplug12 * mechanism on any CompactPCI board that exposes the #ENUM signal as a bit13 * in a system register that can be read through standard port I/O.14 *15 * Send feedback to <scottm@somanetworks.com>16 */17 18#include <linux/module.h>19#include <linux/init.h>20#include <linux/errno.h>21#include <linux/pci.h>22#include <linux/string.h>23#include "cpci_hotplug.h"24 25#define DRIVER_VERSION	"0.1"26#define DRIVER_AUTHOR	"Scott Murray <scottm@somanetworks.com>"27#define DRIVER_DESC	"Generic port I/O CompactPCI Hot Plug Driver"28 29#if !defined(MODULE)30#define MY_NAME	"cpcihp_generic"31#else32#define MY_NAME	THIS_MODULE->name33#endif34 35#define dbg(format, arg...)					\36	do {							\37		if (debug)					\38			printk(KERN_DEBUG "%s: " format "\n",	\39				MY_NAME, ## arg);		\40	} while (0)41#define err(format, arg...) printk(KERN_ERR "%s: " format "\n", MY_NAME, ## arg)42#define info(format, arg...) printk(KERN_INFO "%s: " format "\n", MY_NAME, ## arg)43#define warn(format, arg...) printk(KERN_WARNING "%s: " format "\n", MY_NAME, ## arg)44 45/* local variables */46static bool debug;47static char *bridge;48static u8 bridge_busnr;49static u8 bridge_slot;50static struct pci_bus *bus;51static u8 first_slot;52static u8 last_slot;53static u16 port;54static unsigned int enum_bit;55static u8 enum_mask;56 57static struct cpci_hp_controller_ops generic_hpc_ops;58static struct cpci_hp_controller generic_hpc;59 60static int __init validate_parameters(void)61{62	char *str;63	char *p;64	unsigned long tmp;65 66	if (!bridge) {67		info("not configured, disabling.");68		return -EINVAL;69	}70	str = bridge;71	if (!*str)72		return -EINVAL;73 74	tmp = simple_strtoul(str, &p, 16);75	if (p == str || tmp > 0xff) {76		err("Invalid hotplug bus bridge device bus number");77		return -EINVAL;78	}79	bridge_busnr = (u8) tmp;80	dbg("bridge_busnr = 0x%02x", bridge_busnr);81	if (*p != ':') {82		err("Invalid hotplug bus bridge device");83		return -EINVAL;84	}85	str = p + 1;86	tmp = simple_strtoul(str, &p, 16);87	if (p == str || tmp > 0x1f) {88		err("Invalid hotplug bus bridge device slot number");89		return -EINVAL;90	}91	bridge_slot = (u8) tmp;92	dbg("bridge_slot = 0x%02x", bridge_slot);93 94	dbg("first_slot = 0x%02x", first_slot);95	dbg("last_slot = 0x%02x", last_slot);96	if (!(first_slot && last_slot)) {97		err("Need to specify first_slot and last_slot");98		return -EINVAL;99	}100	if (last_slot < first_slot) {101		err("first_slot must be less than last_slot");102		return -EINVAL;103	}104 105	dbg("port = 0x%04x", port);106	dbg("enum_bit = 0x%02x", enum_bit);107	if (enum_bit > 7) {108		err("Invalid #ENUM bit");109		return -EINVAL;110	}111	enum_mask = 1 << enum_bit;112	return 0;113}114 115static int query_enum(void)116{117	u8 value;118 119	value = inb_p(port);120	return ((value & enum_mask) == enum_mask);121}122 123static int __init cpcihp_generic_init(void)124{125	int status;126	struct resource *r;127	struct pci_dev *dev;128 129	info(DRIVER_DESC " version: " DRIVER_VERSION);130	status = validate_parameters();131	if (status)132		return status;133 134	r = request_region(port, 1, "#ENUM hotswap signal register");135	if (!r)136		return -EBUSY;137 138	dev = pci_get_domain_bus_and_slot(0, bridge_busnr,139					  PCI_DEVFN(bridge_slot, 0));140	if (!dev || dev->hdr_type != PCI_HEADER_TYPE_BRIDGE) {141		err("Invalid bridge device %s", bridge);142		pci_dev_put(dev);143		return -EINVAL;144	}145	bus = dev->subordinate;146	pci_dev_put(dev);147 148	memset(&generic_hpc, 0, sizeof(struct cpci_hp_controller));149	generic_hpc_ops.query_enum = query_enum;150	generic_hpc.ops = &generic_hpc_ops;151 152	status = cpci_hp_register_controller(&generic_hpc);153	if (status != 0) {154		err("Could not register cPCI hotplug controller");155		return -ENODEV;156	}157	dbg("registered controller");158 159	status = cpci_hp_register_bus(bus, first_slot, last_slot);160	if (status != 0) {161		err("Could not register cPCI hotplug bus");162		goto init_bus_register_error;163	}164	dbg("registered bus");165 166	status = cpci_hp_start();167	if (status != 0) {168		err("Could not started cPCI hotplug system");169		goto init_start_error;170	}171	dbg("started cpci hp system");172	return 0;173init_start_error:174	cpci_hp_unregister_bus(bus);175init_bus_register_error:176	cpci_hp_unregister_controller(&generic_hpc);177	err("status = %d", status);178	return status;179 180}181 182static void __exit cpcihp_generic_exit(void)183{184	cpci_hp_stop();185	cpci_hp_unregister_bus(bus);186	cpci_hp_unregister_controller(&generic_hpc);187	release_region(port, 1);188}189 190module_init(cpcihp_generic_init);191module_exit(cpcihp_generic_exit);192 193MODULE_AUTHOR(DRIVER_AUTHOR);194MODULE_DESCRIPTION(DRIVER_DESC);195MODULE_LICENSE("GPL");196module_param(debug, bool, S_IRUGO | S_IWUSR);197MODULE_PARM_DESC(debug, "Debugging mode enabled or not");198module_param(bridge, charp, 0);199MODULE_PARM_DESC(bridge, "Hotswap bus bridge device, <bus>:<slot> (bus and slot are in hexadecimal)");200module_param(first_slot, byte, 0);201MODULE_PARM_DESC(first_slot, "Hotswap bus first slot number");202module_param(last_slot, byte, 0);203MODULE_PARM_DESC(last_slot, "Hotswap bus last slot number");204module_param_hw(port, ushort, ioport, 0);205MODULE_PARM_DESC(port, "#ENUM signal I/O port");206module_param(enum_bit, uint, 0);207MODULE_PARM_DESC(enum_bit, "#ENUM signal bit (0-7)");208