Slot based PCI device probing

From: Petr Vandrovec (vandrove@vc.cvut.cz)
Date: Mon Mar 13 2000 - 13:33:24 EST


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/



This archive was generated by hypermail 2b29 : Wed Mar 15 2000 - 21:00:26 EST