Is there a user space pci rescan method?
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)
Thanks,
Dave:)
-----Original Message-----
From: Alan Cox [mailto:[email protected]]
Sent: Wednesday, September 22, 2004 4:05 PM
To: Dave Aubin
Cc: Linux Kernel Mailing List
Subject: Re: Is there a user space pci rescan method?
Quoted 7 lines · Dave Aubin
Hi,
Is there a user space or perhaps simple kernel module way to rescan
the pci bus? I currently have a user mode program modify the pci bus,but I can not push the user mode program to the bios for reasons I can't get in to.
Take a look at drivers/hotplug. As far as Linux is concerned you've got a hotplug PCI slot if you have to poke at it. Alternatively if its a general funny such as a card you have to poke to reveal devices behind it a PCI quirk would probably do the trick.
Quoted 6 lines · Dave Aubin
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)
There is a "fake" hotplug driver which works for normal pci. But last time I looked at it, it did only support hot disabling, not hot enabling
- but this surely can be fixed.
Thanks,
Jan
Quoted 11 lines · Jan Dittmer
Quoted 6 lines · Dave Aubin
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)There is a "fake" hotplug driver which works for normal pci. But last time I looked at it, it did only support hot disabling, not hot enabling
- but this surely can be fixed.
Yes, hot "enabling" has been left for someone to add to the driver, if you read the comments in it :)
Good luck,
greg k-h
Quoted 11 lines · Greg KH
Quoted 9 lines · Jan Dittmer
Quoted 6 lines · Dave Aubin
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)
Quoted 8 lines
Quoted 3 lines
There is a "fake" hotplug driver which works for normal pci. But last time I looked at it, it did only support hot disabling, not hot enabling
- but this surely can be fixed.Yes, hot "enabling" has been left for someone to add to the driver, if you read the comments in it :)
I read them and started playing around with this driver. So echoing 0 in
/sys/bus/pci/slots/*/power disables the pci device. The problem I see
is, that the tree with the device is disappearing. So how am I supposed to re-enable the device. I've no real hotplug hardware to play with, so I'm bound to reading the source code in drivers/pci/hotplug and testing with fakephp. I found your utility pcihpview (v0.5) which searches for /sys/bus/pci/hotplug_slots. But grepping the kernel tree doesn't show any mentioning of it - so I suppose it is outdated.
Is there anywhere a current article (or Documentation/pci_hotplug.txt) about the state of PCI hotplug and how this is supposed to work?
Thanks,
Jan
ps: Meanwhile I found dummyphp on the pcihpd mailinglist. This doesn't remove the device from /sys/bus/pci/slots/*/power . Still I'd like to know the offical way.
Quoted 10 lines · Jan Dittmer
Quoted 9 lines · Greg KH
Quoted 8 lines · Jan Dittmer
Quoted 6 lines · Dave Aubin
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)
Quoted 6 lines
Quoted 6 lines
Quoted 3 lines
There is a "fake" hotplug driver which works for normal pci. But last time I looked at it, it did only support hot disabling, not hot enabling
- but this surely can be fixed.Yes, hot "enabling" has been left for someone to add to the driver, if you read the comments in it :)
Hot enabling works for month in dummyphp...
Quoted 10 lines
I read them and started playing around with this driver. So echoing 0 in
/sys/bus/pci/slots/*/powerdisables the pci device. The problem I see
is, that the tree with the device is disappearing. So how am I supposed to re-enable the device. I've no real hotplug hardware to play with, so I'm bound to reading the source code indrivers/pci/hotplugand testing with fakephp. I found your utility pcihpview (v0.5) which searches for/sys/bus/pci/hotplug_slots. But grepping the kernel tree doesn't show any mentioning of it - so I suppose it is outdated.
Is there anywhere a current article (orDocumentation/pci_hotplug.txt) about the state of PCI hotplug and how this is supposed to work?
Just search the archive of [email protected] for dummyphp, this is the version that works. I'll rediff it soon and hope Greg will accept it this time.
Message-Id to search for: <[email protected]>
Eike
Quoted 5 lines · Rolf Eike Beer
Just search the archive of [email protected] for dummyphp, this is the version that works. I'll rediff it soon and hope Greg will accept it this time.
Message-Id to search for: <[email protected]>
You didn't read my p.s. ... I found it and it's working quite nice. Already discovered a bug in dv1394. Just one thing: Can you strip DUMMY- from the name in /sys/bus/pci/slots/ ? It's really ugly and you can't mix different hotplug drivers anyway.
Thanks,
Jan
Quoted 8 lines · Jan Dittmer
Quoted 5 lines · Rolf Eike Beer
Just search the archive of [email protected] for dummyphp, this is the version that works. I'll rediff it soon and hope Greg will accept it this time.
Message-Id to search for: <[email protected]>
You didn't read my p.s. ... I found it and it's working quite nice. Already
Ehm, yes. Sorry, around 1900 local time and no real breakfast until now.
Quoted 3 lines
discovered a bug in dv1394. Just one thing: Can you strip DUMMY- from the name in
/sys/bus/pci/slots/? It's really ugly and you can't mix different hotplug drivers anyway.
Sounds reasonable.
Eike
Am Donnerstag, 23. September 2004 19:05 schrieb Rolf Eike Beer:
Quoted 12 lines
Quoted 10 lines · Jan Dittmer
Quoted 6 lines · Rolf Eike Beer
Just search the archive of [email protected] for dummyphp, this is the version that works. I'll rediff it soon and hope Greg will accept it this time.
Message-Id to search for:
<[email protected]>You didn't read my p.s. ... I found it and it's working quite nice. Already
Quoted 7 lines
Ehm, yes. Sorry, around 1900 local time and no real breakfast until now.
Quoted 3 lines
discovered a bug in dv1394. Just one thing: Can you strip DUMMY- from the name in
/sys/bus/pci/slots/? It's really ugly and you can't mix different hotplug drivers anyway.Sounds reasonable.
Ok, here we go. This is my current diff that I use for my tests at home. It adds dummyphp and cleans up fakephp a lot (read: kills it). Changes from last version:
-removed some dead comments
-removed some unused instructions
-reordered allocation in add_slot to do less memory allocations if there is
no device in slot
-changed param "usedonly" to "showunused" so it behaves like fakephp at the
first look: if you load dummyphp without parameters there are only slots with devices in it.
-removed "DUMMY-" prefix to entries in /sys/bus/pci/slots/
Please send comments so I can send it for inclusion soon.
Eike
drivers/pci/hotplug/Kconfig 2004-09-23 21:58:35.000000000 +0200 renamed from drivers/pci/hotplug/Kconfig 2004-09-23 21:16:49.000000000 +0200 +13 -10
@@ -19,26 +19,29 @@ When in doubt, say N. -config HOTPLUG_PCI_FAKE - tristate "Fake PCI Hotplug driver" +config HOTPLUG_PCI_DUMMY + tristate "Dummy PCI Hotplug driver" depends on HOTPLUG_PCI help - Say Y here if you want to use the fake PCI hotplug driver. It can - be used to simulate PCI hotplug events if even if your system is - not PCI hotplug capable. + Say Y here if you want to use the dummy PCI hotplug driver. It can + be used to simulate PCI hotplug events even if your system is not + PCI hotplug capable. 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. + device will be completely removed from the kernel. Writing "1" to + the power file will bring the device back. + + Be careful: it claims all PCI slots in the system with a device in it. + There will be side effects on other hotplug drivers, so do NOT use + another hotplug driver at the same time. 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! - - To compile this driver as a module, choose M here: the - module will be called fakephp. + To compile this driver as a module, choose M here: the module + will be called dummyphp. When in doubt, say N.
drivers/pci/hotplug/Makefile 2004-09-17 16:30:26.000000000 +0200 renamed from drivers/pci/hotplug/Makefile 2004-09-23 21:16:49.000000000 +0200 +1 -1
@@ -3,7 +3,7 @@ # obj-$(CONFIG_HOTPLUG_PCI) += pci_hotplug.o -obj-$(CONFIG_HOTPLUG_PCI_FAKE) += fakephp.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
drivers/pci/hotplug/dummyphp.c 2004-09-23 23:11:23.000000000 +0200 renamed from drivers/pci/hotplug/dummyphp.c 1970-01-01 01:00:00.000000000 +0100 +386 -0
386 lines not on this page · raw message
drivers/pci/hotplug/fakephp.c 1970-01-01 01:00:00.000000000 +0100 renamed from drivers/pci/hotplug/fakephp.c 2004-08-14 07:37:25.000000000 +0200 +0 -232
232 lines not on this page · raw message
Quoted 12 lines · Rolf Eike Beer
Ok, here we go. This is my current diff that I use for my tests at home. It adds dummyphp and cleans up fakephp a lot (read: kills it). Changes from last version:
(quoted diff) +0
-5-removed some dead comments -removed some unused instructions -reordered allocation in add_slot to do less memory allocations if there is no device in slot -changed param "usedonly" to "showunused" so it behaves like fakephp at the first look: if you load dummyphp without parameters there are only slots with devices in it. -removed "DUMMY-" prefix to entries in /sys/bus/pci/slots/
Quoted 1 line
Please send comments so I can send it for inclusion soon.
Well, first of all I think you should just submit a patch to add dummyphp and not removing fakephp in the same step. Also you somehow mis-copied the patch to your mail app - most (not all) tabs are converted to one space (or is it just thunderbird displaying the mail?). Can you resend it? Then I'll give it a try. Greg wrote in another mail that the 'proper' way of 'powering up' device slots should be to rescan the entire bus. I don't know, your approach certainly seems easier, but you are bound to either display all pci slots which may come to live or just the ones in the system already, which means you cannot rescan slots which weren't equipped on boot up. So perhaps adding a rescan method to fakephp is indeed cleaner.
Jan
Am Freitag, 24. September 2004 13:42 schrieben Sie:
Quoted 14 lines
Quoted 13 lines · Rolf Eike Beer
Ok, here we go. This is my current diff that I use for my tests at home. It adds dummyphp and cleans up fakephp a lot (read: kills it). Changes from last version:
(quoted diff) +0
-3-removed some dead comments -removed some unused instructions -reordered allocation in add_slot to do less memory allocations if thereis no device in slot
-changed param "usedonly" to "showunused" so it behaves like fakephp at the first look: if you load dummyphp without parameters there are only slots with devices in it.
-removed "DUMMY-" prefix to entries in/sys/bus/pci/slots/
Quoted 4 lines
Quoted 1 line
Please send comments so I can send it for inclusion soon.
Well, first of all I think you should just submit a patch to add dummyphp and not removing fakephp in the same step. Also you somehow mis-copied the
I said it's my test diff and that I'll redo it for submission ;)
Quoted 2 lines
patch to your mail app - most (not all) tabs are converted to one space (or is it just thunderbird displaying the mail?). Can you resend it? Then I'll
Yes, looks like KMail has eaten it. Hey KDE guys, is this intentional or was this my fault?
You can get it from http://opensource.sf-tec.de/kernel/fake_vs_dummy.diff
Quoted 6 lines
give it a try. Greg wrote in another mail that the 'proper' way of 'powering up' device slots should be to rescan the entire bus. I don't know, your approach certainly seems easier, but you are bound to either display all pci slots which may come to live or just the ones in the system already, which means you cannot rescan slots which weren't equipped on boot up. So perhaps adding a rescan method to fakephp is indeed cleaner.
This is for simulating hotplug events. I don't know how there could be a slot where you put in a device that has not been there on system bootup. Ok, you can trigger such a case by disabling a slot, rmmod dummyphp, modprobe dummyphp again. Greg didn't like dummyphp to display all logical slots even if there is no device in them - which I can understand, under normal circumstances you will never have a use for this extra slots. If you want them just do "modprobe dummyphp showunused=1" and you'll get them all.
Normally you will just remove and bring back one or two cards in the system (e.g. your NIC or sound card, depending on xmms or irc being on top of your priority list *g*). So from my point of view it's a good idea to keep the slot dirs on remove so you can just go back in your command history and replace 0 with 1 to get the device back. I don't see why bus structure or whatever may ever change so rescanning the whole bus is IMHO a bit overkill.
Adding a rescan file is also extra work, the power file is there automagically ;)
Eike
Quoted 6 lines · Rolf Eike Beer
Normally you will just remove and bring back one or two cards in the system (e.g. your NIC or sound card, depending on xmms or irc being on top of your priority list *g*). So from my point of view it's a good idea to keep the slot dirs on remove so you can just go back in your command history and replace 0 with 1 to get the device back. I don't see why bus structure or whatever may ever change so rescanning the whole bus is IMHO a bit overkill.
My point was, I load dummyphp with showunused=0 and only get dirs for the slots with devices in them. Now I decide to put a network card (or whatever I have to spare) in an empty slot, hope that the system doesn't reboot immediately, and voila I don't have any /sys/bus/pci/slots dir to enable the slot and have to reboot nevertheless. Or does the pci system a rescan if I reinsert the module?
Thanks,
Jan
Am Freitag, 24. September 2004 14:16 schrieben Sie:
Quoted 9 lines
Quoted 7 lines · Rolf Eike Beer
Normally you will just remove and bring back one or two cards in the system (e.g. your NIC or sound card, depending on xmms or irc being on top of your priority list *g*). So from my point of view it's a good idea to keep the slot dirs on remove so you can just go back in your command history and replace 0 with 1 to get the device back. I don't see why bus structure or whatever may ever change so rescanning the whole bus is IMHO a bit overkill.
Quoted 6 lines
My point was, I load dummyphp with showunused=0 and only get dirs for the slots with devices in them. Now I decide to put a network card (or whatever I have to spare) in an empty slot, hope that the system doesn't reboot immediately, and voila I don't have any
/sys/bus/pci/slotsdir to enable the slot and have to reboot nevertheless. Or does the pci system a rescan if I reinsert the module?
In this case you have to "rmmod dummyphp; modprobe dummyphp showunused=1" to get all slots and try to enable the device. We have tested it once with a special PCI debugging board where we can electrically disable the PCI bus so we don't kill our hardware. The problem was that on reenabling a interrupt storm killed the machine, I don't remember the exact problem. IIRC it looked like the kernel found the device but the PCI bridge got confused by the new device (or something like this). I don't know if there is a way to survive this situation as the bridges in "normal" hardware are not hotplug aware. Greg?
If there is a way I will try to impleement it, but for now this is beyound my knowledge.
Eike
Quoted 17 lines · Rolf Eike Beer
Am Freitag, 24. September 2004 14:16 schrieben Sie:
Quoted 9 lines
Quoted 7 lines · Rolf Eike Beer
Normally you will just remove and bring back one or two cards in the system (e.g. your NIC or sound card, depending on xmms or irc being on top of your priority list *g*). So from my point of view it's a good idea to keep the slot dirs on remove so you can just go back in your command history and replace 0 with 1 to get the device back. I don't see why bus structure or whatever may ever change so rescanning the whole bus is IMHO a bit overkill.
Quoted 6 lines
My point was, I load dummyphp with showunused=0 and only get dirs for the slots with devices in them. Now I decide to put a network card (or whatever I have to spare) in an empty slot, hope that the system doesn't reboot immediately, and voila I don't have any
/sys/bus/pci/slotsdir to enable the slot and have to reboot nevertheless. Or does the pci system a rescan if I reinsert the module?
Quoted 9 lines
In this case you have to "rmmod dummyphp; modprobe dummyphp showunused=1" to get all slots and try to enable the device. We have tested it once with a special PCI debugging board where we can electrically disable the PCI bus so we don't kill our hardware. The problem was that on reenabling a interrupt storm killed the machine, I don't remember the exact problem. IIRC it looked like the kernel found the device but the PCI bridge got confused by the new device (or something like this). I don't know if there is a way to survive this situation as the bridges in "normal" hardware are not hotplug aware. Greg?
Hm, don't know, but that's the whole reason people want this, so it should work :)
The main reason I don't like showing _all_ possible pci devices like dummyphp does is that it doesn't handle adding a new device (like you just said), and the fact that you forgot to handle pci domains. If you add support for PCI domains, then the list of files in that directory will pretty much be unusable.
Please just add the "rescan" support to fakephp, and everyone will be happy...
thanks,
greg k-h
Quoted 11 lines
Quoted 8 lines
to get all slots and try to enable the device. We have tested it once with a special PCI debugging board where we can electrically disable the PCI bus so we don't kill our hardware. The problem was that on reenabling a interrupt storm killed the machine, I don't remember the exact problem. IIRC it looked like the kernel found the device but the PCI bridge got confused by the new device (or something like this). I don't know if there is a way to survive this situation as the bridges in "normal" hardware are not hotplug aware. Greg?
Hm, don't know, but that's the whole reason people want this, so it should work :)
IMHO they want it for testing logical removal, hot removal without hardware support is just too dangerous to test with dummyphp. Or what am I missing?
Quoted 5 lines
The main reason I don't like showing _all_ possible pci devices like dummyphp does is that it doesn't handle adding a new device (like you just said), and the fact that you forgot to handle pci domains. If you add support for PCI domains, then the list of files in that directory will pretty much be unusable.
Ehm? Did you read the code? I use the PCI domains of the slots and buses. And by default there are only slots with devices in it shown now.
Quoted 2 lines
Please just add the "rescan" support to fakephp, and everyone will be happy...
That can't be. I hate fakephp ;)
Eike
Quoted 2 lines · Greg KH
Please just add the "rescan" support to fakephp, and everyone will be happy...
Well, I started to work on this for fun. What I currently have is a stand-alone module which rescans the pci bus on insert and enables previously disabled devices. This works (at least with my ieee1394 port). Problem is, that fakephp does not get notified about this new pci device and no new file is created in /sys/bus/pci/slots. So I'm going to add this rescan functionality directly to fakephp.
Question is: where? My current idea is a fake hotplug slot "rescan" in /sys/bus/pci/slots , where you can write "1" into the "power" attribute. FWIW I've attached the standalone module and a kernel patch which rips out the pci_bus_add_device functionality from pci_bus_add_devices.
Jan
include/linux/pci.h +1 -0
@@ -704,6 +704,7 @@int pci_scan_slot (struct pci_bus *bus,int devfn);struct pci_dev *pci_scan_single_device (struct pci_bus *bus,int devfn);unsigned int pci_scan_child_bus (struct pci_bus *bus); +void pci_bus_add_device (struct pci_dev *dev);void pci_bus_add_devices (struct pci_bus *bus);void pci_name_device (struct pci_dev *dev);char *pci_class_name (u32 class);
drivers/pci/bus.c +16 -10
@@ -69,6 +69,20 @@ }/** +* add a single device +*/ +void __devinit pci_bus_add_device (struct pci_dev *dev) { +device_add (&dev->dev); + +spin_lock (&pci_bus_lock); +list_add_tail (&dev->global_list, &pci_devices); +spin_unlock (&pci_bus_lock); + +pci_proc_attach_device (dev); +pci_create_sysfs_dev_files (dev); +} + +/** * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices *
@@ -91,16 +105,7 @@*/ if (!list_empty (&dev->global_list))continue ; - -device_add (&dev->dev); - -spin_lock (&pci_bus_lock); -list_add_tail (&dev->global_list, &pci_devices); -spin_unlock (&pci_bus_lock); - -pci_proc_attach_device (dev); -pci_create_sysfs_dev_files (dev); - +pci_bus_add_device (dev); }list_for_each_entry (dev, &bus->devices, bus_list) {
@@ -136,5 +141,6 @@ }EXPORT_SYMBOL (pci_bus_alloc_resource); +EXPORT_SYMBOL (pci_bus_add_device);EXPORT_SYMBOL (pci_bus_add_devices);EXPORT_SYMBOL (pci_enable_bridges);
ifneq ($(KERNELRELEASE),)
obj-m := pcirescan.o
else
KDIR := /lib/modules/$(shell uname -r)/build
# KDIR := ../pcirescan
PWD := $(shell pwd)
default:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
endif
/**
* rescan the pci bus on insert
* Jan Dittmer <[email protected]>
*
* heavily based on a similar module from
* Vladimir Kondratiev, [email protected] */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/errno.h>
/**
* Rescan slot.
* First, determine whether card in the slot has changed. It is
* done by compare of old and actual devices for function 0.
* If change detected, old device(s) removed, other functions
* scanned if it is multi-function dev, new devices inserted. *
* @param temp Device template. Should be set: bus and devfn.
* @return Device for function 0
*/
void pci_rescan_slot(struct pci_dev *temp)
{
struct pci_bus *bus = temp->bus;
struct pci_dev* old_dev = pci_find_slot(bus->number,temp->devfn);
struct pci_dev *dev = NULL;
int func = 0;
int new_multi = 0; /* new multifunction device */
u8 hdr_type;
/* function 0 */
if (!pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type)) {
temp->hdr_type = hdr_type & 0x7f;
new_multi=hdr_type & 0x80;
if (!old_dev) {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
printk("Found new device on %s function %x:%x %x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7,
hdr_type);
pci_bus_add_device(dev);
}
}
if (new_multi) { /* continue scanning for other functions */
/* printk("Scanning subfunctions\n"); */
for (func = 1, temp->devfn++; func < 8; func++, temp->devfn++) {
// printk("%x\n", func);
if (pci_read_config_byte(temp, PCI_HEADER_TYPE, &hdr_type))
continue;
temp->hdr_type = hdr_type & 0x7f;
old_dev = pci_find_slot(bus->number, temp->devfn);
if (!old_dev) {
dev = pci_scan_single_device(bus, temp->devfn);
if (dev) {
printk("Found new device on %s function %x:%x %x\n",
bus->name, temp->devfn >> 3,
temp->devfn & 7,
hdr_type);
printk("Prettyname %s\n", dev->pretty_name);
// from drivers/pci/bus.c, pci_bus_add_devices
pci_bus_add_device(dev);
}
}
}
}
}
}/**
* Rescan PCI bus.
* Assumed, some slots may have changed its content.
* Find old information about each slot and the new one.
* If they match, do nothing. Otherwise,
* remove/insert proper devices.
*
* @param bus
*/
static void pci_rescan_bus(const struct pci_bus *bus)
{
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) {
dev0.devfn = devfn;
pci_rescan_slot(&dev0);
}
}static void pci_rescan_buses(const struct list_head *list)
{
const struct list_head *l;
list_for_each(l,list) {
const struct pci_bus *b = pci_bus_b(l);
/*
printk("Scanning Bus %d:%d:%d, %s\n", b->number,
b->primary, b->secondary, b->name);
*/
pci_rescan_bus(b);
pci_rescan_buses(&b->children);
}
}static int pci_rescan_init(void)
{
pci_rescan_buses(&pci_root_buses);
return -ENODEV;
}static void pci_rescan_exit(void)
{}
module_init(pci_rescan_init);module_exit(pci_rescan_exit);
MODULE_DESCRIPTION("Do PCI bus rescan");MODULE_AUTHOR("jdi");
Quoted 6 lines · Jan Dittmer
Quoted 2 lines · Greg KH
Please just add the "rescan" support to fakephp, and everyone will be happy...
Quoted 10 lines
Well, I started to work on this for fun. What I currently have is a stand-alone module which rescans the pci bus on insert and enables previously disabled devices. This works (at least with my ieee1394 port). Problem is, that fakephp does not get notified about this new pci device and no new file is created in
/sys/bus/pci/slots. So I'm going to add this rescan functionality directly to fakephp.
Question is: where? My current idea is a fake hotplug slot "rescan" in/sys/bus/pci/slots, where you can write "1" into the "power" attribute. FWIW I've attached the standalone module and a kernel patch which rips out thepci_bus_add_devicefunctionality frompci_bus_add_devices.
Well, here is a quick & dirty hack, which adds this function to enable_slot in fakephp. So if you write "1" in the power attribute of any slot, the whole bus gets rescanned (you still need the pci_bus_add_device.patch from the previous mail).
Thanks,
Jan
drivers/pci/hotplug/fakephp.c +103 -0
@@ -165,8 +165,111 @@err ("Problem unregistering a slot %s\n" , dslot->slot->name); } +/** +* Rescan slot. +* First, determine whether card in the slot has changed. It is +* done by compare of old and actual devices for function 0. +* If change detected, old device(s) removed, other functions +* scanned if it is multi-function dev, new devices inserted. +* +* @param temp Device template. Should be set: bus and devfn. +* @return Device for function 0 +*/ +static void pci_rescan_slot (struct pci_dev *temp) +{ +struct pci_bus *bus = temp->bus; +struct pci_dev * old_dev =pci_find_slot (bus->number, temp->devfn); +struct pci_dev *dev =NULL ; +int func =0 ; +int new_multi =0 ;/* new multifunction device */ +u8 hdr_type; +if (!pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) { + temp->hdr_type = hdr_type &0x7f ; + new_multi=hdr_type &0x80 ; +if (!old_dev) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +printk ("Found new device on %s function %x:%x %x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 , + hdr_type); +pci_bus_add_device (dev); +add_slot (dev); + } + } +if (new_multi) {/* continue scanning for other functions */ +for (func =1 , temp->devfn++; func <8 ; func++, temp->devfn++) { +// printk("%x\n", func); +if (pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) +continue ; + temp->hdr_type = hdr_type &0x7f ; + + old_dev =pci_find_slot (bus->number, temp->devfn); +if (!old_dev) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +printk ("Found new device on %s function %x:%x %x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 , + hdr_type); +// from drivers/pci/bus.c, pci_bus_add_devices +pci_bus_add_device (dev); +// add fakephp slot +add_slot (dev); + } + } + } + } + } +} + + +/** +* Rescan PCI bus. +* Assumed, some slots may have changed its content. +* Find old information about each slot and the new one. +* If they match, do nothing. Otherwise, +* remove/insert proper devices. +* +* @param bus +*/ +static void pci_rescan_bus (const struct pci_bus *bus) +{ +unsigned int devfn; +struct pci_dev *dev; + dev =kmalloc (sizeof (struct pci_dev ),GFP_KERNEL ); +if (!dev) +return ; + +memset (dev,0 ,sizeof (dev)); + dev->bus = (struct pci_bus *)bus; + dev->sysdata = bus->sysdata; +for (devfn =0 ; devfn <0x100 ; devfn +=8 ) { + dev->devfn = devfn; +pci_rescan_slot (dev); + } +kfree (dev); +} + +static void pci_rescan_buses (const struct list_head *list) +{ +const struct list_head *l; +list_for_each (l,list) { +const struct pci_bus *b =pci_bus_b (l); +pci_rescan_bus (b); +pci_rescan_buses (&b->children); + } +} + +static void pci_rescan (void ) { +pci_rescan_buses (&pci_root_buses); +} + +static int enable_slot (struct hotplug_slot *hotplug_slot) { +/* mis-use enable_slot for rescanning of pci bus */ +pci_rescan ();return -ENODEV ; }
Quoted 21 lines · Jan Dittmer
Quoted 7 lines · Jan Dittmer
Quoted 2 lines · Greg KH
Please just add the "rescan" support to fakephp, and everyone will be happy...
Quoted 10 lines
Well, I started to work on this for fun. What I currently have is a stand-alone module which rescans the pci bus on insert and enables previously disabled devices. This works (at least with my ieee1394 port). Problem is, that fakephp does not get notified about this new pci device and no new file is created in
/sys/bus/pci/slots. So I'm going to add this rescan functionality directly to fakephp.
Question is: where? My current idea is a fake hotplug slot "rescan" in/sys/bus/pci/slots, where you can write "1" into the "power" attribute. FWIW I've attached the standalone module and a kernel patch which rips out thepci_bus_add_devicefunctionality frompci_bus_add_devices.
Quoted 4 lines
Well, here is a quick & dirty hack, which adds this function to
enable_slotin fakephp. So if you write "1" in the power attribute of any slot, the whole bus gets rescanned (you still need the pci_bus_add_device.patch from the previous mail).
Well one last update. This version also handles deactivation of subfunctions correctly, ie. when the parent should be disabled, all subfunctions will be disabled first.
Small demo:
# modprobe fakephp # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:02.0 0000:04:02.1 0000:04:02.2 0000:04:03.0 0000:04:03.1 # echo -n 0 > /sys/bus/pci/slots/0000\:04\:02.0/power # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:03.0 0000:04:03.1 # echo -n 1 > /sys/bus/pci/slots/0000\:03\:01.0/power # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:02.0 0000:04:02.1 0000:04:02.2 0000:04:03.0 0000:04:03.1 #lspci | grep "0000:04" 0000:04:02.0 Multimedia audio controller: Creative Labs SB Audigy (rev 03) 0000:04:02.1 Input device controller: Creative Labs SB Audigy MIDI/Game port (rev 03) 0000:04:02.2 FireWire (IEEE 1394): Creative Labs SB Audigy FireWire Port 0000:04:03.0 SCSI storage controller: Adaptec AHA-3960D / AIC-7899A U160/m (rev 01) 0000:04:03.1 SCSI storage controller: Adaptec AHA-3960D / AIC-7899A U160/m (rev 01)
Sound plays fine afterwards.
Actually this only works only once or twice. At some point the removal command will hang (but I suppose this is a problem with either snd-emu10k1 or ieee1394).
Jan
drivers/pci/hotplug/fakephp.c +134 -0
@@ -165,14 +165,126 @@err ("Problem unregistering a slot %s\n" , dslot->slot->name); } +/** +* Rescan slot. +* Tries hard not to re-enable already existing devices +* also handle scanning of subfunctions +* +* @param temp Device template. Should be set: bus and devfn. +*/ +static void pci_rescan_slot (struct pci_dev *temp) +{ +struct pci_bus *bus = temp->bus; +struct pci_dev * old_dev =pci_find_slot (bus->number, temp->devfn); +struct pci_dev *dev =NULL ; +int func =0 ; +int new_multi =0 ;/* new multifunction device */ +u8 hdr_type; +if (!pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) { + temp->hdr_type = hdr_type &0x7f ; + new_multi=hdr_type &0x80 ; +if (!old_dev) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +dbg ("Found new device on %s function %x:%x %x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 , + hdr_type); +pci_bus_add_device (dev); +add_slot (dev); + } + } +if (new_multi) {/* continue scanning for other functions */ +for (func =1 , temp->devfn++; func <8 ; func++, temp->devfn++) { +if (pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) +continue ; + temp->hdr_type = hdr_type &0x7f ; + + old_dev =pci_find_slot (bus->number, temp->devfn); +if (!old_dev) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +dbg ("Found new device on %s function %x:%x %x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 , + hdr_type); +pci_bus_add_device (dev); +add_slot (dev); + } + } + } + } + } +} + + +/** +* Rescan PCI bus. +* call pci_rescan_slot for each possible function of the bus +* +* @param bus +*/ +static void pci_rescan_bus (const struct pci_bus *bus) +{ +unsigned int devfn; +struct pci_dev *dev; + dev =kmalloc (sizeof (struct pci_dev ),GFP_KERNEL ); +if (!dev) +return ; + +memset (dev,0 ,sizeof (dev)); + dev->bus = (struct pci_bus *)bus; + dev->sysdata = bus->sysdata; +for (devfn =0 ; devfn <0x100 ; devfn +=8 ) { + dev->devfn = devfn; +pci_rescan_slot (dev); + } +kfree (dev); +} + +/* recursively scan all buses */ +static void pci_rescan_buses (const struct list_head *list) +{ +const struct list_head *l; +list_for_each (l,list) { +const struct pci_bus *b =pci_bus_b (l); +pci_rescan_bus (b); +pci_rescan_buses (&b->children); + } +} + +/* initiate rescan of all pci buses */ +static void pci_rescan (void ) { +pci_rescan_buses (&pci_root_buses); +} + +static int enable_slot (struct hotplug_slot *hotplug_slot) { +/* mis-use enable_slot for rescanning of the pci bus */ +pci_rescan ();return -ENODEV ; } +/* find the hotplug_slot for the pci_dev */ +static struct hotplug_slot *get_slot_from_dev (struct pci_dev *dev) +{ +struct dummy_slot *dslot; + +list_for_each_entry (dslot, &slot_list, node) { +if (dslot->dev == dev) +return dslot->slot; + } +return NULL ; +} + +static int disable_slot (struct hotplug_slot *slot) {struct dummy_slot *dslot; +struct hotplug_slot *hslot; +struct pci_dev *dev; +int func;if (!slot)return -ENODEV ;
@@ -185,6 +297,28 @@err ("Can't remove PCI devices with other PCI devices behind it yet.\n" );return -ENODEV ; } +/* search for subfunctions and disable them first */ +if (!(dslot->dev->devfn &7 )) { +dbg ("Searching for subfunctions\n" ); +for (func=1 ;func<8 ;func++) { +dbg ("Considering %x %x+%x\n" , + dslot->dev->bus->number, + dslot->dev->devfn, + func); + dev =pci_find_slot (dslot->dev->bus->number, dslot->dev->devfn + func); +if (dev) { +dbg ("Slot %s Removed <%s>\n" , dslot->dev->slot_name, dslot->dev->pretty_name); + hslot =get_slot_from_dev (dev); +if (hslot) +disable_slot (hslot); +else { +err ("Hotplug slot not found for subordinate pci-device\n" ); +return -ENODEV ; + } + }else +dbg ("No device in slot found\n" ); + } + }/* remove the device from the pci core */ pci_remove_bus_device (dslot->dev);
include/linux/pci.h +1 -0
@@ -704,6 +704,7 @@int pci_scan_slot (struct pci_bus *bus,int devfn);struct pci_dev *pci_scan_single_device (struct pci_bus *bus,int devfn);unsigned int pci_scan_child_bus (struct pci_bus *bus); +void pci_bus_add_device (struct pci_dev *dev);void pci_bus_add_devices (struct pci_bus *bus);void pci_name_device (struct pci_dev *dev);char *pci_class_name (u32 class);
drivers/pci/bus.c +16 -10
@@ -69,6 +69,20 @@ }/** +* add a single device +*/ +void __devinit pci_bus_add_device (struct pci_dev *dev) { +device_add (&dev->dev); + +spin_lock (&pci_bus_lock); +list_add_tail (&dev->global_list, &pci_devices); +spin_unlock (&pci_bus_lock); + +pci_proc_attach_device (dev); +pci_create_sysfs_dev_files (dev); +} + +/** * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices *
@@ -91,16 +105,7 @@*/ if (!list_empty (&dev->global_list))continue ; - -device_add (&dev->dev); - -spin_lock (&pci_bus_lock); -list_add_tail (&dev->global_list, &pci_devices); -spin_unlock (&pci_bus_lock); - -pci_proc_attach_device (dev); -pci_create_sysfs_dev_files (dev); - +pci_bus_add_device (dev); }list_for_each_entry (dev, &bus->devices, bus_list) {
@@ -136,5 +141,6 @@ }EXPORT_SYMBOL (pci_bus_alloc_resource); +EXPORT_SYMBOL (pci_bus_add_device);EXPORT_SYMBOL (pci_bus_add_devices);EXPORT_SYMBOL (pci_enable_bridges);
Quoted 22 lines · Jan Dittmer
Quoted 21 lines · Jan Dittmer
Quoted 17 lines · Jan Dittmer
Quoted 2 lines · Greg KH
Please just add the "rescan" support to fakephp, and everyone will be happy...
Well, I started to work on this for fun. What I currently have is a stand-alone module which rescans the pci bus on insert and enables previously disabled devices. This works (at least with my ieee1394 port). Problem is, that fakephp does not get notified about this new pci device and no new file is created in
/sys/bus/pci/slots. So I'm going to add this rescan functionality directly to fakephp.
Question is: where? My current idea is a fake hotplug slot "rescan" in/sys/bus/pci/slots, where you can write "1" into the "power" attribute. FWIW I've attached the standalone module and a kernel patch which rips out thepci_bus_add_devicefunctionality frompci_bus_add_devices.
Quoted 8 lines
Quoted 4 lines
Well, here is a quick & dirty hack, which adds this function to
enable_slotin fakephp. So if you write "1" in the power attribute of any slot, the whole bus gets rescanned (you still need the pci_bus_add_device.patch from the previous mail).Well one last update. This version also handles deactivation of subfunctions correctly, ie. when the parent should be disabled, all subfunctions will be disabled first.
Nice, I like it. Care to resend this in 2 different emails, with a good description in the subject line, and in the body of the email, and a "Signed-off-by:" line in it too (as per the Documentation/SubmittingPatches file) so I can apply these to the tree?
thanks,
greg k-h
PATCH 1/2 fakephp: introduce pci_bus_add_device
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from pci_bus_add_devices to pci_bus_add_device to add a single device to sysfs, procfs and the global device list.
===== drivers/pci/bus.c 1.9 vs edited =====
drivers/pci/bus.c 2004-10-31 23:24:10 +01:00 renamed from drivers/pci/bus.c 2004-04-11 00:27:59 +02:00 +20 -10
@@ -69,6 +69,24 @@ } /** + * add a single device + * @dev: device to add + * + * This adds a single pci device to the global + * device list and adds sysfs and procfs entries for it + */ +void __devinit pci_bus_add_device(struct pci_dev *dev) { + device_add(&dev->dev); + + spin_lock(&pci_bus_lock); + list_add_tail(&dev->global_list, &pci_devices); + spin_unlock(&pci_bus_lock); + + pci_proc_attach_device(dev); + pci_create_sysfs_dev_files(dev); +} + +/** * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices *
@@ -91,16 +109,7 @@ */ if (!list_empty(&dev->global_list)) continue; - - device_add(&dev->dev); - - spin_lock(&pci_bus_lock); - list_add_tail(&dev->global_list, &pci_devices); - spin_unlock(&pci_bus_lock); - - pci_proc_attach_device(dev); - pci_create_sysfs_dev_files(dev); - + pci_bus_add_device(dev); } list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -136,5 +145,6 @@ } EXPORT_SYMBOL(pci_bus_alloc_resource); +EXPORT_SYMBOL(pci_bus_add_device); EXPORT_SYMBOL(pci_bus_add_devices); EXPORT_SYMBOL(pci_enable_bridges);
===== include/linux/pci.h 1.139 vs edited =====
include/linux/pci.h 2004-10-31 23:10:04 +01:00 renamed from include/linux/pci.h 2004-10-06 00:56:26 +02:00 +1 -0
@@ -713,6 +713,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); unsigned int pci_scan_child_bus(struct pci_bus *bus); +void pci_bus_add_device(struct pci_dev *dev); void pci_bus_add_devices(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class);
Re: [patch 1/2] fakephp: introduce pci_bus_add_device
Quoted 11 lines · Jan Dittmer
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from
pci_bus_add_devicestopci_bus_add_deviceto add a single device to sysfs, procfs and the global device list.Signed-off-by Jan Dittmer <[email protected]>=====
drivers/pci/bus.c1.9 vs edited =====
drivers/pci/bus.c 2004-10-31 23:24:10 +01:00 line 78
Quoted 10 lines
drivers/pci/bus.c 2004-10-31 23:24:10 +01:00 renamed from drivers/pci/bus.c 2004-04-11 00:27:59 +02:00 +7
-0@@ -69,6 +69,24 @@ } /** + * add a single device + * @dev: device to add + * + * This adds a single pci device to the global + * device list and adds sysfs and procfs entries for it + */ +void __devinit pci_bus_add_device(struct pci_dev *dev) {
the brace should go to a line of it's own
Re: [patch 1/2] fakephp: introduce pci_bus_add_device
Quoted 10 lines · Christoph Hellwig
Quoted 6 lines · Jan Dittmer
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from
pci_bus_add_devicestopci_bus_add_deviceto add a single device to sysfs, procfs and the global device list.Signed-off-by Jan Dittmer <[email protected]>the brace should go to a line of it's own
Sorry about that, updated patch follows:
drivers/pci/bus.c 2004-11-01 10:41:27 +01:00 renamed from drivers/pci/bus.c 2004-04-11 00:27:59 +02:00 +21 -10
@@ -69,6 +69,25 @@ } /** + * add a single device + * @dev: device to add + * + * This adds a single pci device to the global + * device list and adds sysfs and procfs entries + */ +void __devinit pci_bus_add_device(struct pci_dev *dev) +{ + device_add(&dev->dev); + + spin_lock(&pci_bus_lock); + list_add_tail(&dev->global_list, &pci_devices); + spin_unlock(&pci_bus_lock); + + pci_proc_attach_device(dev); + pci_create_sysfs_dev_files(dev); +} + +/** * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices *
@@ -91,16 +110,7 @@ */ if (!list_empty(&dev->global_list)) continue; - - device_add(&dev->dev); - - spin_lock(&pci_bus_lock); - list_add_tail(&dev->global_list, &pci_devices); - spin_unlock(&pci_bus_lock); - - pci_proc_attach_device(dev); - pci_create_sysfs_dev_files(dev); - + pci_bus_add_device(dev); } list_for_each_entry(dev, &bus->devices, bus_list) {
@@ -136,5 +146,6 @@ } EXPORT_SYMBOL(pci_bus_alloc_resource); +EXPORT_SYMBOL(pci_bus_add_device); EXPORT_SYMBOL(pci_bus_add_devices); EXPORT_SYMBOL(pci_enable_bridges);
include/linux/pci.h 2004-10-31 23:10:04 +01:00 renamed from include/linux/pci.h 2004-10-06 00:56:26 +02:00 +1 -0
@@ -713,6 +713,7 @@ int pci_scan_slot(struct pci_bus *bus, int devfn); struct pci_dev * pci_scan_single_device(struct pci_bus *bus, int devfn); unsigned int pci_scan_child_bus(struct pci_bus *bus); +void pci_bus_add_device(struct pci_dev *dev); void pci_bus_add_devices(struct pci_bus *bus); void pci_name_device(struct pci_dev *dev); char *pci_class_name(u32 class);
Re: [patch 1/2] fakephp: introduce pci_bus_add_device
Quoted 8 lines · Jan Dittmer
Quoted 7 lines · Christoph Hellwig
Quoted 5 lines · Jan Dittmer
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from
pci_bus_add_devicestopci_bus_add_deviceto add a single device to sysfs, procfs and the global device list.
Quoted 5 lines
Quoted 3 lines
Quoted 1 line
Signed-off-by Jan Dittmer <[email protected]>the brace should go to a line of it's own
Sorry about that, updated patch follows:
Ugh, your email client ate all of the tabs and spit them out as spaces for this patch :(
Care to try it again?
thanks,
greg k-h
Re: [patch 1/2] fakephp: introduce pci_bus_add_device
Quoted 16 lines · Greg KH
Quoted 14 lines · Jan Dittmer
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jan Dittmer
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from
pci_bus_add_devicestopci_bus_add_deviceto add a single device to sysfs, procfs and the global device list.Signed-off-by Jan Dittmer <[email protected]>the brace should go to a line of it's own
Quoted 7 lines
Quoted 1 line
Sorry about that, updated patch follows:
Ugh, your email client ate all of the tabs and spit them out as spaces for this patch :(
Care to try it again?
Well, I still don't know how to do this with Thunderbird as non attachment. So here it goes as attachment.
Jan
===== drivers/pci/bus.c 1.9 vs edited =====
drivers/pci/bus.c +21 -10
@@ -69,6 +69,25 @@ }/** +* add a single device +* @dev: device to add +* +* This adds a single pci device to the global +* device list and adds sysfs and procfs entries +*/ +void __devinit pci_bus_add_device (struct pci_dev *dev) +{ +device_add (&dev->dev); + +spin_lock (&pci_bus_lock); +list_add_tail (&dev->global_list, &pci_devices); +spin_unlock (&pci_bus_lock); + +pci_proc_attach_device (dev); +pci_create_sysfs_dev_files (dev); +} + +/** * pci_bus_add_devices - insert newly discovered PCI devices * @bus: bus to check for new devices *
@@ -91,16 +110,7 @@*/ if (!list_empty (&dev->global_list))continue ; - -device_add (&dev->dev); - -spin_lock (&pci_bus_lock); -list_add_tail (&dev->global_list, &pci_devices); -spin_unlock (&pci_bus_lock); - -pci_proc_attach_device (dev); -pci_create_sysfs_dev_files (dev); - +pci_bus_add_device (dev); }list_for_each_entry (dev, &bus->devices, bus_list) {
@@ -136,5 +146,6 @@ }EXPORT_SYMBOL (pci_bus_alloc_resource); +EXPORT_SYMBOL (pci_bus_add_device);EXPORT_SYMBOL (pci_bus_add_devices);EXPORT_SYMBOL (pci_enable_bridges);
===== include/linux/pci.h 1.139 vs edited =====
include/linux/pci.h +1 -0
@@ -713,6 +713,7 @@int pci_scan_slot (struct pci_bus *bus,int devfn);struct pci_dev *pci_scan_single_device (struct pci_bus *bus,int devfn);unsigned int pci_scan_child_bus (struct pci_bus *bus); +void pci_bus_add_device (struct pci_dev *dev);void pci_bus_add_devices (struct pci_bus *bus);void pci_name_device (struct pci_dev *dev);char *pci_class_name (u32 class);
Greg KH
AppliedRe: [patch 1/2] fakephp: introduce pci_bus_add_device
Quoted 20 lines · Jan Dittmer
Quoted 19 lines · Greg KH
Quoted 15 lines · Jan Dittmer
Quoted 11 lines · Christoph Hellwig
Quoted 6 lines · Jan Dittmer
fakephp needs to add newly discovered devices to the global pci list. Therefore seperate out the appropriate chunk from
pci_bus_add_devicestopci_bus_add_deviceto add a single device to sysfs, procfs and the global device list.Signed-off-by Jan Dittmer <[email protected]>the brace should go to a line of it's own
Sorry about that, updated patch follows:
Quoted 7 lines
Quoted 4 lines
Ugh, your email client ate all of the tabs and spit them out as spaces for this patch :(
Care to try it again?
Well, I still don't know how to do this with Thunderbird as non attachment. So here it goes as attachment.
I'll live with that :)
Applied, thanks,
greg k-h
PATCH 2/2 fakephp: add pci bus rescan ability
In reply to Greg KHThis adds the ability to rescan the pci bus for newly inserted, reprogrammed or previously disabled pci devices.
To initiate a rescan you need to write '1' to any of the /sys/bus/pci/slots/*/power control files. No known pci devices will be touched.
Additionally this fixes a bug, when someone tries to disable a device with subfunctions. The subfunctions will be disabled first now.
Short demo:
# modprobe fakephp # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:02.0 0000:04:02.1 0000:04:02.2 0000:04:03.0 0000:04:03.1 # echo -n 0 > /sys/bus/pci/slots/0000\:04\:02.0/power # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:03.0 0000:04:03.1 # echo -n 1 > /sys/bus/pci/slots/0000\:03\:01.0/power # ls /sys/bus/pci/slots | grep "0000:04" 0000:04:02.0 0000:04:02.1 0000:04:02.2 0000:04:03.0 0000:04:03.1 # lspci | grep "0000:04" 0000:04:02.0 Multimedia audio controller: Creative Labs SB Audigy (rev 03) 0000:04:02.1 Input device controller: Creative Labs SB Audigy MIDI/Gameport (rev 03) 0000:04:02.2 FireWire (IEEE 1394): Creative Labs SB Audigy FireWire Port 0000:04:03.0 SCSI storage controller: Adaptec AHA-3960D / AIC-7899A U160/m (rev 01) 0000:04:03.1 SCSI storage controller: Adaptec AHA-3960D / AIC-7899A U160/m (rev 01)
===== drivers/pci/hotplug/fakephp.c 1.2 vs edited =====
drivers/pci/hotplug/fakephp.c +127 -1
@@ -165,14 +165,123 @@err ("Problem unregistering a slot %s\n" , dslot->slot->name); } +/** +* Rescan slot. +* Tries hard not to re-enable already existing devices +* also handles scanning of subfunctions +* +* @param temp Device template. Should be set: bus and devfn. +*/ +static void pci_rescan_slot (struct pci_dev *temp) +{ +struct pci_bus *bus = temp->bus; +struct pci_dev *dev; +int func; +u8 hdr_type; +if (!pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) { + temp->hdr_type = hdr_type &0x7f ; +if (!pci_find_slot (bus->number, temp->devfn)) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +dbg ("New device on %s function %x:%x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 ); +pci_bus_add_device (dev); +add_slot (dev); + } + } +/* multifunction device? */ +if (!(hdr_type &0x80 )) +return ; + +/* continue scanning for other functions */ +for (func =1 , temp->devfn++; func <8 ; func++, temp->devfn++) { +if (pci_read_config_byte (temp,PCI_HEADER_TYPE , &hdr_type)) +continue ; + temp->hdr_type = hdr_type &0x7f ; + +if (!pci_find_slot (bus->number, temp->devfn)) { + dev =pci_scan_single_device (bus, temp->devfn); +if (dev) { +dbg ("New device on %s function %x:%x\n" , + bus->name, temp->devfn >>3 , + temp->devfn &7 ); +pci_bus_add_device (dev); +add_slot (dev); + } + } + } + } +} + + +/** +* Rescan PCI bus. +* call pci_rescan_slot for each possible function of the bus +* +* @param bus +*/ +static void pci_rescan_bus (const struct pci_bus *bus) +{ +unsigned int devfn; +struct pci_dev *dev; + dev =kmalloc (sizeof (struct pci_dev ),GFP_KERNEL ); +if (!dev) +return ; + +memset (dev,0 ,sizeof (dev)); + dev->bus = (struct pci_bus *)bus; + dev->sysdata = bus->sysdata; +for (devfn =0 ; devfn <0x100 ; devfn +=8 ) { + dev->devfn = devfn; +pci_rescan_slot (dev); + } +kfree (dev); +} + +/* recursively scan all buses */ +static void pci_rescan_buses (const struct list_head *list) +{ +const struct list_head *l; +list_for_each (l,list) { +const struct pci_bus *b =pci_bus_b (l); +pci_rescan_bus (b); +pci_rescan_buses (&b->children); + } +} + +/* initiate rescan of all pci buses */ +static inline void pci_rescan (void ) { +pci_rescan_buses (&pci_root_buses); +} + +static int enable_slot (struct hotplug_slot *hotplug_slot) { +/* mis-use enable_slot for rescanning of the pci bus */ +pci_rescan ();return -ENODEV ; } +/* find the hotplug_slot for the pci_dev */ +static struct hotplug_slot *get_slot_from_dev (struct pci_dev *dev) +{ +struct dummy_slot *dslot; + +list_for_each_entry (dslot, &slot_list, node) { +if (dslot->dev == dev) +return dslot->slot; + } +return NULL ; +} + +static int disable_slot (struct hotplug_slot *slot) {struct dummy_slot *dslot; +struct hotplug_slot *hslot; +struct pci_dev *dev; +int func;if (!slot)return -ENODEV ;
@@ -185,6 +294,23 @@err ("Can't remove PCI devices with other PCI devices behind it yet.\n" );return -ENODEV ; } +/* search for subfunctions and disable them first */ +if (!(dslot->dev->devfn &7 )) { +for (func =1 ; func <8 ; func++) { + dev =pci_find_slot (dslot->dev->bus->number, + dslot->dev->devfn + func); +if (dev) { + hslot =get_slot_from_dev (dev); +if (hslot) +disable_slot (hslot); +else { +err ("Hotplug slot not found for subfunction of PCI device\n" ); +return -ENODEV ; + } + }else +dbg ("No device in slot found\n" ); + } + }/* remove the device from the pci core */ pci_remove_bus_device (dslot->dev);
@@ -227,6 +353,6 @@MODULE_AUTHOR (DRIVER_AUTHOR );MODULE_DESCRIPTION (DRIVER_DESC );MODULE_LICENSE ("GPL" ); -MODULE_PARM (debug,"i" ); +module_param (debug, int,S_IRUGO |S_IWUSR );MODULE_PARM_DESC (debug,"Debugging mode enabled or not" );
Greg KH
AppliedRe: [patch 2/2] fakephp: add pci bus rescan ability
Quoted 7 lines · Jan Dittmer
This adds the ability to rescan the pci bus for newly inserted, reprogrammed or previously disabled pci devices.
To initiate a rescan you need to write '1' to any of the/sys/bus/pci/slots/*/powercontrol files. No known pci devices will be touched.
Additionally this fixes a bug, when someone tries to disable a device with subfunctions. The subfunctions will be disabled first now.
Very nice, thanks for doing this work.
Applied, thanks.
greg k-h
Quoted 6 lines · Jan Dittmer
My point was, I load dummyphp with showunused=0 and only get dirs for the slots with devices in them. Now I decide to put a network card (or whatever I have to spare) in an empty slot, hope that the system doesn't reboot immediately, and voila I don't have any
/sys/bus/pci/slotsdir to enable the slot and have to reboot nevertheless. Or does the pci system a rescan if I reinsert the module?
That is DANGEROUS and WILL DESTROY YOUR SYSTEM. Under no circumstances should we be encouraging people to do that.
Signature · 6 lines
"Next the statesmen will invent cheap lies, putting the blame upon the nation that is attacked, and every man will be glad of those conscience-soothing falsities, and will diligently study them, and refuse to examine any refutations of them; and thus he will by and by convince himself that the war is just, and will thank God for the better sleep he enjoys after this process of grotesque self-deception." -- Mark Twain
Am Freitag, 24. September 2004 15:09 schrieb Matthew Wilcox:
Quoted 10 lines · Jan Dittmer
Quoted 6 lines
My point was, I load dummyphp with showunused=0 and only get dirs for the slots with devices in them. Now I decide to put a network card (or whatever I have to spare) in an empty slot, hope that the system doesn't reboot immediately, and voila I don't have any
/sys/bus/pci/slotsdir to enable the slot and have to reboot nevertheless. Or does the pci system a rescan if I reinsert the module?That is DANGEROUS and WILL DESTROY YOUR SYSTEM. Under no circumstances should we be encouraging people to do that.
Yes, and that's why there a big comments as well in the Kconfig help as well as in the source of both dummyphp and fakephp.
Eike
Quoted 3 lines · Rolf Eike Beer
-changed param "usedonly" to "showunused" so it behaves like fakephp at the
first look: if you load dummyphp without parameters there are only slots with devices in it.
Well, know I get only entries for all devices I don't have!
drivers/pci/hotplug/dummyphp.c 2004-09-23 23:11:23.000000000 +0200 line 145
Quoted 6 lines
+
dslot->dev=pci_get_slot(dslot->bus, dslot->devfn);drivers/pci/hotplug/dummyphp.c 2004-09-23 23:11:23.000000000 +0200 renamed from drivers/pci/hotplug/dummyphp.c 1970-01-01 01:00:00.000000000 +0100 +5
-0+ + if (showunused || dslot->dev) { + retval = 0; + goto error_dslot; + }
This should probably be !showunused || !dslot->dev ?
Jan
Am Freitag, 24. September 2004 14:40 schrieben Sie:
Quoted 6 lines
Quoted 3 lines · Rolf Eike Beer
-changed param "usedonly" to "showunused" so it behaves like fakephp at the first look: if you load dummyphp without parameters there are only slots with devices in it.
Well, know I get only entries for all devices I don't have!
There was a device mask but I decided this was too ugly and ripped it out. Maybe it would make sense to have a parameter with an array of buses you want to see completely or something like this.
Quoted 8 lines
drivers/pci/hotplug/dummyphp.c 2004-09-23 23:11:23.000000000 +0200 line 145
Quoted 6 lines
+
dslot->dev=pci_get_slot(dslot->bus, dslot->devfn);drivers/pci/hotplug/dummyphp.c 2004-09-23 23:11:23.000000000 +0200 renamed from drivers/pci/hotplug/dummyphp.c 1970-01-01 01:00:00.000000000 +0100 +5
-0+ + if (showunused || dslot->dev) { + retval = 0; + goto error_dslot; + }This should probably be !showunused || !dslot->dev ?
Yes. Error in boolean simplification.
Eike
Quoted 17 lines · Jan Dittmer
Quoted 16 lines · Greg KH
Quoted 12 lines · Jan Dittmer
Quoted 6 lines · Dave Aubin
Hi,
I know very little about hotplug, but does make sense.
How do you motivate a hotplug insertion event? Or should I just go read the /docs on hotplugging? Any help is Appreciated:)There is a "fake" hotplug driver which works for normal pci. But last time I looked at it, it did only support hot disabling, not hot enabling
- but this surely can be fixed.
Quoted 8 lines
Quoted 3 lines
Yes, hot "enabling" has been left for someone to add to the driver, if you read the comments in it :)
I read them and started playing around with this driver. So echoing 0 in
/sys/bus/pci/slots/*/powerdisables the pci device. The problem I see
is, that the tree with the device is disappearing. So how am I supposed to re-enable the device.
You need to add another sysfs file called "rescan" or something. Writing to that file will cause the kernel to rescan pci space, and add any devices it finds that are not already present. The code to do that can be taken from the pci startup code in the kernel today.
Quoted 2 lines
I've no real hotplug hardware to play with, so I'm bound to reading the source code in
drivers/pci/hotplugand testing with fakephp.
That's fine. You don't need real hotplug pci hardware to use fakephp, that's what the driver is for :)
Quoted 3 lines
I found your utility pcihpview (v0.5) which searches for
/sys/bus/pci/hotplug_slots. But grepping the kernel tree doesn't show any mentioning of it - so I suppose it is outdated.
That's a 2.4 interface. I need to get a new version of that program out there that works for 2.6 one of these days (the bk version of the program has this support already in it, if you want to mess with that...)
Quoted 2 lines
Is there anywhere a current article (or
Documentation/pci_hotplug.txt) about the state of PCI hotplug and how this is supposed to work?
Not really, sorry.
Quoted 3 lines
ps: Meanwhile I found dummyphp on the pcihpd mailinglist. This doesn't remove the device from
/sys/bus/pci/slots/*/power. Still I'd like to know the offical way.
That's the driver that I based fakephp on. It's a good starting point for what it sounds like you want to do.
Hope this helps,
greg k-h