* [ANN] dummyphp
@ 2003-09-04 12:38 Rolf Eike Beer
2003-09-16 16:43 ` Greg KH
0 siblings, 1 reply; 2+ messages in thread
From: Rolf Eike Beer @ 2003-09-04 12:38 UTC (permalink / raw)
To: linux-hotplug
[-- Attachment #1: Type: text/plain, Size: 1207 bytes --]
Hi,
I think it's time to announce my dummyphp patches to the public.
Dummyphp adds a pseudo hotplug driver which allows to simulate hotplug events
by writing 0 or 1 to the power files of the PCI slots. It claims all PCI
slots it finds in the system, so it should not be used if any other hotplug
driver is present in the system.
Of course it's only a logical remove, the power to the device is still on so
there is a great chance to destroy important things (hardware!) if you pull
out a PCI board after disabling it. It's also possible to reactivate the
board again and work with it as before.
If you are using kernel 2.[56] and drivers using the new driver model it's not
necessary to unload the driver of the card before, the kernel will tell the
driver that the adapter has been removed and the driver will release his
internal stuff. With kernel 2.4 it's not that easy, dummyphp will refuse to
deactivate an adapter with loaded driver.
It does the same as fakephp.c which is in 2.6 now, with 2 differences:
-it does not remove the slot directory from sysfs on disable
-you can reenable slots
Any feedback welcome. Greg, it would be nice if you push this to Marcelo and
Linus.
Eike
[-- Attachment #2: 2.4.22-pre8-dummyphp.diff --]
[-- Type: text/x-diff, Size: 11871 bytes --]
diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/Config.in linux-2.4.22-pre8-caliban/drivers/hotplug/Config.in
--- linux-2.4.22-pre8-diff/drivers/hotplug/Config.in 2003-07-26 22:01:18.000000000 +0200
+++ linux-2.4.22-pre8-caliban/drivers/hotplug/Config.in 2003-07-25 14:56:14.000000000 +0200
@@ -6,6 +6,8 @@
dep_tristate 'Support for PCI Hotplug (EXPERIMENTAL)' CONFIG_HOTPLUG_PCI $CONFIG_EXPERIMENTAL $CONFIG_PCI
+dep_tristate ' Dummy PCI Hotplug driver' CONFIG_HOTPLUG_PCI_DUMMY $CONFIG_HOTPLUG_PCI
+
dep_tristate ' Compaq PCI Hotplug driver' CONFIG_HOTPLUG_PCI_COMPAQ $CONFIG_HOTPLUG_PCI $CONFIG_X86
dep_mbool ' Save configuration into NVRAM on Compaq servers' CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM $CONFIG_HOTPLUG_PCI_COMPAQ
if [ "$CONFIG_X86_IO_APIC" = "y" ]; then
diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/Makefile linux-2.4.22-pre8-caliban/drivers/hotplug/Makefile
--- linux-2.4.22-pre8-diff/drivers/hotplug/Makefile 2003-07-26 22:01:18.000000000 +0200
+++ linux-2.4.22-pre8-caliban/drivers/hotplug/Makefile 2003-07-25 14:56:14.000000000 +0200
@@ -4,11 +4,12 @@
O_TARGET := vmlinux-obj.o
-list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o
+list-multi := cpqphp.o pci_hotplug.o ibmphp.o acpiphp.o dummyphp.o
export-objs := pci_hotplug_core.o pci_hotplug_util.o
obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o
+obj-$(CONFIG_HOTPLUG_PCI_DUMMY) += dummyphp.o
obj-$(CONFIG_HOTPLUG_PCI_COMPAQ) += cpqphp.o
obj-$(CONFIG_HOTPLUG_PCI_IBM) += ibmphp.o
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
@@ -32,6 +33,8 @@
acpiphp_pci.o \
acpiphp_res.o
+dummyphp_objs := dummyphp_core.o
+
ifeq ($(CONFIG_HOTPLUG_PCI_COMPAQ_NVRAM),y)
cpqphp-objs += cpqphp_nvram.o
endif
@@ -50,3 +53,6 @@
acpiphp.o: $(acpiphp_objs)
$(LD) -r -o $@ $(acpiphp_objs)
+
+dummyphp.o: $(dummyphp_objs)
+ $(LD) -r -o $@ $(dummyphp_objs)
diff -Nau -x .depend -x '*vmlinux*' linux-2.4.22-pre8-diff/drivers/hotplug/dummyphp_core.c linux-2.4.22-pre8-caliban/drivers/hotplug/dummyphp_core.c
--- linux-2.4.22-pre8-diff/drivers/hotplug/dummyphp_core.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.4.22-pre8-caliban/drivers/hotplug/dummyphp_core.c 2003-07-26 22:00:46.000000000 +0200
@@ -0,0 +1,379 @@
+/*
+ * Dummy PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de>
+ *
+ * Based on code from:
+ * Vladimir Kondratiev <vladimir.kondratiev@intel.com>
+ * Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * Send feedback to <eike-kernel@sf-tec.de>
+ */
+
+/*
+ *
+ * This driver will "emulate" removing PCI devices from the system. If
+ * the "power" file is written to with "0" then the specified PCI device
+ * will be completely removed from the kernel.
+ *
+ * WARNING, this does NOT turn off the power to the PCI device. This is
+ * a "logical" removal, not a physical or electrical removal.
+ *
+ * Use this module at your own risk, you have been warned!
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+
+#define dbg(format, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "%s: " format, \
+ MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE 16 /* DUMMY-{BUS}:{DEV} */
+
+struct dummy_slot {
+ struct list_head node;
+ struct pci_bus *bus;
+ int devfn;
+ struct pci_dev *dev;
+ struct hotplug_slot *slot;
+};
+
+#ifndef CONFIG_HOTPLUG_PCI_DUMMY_MODULE
+ #define MY_NAME "dummyphp"
+#else
+ #define MY_NAME THIS_MODULE->name
+#endif
+
+static int debug;
+static LIST_HEAD(slot_list);
+
+#define DRIVER_VERSION "0.1"
+#define DRIVER_AUTHOR "Rolf Eike Beer <eike-kernel@sf-tec.de>"
+#define DRIVER_DESC "Dummy Hot Plug PCI Controller Driver"
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
+
+static int enable_slot (struct hotplug_slot *slot);
+static int disable_slot (struct hotplug_slot *slot);
+
+static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
+ .owner = THIS_MODULE,
+ .enable_slot = enable_slot,
+ .disable_slot = disable_slot,
+};
+
+/**
+ * configure_visit_pci_dev - callback to configure new discovered devices
+ * @wrapped_dev: the device
+ * @wrapped_bus: the bus of the device
+ */
+static int configure_visit_pci_dev (struct pci_dev_wrapped *wrapped_dev,
+ struct pci_bus_wrapped *wrapped_bus)
+{
+ struct pci_dev* dev = wrapped_dev->dev;
+
+ /* Create /proc/bus/pci proc entry for this device and bus device is on
+ Notify the drivers of the change */
+ dbg("%s - starting\n", __FUNCTION__);
+ if (dev) {
+ pci_proc_attach_device(dev);
+ pci_announce_device_to_drivers(dev);
+ }
+
+ return 0;
+}
+
+static struct pci_visit configure_functions = {
+ visit_pci_dev: configure_visit_pci_dev,
+};
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ */
+static int
+enable_slot(struct hotplug_slot *hotplug_slot)
+{
+ struct pci_dev dev0;
+ struct dummy_slot *slot;
+ struct pci_bus *child;
+ unsigned char bus;
+ struct pci_dev_wrapped wrapped_dev;
+ struct pci_bus_wrapped wrapped_bus;
+ int rc = 0;
+
+ if (!hotplug_slot)
+ return -ENODEV;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ /* enable the specified slot */
+ slot = (struct dummy_slot *) hotplug_slot->private;
+ slot->dev = pci_find_slot(slot->bus->number, slot->devfn);
+
+ /* Still NULL ? Well then scan for it ! */
+ if (slot->dev == NULL) {
+ dbg("INFO: pci_dev still null\n");
+ memset(&dev0, 0, sizeof(struct pci_dev));
+ dev0.bus = slot->bus;
+ dev0.devfn = slot->devfn;
+ dev0.sysdata = slot->bus->sysdata;
+
+ /* this will generate pci_dev structures for all functions,
+ but we will only call this case when lookup fails */
+ slot->dev = pci_scan_slot(&dev0);
+ if (slot->dev == NULL) {
+ dbg("ERROR: pci_dev still null\n");
+ return -ENODEV;
+ }
+ }
+
+ if (slot->dev->hdr_type == PCI_HEADER_TYPE_BRIDGE) {
+ pci_read_config_byte(slot->dev, PCI_SECONDARY_BUS, &bus);
+ child = (struct pci_bus*) pci_add_new_bus(slot->dev->bus,
+ (slot->dev), bus);
+ pci_do_scan_bus(child);
+
+ }
+
+ if (slot->dev) {
+ memset(&wrapped_dev, 0, sizeof(struct pci_dev_wrapped));
+ memset(&wrapped_bus, 0, sizeof(struct pci_bus_wrapped));
+ wrapped_dev.dev = slot->dev;
+ wrapped_bus.bus = slot->dev->bus;
+ rc = pci_visit_dev(&configure_functions, &wrapped_dev,
+ &wrapped_bus);
+ }
+ return rc;
+}
+
+/**
+ * is_pci_dev_in_use - check if a driver uses a pci device
+ * @dev: the device to check
+ */
+static int
+is_pci_dev_in_use(struct pci_dev* dev)
+{
+ /*
+ * dev->driver will be set if the device is in use by a new-style
+ * driver -- otherwise, check the device's regions to see if any
+ * driver has claimed them
+ */
+
+ int i, inuse = 0;
+
+ if (dev->driver)
+ return 1; /* assume driver feels responsible */
+
+ for (i = 0; !dev->driver && !inuse && (i < 6); i++) {
+ if (!pci_resource_start(dev, i))
+ continue;
+
+ if (pci_resource_flags(dev, i) & IORESOURCE_IO)
+ inuse = check_region(pci_resource_start(dev, i),
+ pci_resource_len(dev, i));
+ else if (pci_resource_flags(dev, i) & IORESOURCE_MEM)
+ inuse = check_mem_region(pci_resource_start(dev, i),
+ pci_resource_len(dev, i));
+ }
+
+ return inuse;
+
+}
+
+/**
+ * disable_slot - disable any adapter in this slot
+ * @hotplug_slot: slot to disable
+ */
+static int
+disable_slot(struct hotplug_slot *hotplug_slot)
+{
+ struct pci_dev* old_dev;
+ int func;
+ struct dummy_slot *slot;
+
+ if (!hotplug_slot)
+ return -ENODEV;
+
+ slot = (struct dummy_slot *) hotplug_slot->private;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ /* assume the driver feels responsible if dev->driver is set */
+ if (is_pci_dev_in_use(slot->dev)) {
+ if (slot->dev->driver) {
+ err("Can't disable slot %x:%x, driver %s still holds reference to it!",
+ slot->bus->number, PCI_SLOT(slot->devfn),
+ slot->dev->driver->name);
+ } else {
+ err("Can't disable slot %x:%x, a driver still holds reference to it!",
+ slot->bus->number, PCI_SLOT(slot->devfn));
+ }
+ return -EBUSY;
+ }
+
+ /* disable the specified slot */
+
+ for (func = 0; func < 8; func++) {
+ old_dev = pci_find_slot(slot->bus->number, slot->devfn+func);
+ if (old_dev) {
+ printk(KERN_INFO "Slot %s Removed <%s>\n",
+ old_dev->slot_name, old_dev->name);
+ pci_remove_device(old_dev);
+ }
+ }
+ hotplug_slot->info->power_status = 0;
+ slot->dev = NULL;
+
+ return 0;
+}
+
+/**
+ * scan_pci_bus - add an entry for every slot on this bus
+ * @bus: bus to scan
+ */
+static int __init
+scan_pci_bus(const struct pci_bus *bus)
+{
+ struct dummy_slot *dslot;
+ struct hotplug_slot *hp;
+ int retval = -ENOMEM;
+ unsigned int devfn;
+ struct pci_dev dev0;
+
+ memset(&dev0, 0, sizeof(dev0));
+ dev0.bus = (struct pci_bus*)bus;
+ dev0.sysdata = bus->sysdata;
+ for (devfn = 0; devfn < 0x100; devfn += 8) {
+ hp = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+ if (!hp)
+ goto error;
+
+ memset(hp, 0, sizeof(struct hotplug_slot));
+
+ hp->info = kmalloc(sizeof(struct hotplug_slot_info),
+ GFP_KERNEL);
+ if (!hp->info)
+ goto error_info;
+
+ memset(hp->info, 0, sizeof(struct hotplug_slot_info));
+
+ hp->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+ if ( !hp->name )
+ goto error_name;
+
+ dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+ if ( !dslot )
+ goto error_slot;
+
+ dslot->bus = (struct pci_bus *) bus;
+ dslot->devfn = devfn;
+ dslot->slot = hp;
+
+ hp->ops = &dummy_hotplug_slot_ops;
+ hp->private = (void *) dslot;
+
+ dslot->dev = pci_find_slot(dslot->bus->number, dslot->devfn);
+ hp->info->power_status = (dslot->dev != NULL);
+
+ hp->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+ hp->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+
+ snprintf(hp->name, SLOT_NAME_SIZE, "DUMMY-%02x:%02x",
+ dslot->bus->number, PCI_SLOT(dslot->devfn));
+
+ retval = pci_hp_register(hp);
+ if (retval) {
+ err("pci_hp_register failed with error %d\n", retval);
+ goto error_register;
+ }
+ list_add(&dslot->node, &slot_list);
+ }
+ return 0;
+
+error_register:
+ kfree(dslot);
+error_slot:
+ kfree(hp->name);
+error_name:
+ kfree(hp->info);
+error_info:
+ kfree(hp);
+error:
+ return retval;
+}
+
+/**
+ * scan_pci_buses - scan this bus and all child buses for slots
+ * @list: list of buses to scan
+ */
+static int __init
+pci_scan_buses(const struct list_head *list)
+{
+ int retval;
+ const struct list_head *l;
+
+ list_for_each(l,list) {
+ const struct pci_bus *b = pci_bus_b(l);
+ retval = scan_pci_bus(b);
+ if (retval)
+ return retval;
+ retval = pci_scan_buses(&b->children);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
+static void __exit
+cleanup_slots (void)
+{
+ struct list_head *tmp;
+ struct list_head *next;
+ struct dummy_slot *dslot;
+
+ list_for_each_safe (tmp, next, &slot_list) {
+ dslot = list_entry (tmp, struct dummy_slot, node);
+ pci_hp_deregister(dslot->slot);
+ }
+}
+
+
+static int __init
+dummyphp_init(void)
+{
+ info(DRIVER_DESC " version: " DRIVER_VERSION "\n");
+
+ return pci_scan_buses(&pci_root_buses);
+}
+
+
+static void __exit
+dummyphp_exit(void)
+{
+ cleanup_slots();
+}
+
+module_init(dummyphp_init);
+module_exit(dummyphp_exit);
[-- Attachment #3: 2.6.0-test4-dummyphp.diff --]
[-- Type: text/x-diff, Size: 10112 bytes --]
diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/Kconfig linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Kconfig
--- linux-2.6.0-test1/drivers/pci/hotplug/Kconfig 2003-07-14 05:33:13.000000000 +0200
+++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Kconfig 2003-07-21 18:11:26.000000000 +0200
@@ -46,6 +46,25 @@
When in doubt, say N.
+config HOTPLUG_PCI_DUMMY
+ tristate "Dummy PCI Hotplug driver"
+ depends on HOTPLUG_PCI
+ help
+ Say Y here if you want to use the dummy PCI hotplug driver. It can
+ be used to simulate PCI hotplug events if even if your system not
+ hotplug capable.
+
+ Be careful: it claims all PCI slots in the system. There may be
+ side effects on other hotplug drivers, so only use one hotplug driver
+ at the same time.
+
+ This code is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called cpqphp. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
+ When in doubt, say N.
+
config HOTPLUG_PCI_COMPAQ
tristate "Compaq PCI Hotplug driver"
depends on HOTPLUG_PCI && X86
diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/Makefile linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Makefile
--- linux-2.6.0-test1/drivers/pci/hotplug/Makefile 2003-07-14 05:36:33.000000000 +0200
+++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/Makefile 2003-07-21 18:11:26.000000000 +0200
@@ -9,6 +9,7 @@
obj-$(CONFIG_HOTPLUG_PCI_ACPI) += acpiphp.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_ZT5550) += cpcihp_zt5550.o
obj-$(CONFIG_HOTPLUG_PCI_CPCI_GENERIC) += cpcihp_generic.o
+obj-$(CONFIG_HOTPLUG_PCI_DUMMY) += dummyphp.o
pci_hotplug-objs := pci_hotplug_core.o
@@ -33,6 +34,8 @@
acpiphp_pci.o \
acpiphp_res.o
+dummyphp-objs := dummyphp_core.o
+
ifdef CONFIG_HOTPLUG_PCI_ACPI
EXTRA_CFLAGS += -D_LINUX -I$(TOPDIR)/drivers/acpi
ifdef CONFIG_ACPI_DEBUG
diff -Nau linux-2.6.0-test1/drivers/pci/hotplug/dummyphp_core.c linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/dummyphp_core.c
--- linux-2.6.0-test1/drivers/pci/hotplug/dummyphp_core.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.0-test1-bk2-caliban/drivers/pci/hotplug/dummyphp_core.c 2003-07-21 18:11:26.000000000 +0200
@@ -0,0 +1,331 @@
+/*
+ * Dummy PCI Hot Plug Controller Driver
+ *
+ * Copyright (c) 2003 Rolf Eike Beer <eike-kernel@sf-tec.de>
+ *
+ * Based on code from:
+ * Vladimir Kondratiev <vladimir.kondratiev@intel.com>
+ * Greg Kroah-Hartman <greg@kroah.com>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, version 2 of the License.
+ *
+ * Send feedback to <eike-kernel@sf-tec.de>
+ */
+
+/*
+ *
+ * This driver will "emulate" removing PCI devices from the system. If
+ * the "power" file is written to with "0" then the specified PCI device
+ * will be completely removed from the kernel.
+ *
+ * WARNING, this does NOT turn off the power to the PCI device. This is
+ * a "logical" removal, not a physical or electrical removal.
+ *
+ * Use this module at your own risk, you have been warned!
+ *
+ */
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include "pci_hotplug.h"
+#include "../pci.h"
+
+#ifndef CONFIG_HOTPLUG_PCI_DUMMY_MODULE
+ #define MY_NAME "dummyphp"
+#else
+ #define MY_NAME THIS_MODULE->name
+#endif
+
+#define dbg(format, arg...) \
+ do { \
+ if (debug) \
+ printk(KERN_DEBUG "%s: " format, \
+ MY_NAME , ## arg); \
+ } while (0)
+#define err(format, arg...) printk(KERN_ERR "%s: " format, MY_NAME , ## arg)
+#define info(format, arg...) printk(KERN_INFO "%s: " format, MY_NAME , ## arg)
+
+#define DRIVER_AUTHOR "Rolf Eike Beer <eike-kernel@sf-tec.de>"
+#define DRIVER_DESC "Dummy PCI Hot Plug Controller Driver"
+
+/* name size which is used for entries in pcihpfs */
+#define SLOT_NAME_SIZE 20 /* DUMMY-{DOMAIN}-{BUS}:{DEV} */
+
+struct dummy_slot {
+ struct list_head node;
+ struct hotplug_slot *slot;
+ struct pci_dev *dev;
+ struct pci_bus *bus;
+ int devfn;
+};
+
+static int debug;
+static LIST_HEAD(slot_list);
+
+static int enable_slot (struct hotplug_slot *slot);
+static int disable_slot (struct hotplug_slot *slot);
+
+static struct hotplug_slot_ops dummy_hotplug_slot_ops = {
+ .owner = THIS_MODULE,
+ .enable_slot = enable_slot,
+ .disable_slot = disable_slot,
+};
+
+/**
+ * dummy_release - free the memory of a slot
+ * @slot: slot pointer to remove
+ */
+static void dummy_release(struct hotplug_slot *slot)
+{
+ struct dummy_slot *dslot = slot->private;
+
+ list_del(&dslot->node);
+ kfree(dslot->slot->info);
+ kfree(dslot->slot);
+ if (dslot->dev)
+ pci_dev_put(dslot->dev);
+ kfree(dslot);
+}
+
+/**
+ * add_slot - add a new "hotplug" slot
+ * @dev - a struct pci_dev describing this slot (regardless if
+ * there is actually a device in this slot or not)
+ */
+static inline int __init
+add_slot(const struct pci_dev *dev)
+{
+ struct dummy_slot *dslot;
+ struct hotplug_slot *slot;
+ struct pci_dev *tmp_dev;
+ int retval = -ENOMEM;
+
+ slot = kmalloc(sizeof(struct hotplug_slot), GFP_KERNEL);
+ if (!slot)
+ goto error;
+
+ memset(slot, 0, sizeof(*slot));
+
+ slot->info = kmalloc(sizeof(struct hotplug_slot_info), GFP_KERNEL);
+ if (!slot->info)
+ goto error_slot;
+
+ memset(slot->info, 0, sizeof(struct hotplug_slot_info));
+
+ slot->info->max_bus_speed = PCI_SPEED_UNKNOWN;
+ slot->info->cur_bus_speed = PCI_SPEED_UNKNOWN;
+
+ slot->name = kmalloc(SLOT_NAME_SIZE, GFP_KERNEL);
+ if (!slot->name)
+ goto error_info;
+ dslot = kmalloc(sizeof(struct dummy_slot), GFP_KERNEL);
+ if (!dslot)
+ goto error_name;
+
+ dslot->bus = dev->bus;
+ dslot->devfn = dev->devfn;
+
+ tmp_dev = pci_find_slot(dslot->bus->number, dslot->devfn);
+ slot->info->power_status = (tmp_dev != NULL);
+
+ slot->ops = &dummy_hotplug_slot_ops;
+ slot->release = &dummy_release;
+ slot->private = (void *) dslot;
+
+ snprintf(slot->name, SLOT_NAME_SIZE, "DUMMY-%04x:%02x:%02x",
+ pci_domain_nr(dev->bus), dslot->bus->number,
+ PCI_SLOT(dslot->devfn));
+
+ retval = pci_hp_register(slot);
+ if (retval) {
+ err("pci_hp_register failed with error %d\n", retval);
+ goto error_dslot;
+ }
+
+ dslot->slot = slot;
+ if (slot->info->power_status) {
+ dslot->dev = pci_dev_get(tmp_dev);
+ } else {
+ dslot->dev = NULL;
+ }
+ list_add(&dslot->node, &slot_list);
+
+ return retval;
+
+error_dslot:
+ kfree(dslot);
+error_name:
+ kfree(slot->name);
+error_info:
+ kfree(slot->info);
+error_slot:
+ kfree(slot);
+error:
+ return retval;
+}
+
+/**
+ * scan_pci_bus - add an entry for every slot on this bus
+ * @bus: bus to scan
+ */
+static inline int __init
+scan_pci_bus(const struct pci_bus *bus)
+{
+ int retval;
+ struct pci_dev dev0;
+
+ memset(&dev0, 0, sizeof(struct pci_dev));
+ dev0.bus = (struct pci_bus*) bus;
+ dev0.sysdata = bus->sysdata;
+ for (dev0.devfn = 0; dev0.devfn < 0x100; dev0.devfn += 8) {
+ retval = add_slot(&dev0);
+ if (retval)
+ break;
+ }
+ return retval;
+}
+
+/**
+ * enable_slot - power on and enable a slot
+ * @hotplug_slot: slot to enable
+ */
+static int
+enable_slot(struct hotplug_slot *hotplug_slot)
+{
+ struct dummy_slot *dslot;
+ struct pci_dev *dev;
+ int num;
+
+ if (!hotplug_slot)
+ return -ENODEV;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, hotplug_slot->name);
+
+ /* enable the specified slot */
+ dslot = (struct dummy_slot *) hotplug_slot->private;
+
+ dev = dslot->dev;
+ if (dev == NULL)
+ dev = pci_find_slot(dslot->bus->number, dslot->devfn);
+
+ /* No pci device, we need to create it then */
+ if (dev == NULL) {
+ dbg("INFO: pci_dev still null\n");
+
+ num = pci_scan_slot(dslot->bus, dslot->devfn);
+ if (num)
+ pci_bus_add_devices(dslot->bus);
+
+ dev = pci_find_slot(dslot->bus->number, dslot->devfn);
+ if (dev == NULL) {
+ dbg("ERROR: pci_dev still null\n");
+ return -ENODEV;
+ }
+ dslot->dev = pci_dev_get(dev);
+ }
+
+ return 0;
+}
+
+/**
+ * disable_slot - disable any adapter in this slot
+ * @slot: slot to disable
+ */
+static int
+disable_slot(struct hotplug_slot *slot)
+{
+ struct dummy_slot *dslot;
+
+ if (!slot)
+ return -ENODEV;
+
+ dslot = (struct dummy_slot *) slot->private;
+
+ dbg("%s - physical_slot = %s\n", __FUNCTION__, slot->name);
+
+ /* don't disable bridged devices just yet, we can't handle them easily... */
+ if (dslot->dev->subordinate) {
+ err("Can't remove PCI devices with other PCI devices behind it yet.\n");
+ return -EPERM;
+ }
+
+ if (!dslot->dev) {
+ dbg("No device in slot, exiting");
+ return -ENODEV;
+ }
+ pci_dev_put(dslot->dev);
+
+ /* remove the device from the pci core */
+ info("Slot %s removed\n", pci_name(dslot->dev));
+ pci_remove_bus_device(dslot->dev);
+
+ dslot->dev = NULL;
+
+ slot->info->power_status = 0;
+
+ return 0;
+}
+
+/**
+ * pci_scan_buses - scan this bus and all child buses for slots
+ * @list: list of buses to scan
+ */
+static int __init
+pci_scan_buses(const struct list_head *list)
+{
+ int retval;
+ const struct list_head *l;
+
+ list_for_each(l,list) {
+ const struct pci_bus *b = pci_bus_b(l);
+ retval = scan_pci_bus(b);
+ if (retval)
+ return retval;
+ retval = pci_scan_buses(&b->children);
+ if (retval)
+ return retval;
+ }
+ return 0;
+}
+
+static inline void __exit
+cleanup_slots(void)
+{
+ struct list_head *tmp;
+ struct list_head *next;
+ struct dummy_slot *dslot;
+
+ list_for_each_safe (tmp, next, &slot_list) {
+ dslot = list_entry (tmp, struct dummy_slot, node);
+ pci_hp_deregister(dslot->slot);
+ }
+}
+
+static int __init
+dummyphp_init(void)
+{
+ info(DRIVER_DESC "\n");
+
+ return pci_scan_buses(&pci_root_buses);
+}
+
+static void __exit
+dummyphp_exit(void)
+{
+ cleanup_slots();
+}
+
+module_init(dummyphp_init);
+module_exit(dummyphp_exit);
+
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+MODULE_PARM(debug, "i");
+MODULE_PARM_DESC(debug, "Debugging mode enabled or not");
^ permalink raw reply [flat|nested] 2+ messages in thread
* Re: [ANN] dummyphp
2003-09-04 12:38 [ANN] dummyphp Rolf Eike Beer
@ 2003-09-16 16:43 ` Greg KH
0 siblings, 0 replies; 2+ messages in thread
From: Greg KH @ 2003-09-16 16:43 UTC (permalink / raw)
To: linux-hotplug
On Thu, Sep 04, 2003 at 02:38:39PM +0200, Rolf Eike Beer wrote:
>
> If you are using kernel 2.[56] and drivers using the new driver model it's not
> necessary to unload the driver of the card before, the kernel will tell the
> driver that the adapter has been removed and the driver will release his
> internal stuff. With kernel 2.4 it's not that easy, dummyphp will refuse to
> deactivate an adapter with loaded driver.
Why? Why can't it just disconnect the device like the other pci hotplug
drivers do in 2.4?
> It does the same as fakephp.c which is in 2.6 now, with 2 differences:
>
> -it does not remove the slot directory from sysfs on disable
> -you can reenable slots
>
> Any feedback welcome. Greg, it would be nice if you push this to Marcelo and
> Linus.
I really don't like the way the slots are named here, that's why I made
fakephp to only show the existing devices in the system. I'd really
like a change to fakephp that just rescans the pci bus to see if any new
devices have been added by the bios, to handle the "add a new device"
issue. I'll go add a patch to the pci hotplug core to export the sysfs
directory to make this easier to support.
Oh, and this is probably the wrong mailing list for this, there is a pci
hotplug linux mailing list that you might want to post this to (that's
where the other pci hotplug driver authors are.)
thanks,
greg k-h
-------------------------------------------------------
This sf.net email is sponsored by:ThinkGeek
Welcome to geek heaven.
http://thinkgeek.com/sf
_______________________________________________
Linux-hotplug-devel mailing list http://linux-hotplug.sourceforge.net
Linux-hotplug-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-hotplug-devel
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2003-09-16 16:43 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-09-04 12:38 [ANN] dummyphp Rolf Eike Beer
2003-09-16 16:43 ` Greg KH
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).