Skip to contentSkip to conversation

Is there a user space pci rescan method?

PATCH Applied Dave Aubin 6 participants 31 messages Sep 22, 2004 – Nov 12, 2004 PCI

lore
Share & tools
lore

Dave Aubin

author
#0 lore raw

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.

#1 lore raw
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

#2 lore raw
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

#3 lore raw
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.

#4 lore raw
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/*/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?

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

#5 lore raw
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

#6 lore raw
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

#7 lore raw

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
diff -x '*.o' -x '.tmp*' -Naur linux-2.6.8/drivers/pci/hotplug/Kconfig linux-2.6.9-rc2-bk/drivers/pci/hotplug/Kconfig
@@ -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
diff -x '*.o' -x '.tmp*' -Naur linux-2.6.8/drivers/pci/hotplug/Makefile linux-2.6.9-rc2-bk/drivers/pci/hotplug/Makefile
@@ -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

#8 lore raw
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

#9 lore raw

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 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 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

#10 lore raw
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

#11 lore raw

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/slots dir 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

#12 lore raw
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/slots dir 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

#13 lore raw
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

#14 lore raw
In reply to Greg KH
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
diff -ur linus/drivers/pci/bus.c pcirescan/drivers/pci/bus.c
@@ -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");

#15 lore raw
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 the pci_bus_add_device functionality from pci_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
diff -ur linus/drivers/pci/hotplug/fakephp.c pcirescan/drivers/pci/hotplug/fakephp.c
@@ -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;
 }
 
#16 lore raw
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 the pci_bus_add_device functionality from pci_bus_add_devices.

Quoted 4 lines

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).

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
diff -X /home/jdittmer/stuff/diffignore -ur linus/drivers/pci/hotplug/fakephp.c pcirescan/drivers/pci/hotplug/fakephp.c
@@ -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
diff -ur linus/drivers/pci/bus.c pcirescan/drivers/pci/bus.c
@@ -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);
#17 lore raw
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 the pci_bus_add_device functionality from pci_bus_add_devices.

Quoted 8 lines
Quoted 4 lines

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).

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

#18 lore raw

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);
#19 lore raw

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_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 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

#20 lore raw

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_devices to pci_bus_add_device to add a single device to sysfs, procfs and the global device list.

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);
#21 lore raw

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_devices to pci_bus_add_device to add a single device to sysfs, procfs and the global device list.

Quoted 5 lines
Quoted 3 lines
Quoted 1 line

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

#22 lore raw

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_devices to pci_bus_add_device to add a single device to sysfs, procfs and the global device list.

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);
Applied
#23 lore raw

Re: [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_devices to pci_bus_add_device to add a single device to sysfs, procfs and the global device list.

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

#24 lore raw

PATCH 2/2 fakephp: add pci bus rescan ability

In reply to Greg KH

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/*/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");
 
Applied
#25 lore raw

Re: [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/*/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.

Very nice, thanks for doing this work.

Applied, thanks.

greg k-h

#26 lore raw
In reply to Jan Dittmer
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/slots dir 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
#27 lore raw

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/slots dir 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

#28 lore raw
In reply to Rolf Eike Beer
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

#29 lore raw

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

#30 lore raw
In reply to Jan Dittmer
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/*/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.

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/hotplug and 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