Messages in this thread Patch in this message | | | Date | Mon, 13 Mar 2000 19:33:24 +0100 | From | Petr Vandrovec <> | Subject | Slot based PCI device probing |
| |
Hi Jeff, few weeks ago you asked on linux-kernel for slot-based pci probing. So I wrote following patch. To get it to work you should (1) enable CONFIG_HOTPLUG. Or at least modify drivers to not bail out if pci_register_driver() returns 0. There is no problem with driver init's marked __init, as pci_unfroze is invoked before __init is droped. And if CONFIG_HOTPLUG is not defined, no-one will call your ->probe after init release. (2) Modify all drivers from pci_find_* to pci_register_*. It is not possible to get slot-based pci probing without that. (3) Pray that all subsystem handle this correctly. If they support modularisation, it should work fine. There is optional parameter, pciorder=BUS:SLOT.FUNCTION[,BUS:SLOT.FUNCTION...] which can be used to specify probing order - listed slots are probed first, after this list all slots without driver all probed again. I tested it only with IDE and matroxfb in-kernel. IDE in 2.3.52-pre1 uses pci_find*, so it is always initialized before matroxfb :-( Matroxfb worked after I reverted 2.3.51 fbcon/fbmem changes. So if you are using multihead, look at this: pciorder=1:00.0,0:08.0 initializes first AGP, then PCI... Of course, this patch does not affect modules - if you want specific ordering, compile driver into kernel and use 'pciorder='. I think that for modules we should stick with current state. Best regards, Petr Vandrovec vandrove@vc.cvut.cz
diff -urdN linux/drivers/pci/pci.c linux/drivers/pci/pci.c --- linux/drivers/pci/pci.c Mon Feb 28 15:16:54 2000 +++ linux/drivers/pci/pci.c Mon Mar 13 18:17:42 2000 @@ -33,6 +33,11 @@ LIST_HEAD(pci_root_buses); LIST_HEAD(pci_devices); +static int pci_frozen = 1; +#define PCIORDER_MAX_SLOTS 16 +static u32 pciorder_array[PCIORDER_MAX_SLOTS]; +static u32 *pciorder_used = pciorder_array; + struct pci_dev * pci_find_slot(unsigned int bus, unsigned int devfn) { @@ -254,6 +259,8 @@ int count = 0; list_add_tail(&drv->node, &pci_drivers); + if (pci_frozen) + return 0; pci_for_each_dev(dev) { if (!pci_dev_driver(dev)) count += pci_announce_device(drv, dev); @@ -276,6 +283,38 @@ } } +static void +pci_find_driver_for_device(struct pci_dev *dev) +{ + struct list_head *ln; + + for (ln = pci_drivers.next; ln != &pci_drivers && !pci_dev_driver(dev); ln = ln->next) { + struct pci_driver *drv = list_entry(ln, struct pci_driver, node); + if (pci_announce_device(drv, dev)) + break; + } +} + +void +pci_unfroze(void) +{ + struct pci_dev *dev; + u32 *pciorder; + + if (!pci_frozen) + return; + pci_frozen = 0; + for (pciorder = pciorder_array; pciorder < pciorder_used; pciorder++) { + dev = pci_find_slot(*pciorder >> 16, *pciorder & 0xFFFF); + if (dev) { + pci_find_driver_for_device(dev); + } + } + pci_for_each_dev(dev) { + pci_find_driver_for_device(dev); + } +} + #ifdef CONFIG_HOTPLUG void @@ -288,6 +327,8 @@ #ifdef CONFIG_PROC_FS pci_proc_attach_device(dev); #endif + if (pci_frozen) + return; for(ln=pci_drivers.next; ln != &pci_drivers; ln=ln->next) { struct pci_driver *drv = list_entry(ln, struct pci_driver, node); if (drv->remove && pci_announce_device(drv, dev)) @@ -988,8 +1029,32 @@ return 1; } -__setup("pci=", pci_setup); +static int __init pciorder_setup(char *str) +{ + u32 bus; + u32 node; + + do { + bus = simple_strtoul(str, &str, 16); + if (*str != ':') { + printk(KERN_DEBUG "Missing : in pciorder=\n"); + return 1; + } + node = simple_strtoul(str + 1, &str, 16); + if (*str == '.') { + u32 fn; + + fn = simple_strtoul(str + 1, &str, 16); + node = (node << 3) | fn; + } + *pciorder_used++ = (bus << 16) | node; + printk(KERN_DEBUG "pciorder=%X:%02X.%X\n", bus, node >> 3, node & 7); + } while (*str++ == ',' && pciorder_used < pciorder_array + PCIORDER_MAX_SLOTS); + return 1; +} +__setup("pci=", pci_setup); +__setup("pciorder=", pciorder_setup); EXPORT_SYMBOL(pci_read_config_byte); EXPORT_SYMBOL(pci_read_config_word); diff -urdN linux/init/main.c linux/init/main.c --- linux/init/main.c Fri Mar 10 05:12:27 2000 +++ linux/init/main.c Mon Mar 13 17:16:18 2000 @@ -98,7 +98,9 @@ extern void filesystem_setup(void); extern void ecard_init(void); - +#if defined(CONFIG_PCI) +extern void pci_unfroze(void); +#endif #if defined(CONFIG_SYSVIPC) extern void ipc_init(void); #endif @@ -678,6 +680,10 @@ #endif do_initcalls(); + +#ifdef CONFIG_PCI + pci_unfroze(); +#endif /* .. filesystems .. */ filesystem_setup(); - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/
| |