[Fwd] Initialization order of PCI devices

From: Petr Vandrovec (vandrove@vc.cvut.cz)
Date: Tue May 23 2000 - 09:53:50 EST


Oops. I forgot to cc it to linux-kernel :-( Sorry.
                                                Petr Vandrovec
                                                vandrove@vc.cvut.cz

----- Forwarded message from Petr Vandrovec <vandrove@vc.cvut.cz> -----

Date: Tue, 23 May 2000 16:41:38 +0200
From: Petr Vandrovec <vandrove@vc.cvut.cz>
To: kraxel@goldbach.in-berlin.de
Cc: mj@suse.cz, jgarzik@mandrakesoft.com, alan@redhat.com, vandrove@vc.cvut.cz
Subject: Initialization order of PCI devices
User-Agent: Mutt/1.2i

Hi Gerd, Hi Martin, Hi others,
  I revived and slightly modified patch to PCI subsystem which
(1) postpones initialization of PCI devices which use pci_register_driver
    after all `software' drivers (such as procfs) are initialized
(2) allows you to set order in which devices are scanned. This allows you
    to chose which device is eth0, what is fb0, what is scsi0 and so on...
Since last version two months ago I now changed code so that pci devices
list is really reordered. This has nice effect that it partially works
also for modules and for old-PCI API drivers too.

This patch is not compatible with:
drivers/atm/eni.c - driver unregisters if pci_register_driver returns 0.
     Fixed...
drivers/char/epca.c - driver unregisters if pci_register_driver returns 0.
     Upper-layer does not handle hotplug :-(
drivers/net/sis900.c - driver unregisters if pci_register_driver returns 0.
     Driver does not correctly handle if pci_register_driver fails.
     Fixed...
drivers/net/yellowfin.c - driver unregisters if pci_register_driver returns 0.
     Driver does not correctly handle if pci_register_driver fails
     (unregisters not-registered driver).
     Fixed...
drivers/sound/es1370.c - driver unregisters if pci_register_driver returns 0.
     Driver does not correctly handle if pci_register_driver fails (returns OK).
     Fixed...
drivers/sound/es1371.c - same as above
     Fixed...
drivers/sound/esssolo1.c - same as above
     Fixed...
drivers/sound/i810_audio.c - same as above
     Fixed...
drivers/sound/sonicvibes.c - same as above
     Fixed...
drivers/sound/trident.c - same as above
     Fixed...
drivers/sound/via82cxxx_audio.c - driver unregisters if
     pci_register_driver returns 0.
     Fixed...
arch/i386/kernel/acpi.c - cannot work as is, because of it expects that
     ACPI hardware is not hotplug... It can be fixed by reverting this
     driver to older pci_find_xxx function group.
If there is interest in this patch, I'll try to fix acpi and epca drivers too,
but as I do not have epca hardware... I send this patch to driver's maintainers
too.
I think that drivers part of this patch should be applied anyway - it makes
source code shorter, if nothing else...
                                                Petr Vandrovec
                                                vandrove@vc.cvut.cz

/* -------- PCI subsystem change -------- */

diff -urdN linux/drivers/pci/pci.c linux/drivers/pci/pci.c
--- linux/drivers/pci/pci.c Sat Apr 29 06:05:24 2000
+++ linux/drivers/pci/pci.c Tue May 23 13:33:37 2000
@@ -57,6 +57,11 @@
 }
 
 
+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_subsys(unsigned int vendor, unsigned int device,
                 unsigned int ss_vendor, unsigned int ss_device,
@@ -318,6 +323,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);
@@ -340,6 +347,52 @@
         }
 }
 
+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 __init
+pci_unfroze(void)
+{
+ struct pci_dev *dev;
+
+ if (!pci_frozen)
+ return;
+ pci_frozen = 0;
+ pci_for_each_dev(dev) {
+ pci_find_driver_for_device(dev);
+ }
+}
+
+static void __init
+pciorder_sort(void)
+{
+ struct pci_dev *dev;
+ u32 *pciorder;
+ LIST_HEAD(sorted_devices);
+
+ DBG(KERN_DEBUG "PCI: Sorting device list...\n");
+ for (pciorder = pciorder_array; pciorder < pciorder_used; pciorder++) {
+ dev = pci_find_slot(*pciorder >> 16, *pciorder & 0xFFFF);
+ if (dev) {
+ list_del(&dev->global_list);
+ list_add_tail(&dev->global_list, &sorted_devices);
+ } else {
+ DBG(KERN_DEBUG "PCI device at %X:%02X.%X was not found\n",
+ *pciorder >> 16, (*pciorder >> 3) & 0x1FFF, *pciorder & 7);
+ }
+ }
+ list_splice(&sorted_devices, &pci_devices);
+}
+
 #ifdef CONFIG_HOTPLUG
 
 void
@@ -352,6 +405,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))
@@ -1127,6 +1182,8 @@
 
         pcibios_init();
 
+ pciorder_sort();
+
         pci_for_each_dev(dev) {
                 pci_fixup_device(PCI_FIXUP_FINAL, dev);
         }
@@ -1151,8 +1208,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_INFO "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;
+ DBG(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/include/linux/pci.h linux/include/linux/pci.h
--- linux/include/linux/pci.h Thu May 11 18:27:24 2000
+++ linux/include/linux/pci.h Tue May 23 14:27:48 2000
@@ -605,11 +605,13 @@
         if (rc > 0)
                 return 0;
 
- /* iff CONFIG_HOTPLUG and built into kernel, we should
- * leave the driver around for future hotplug events.
+ /* if driver is built into kernel, we should leave the
+ * driver around for future hotplug events and because
+ * of devices are registered with drivers after all
+ * in-kernel drivers are registered.
          * For the module case, a hotplug daemon of some sort
          * should load a module in response to an insert event. */
-#if defined(CONFIG_HOTPLUG) && !defined(MODULE)
+#if !defined(MODULE)
         if (rc == 0)
                 return 0;
 #endif
diff -urdN linux/init/main.c linux/init/main.c
--- linux/init/main.c Tue May 23 09:59:00 2000
+++ linux/init/main.c Tue May 23 10:35:19 2000
@@ -102,7 +102,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
@@ -718,6 +720,10 @@
 #endif
 
         do_initcalls();
+
+#ifdef CONFIG_PCI
+ pci_unfroze();
+#endif
 
         /* .. filesystems .. */
         filesystem_setup();

/* ---------- Driver Fixes ---------- */

diff -urdN linux/drivers/atm/eni.c linux/drivers/atm/eni.c
--- linux/drivers/atm/eni.c Tue May 23 09:58:54 2000
+++ linux/drivers/atm/eni.c Tue May 23 14:14:02 2000
@@ -2311,9 +2311,7 @@
                     sizeof(skb->cb),sizeof(struct eni_skb_prv));
                 return -EIO;
         }
- if (pci_register_driver(&eni_driver) > 0) return 0;
- pci_unregister_driver (&eni_driver);
- return -ENODEV;
+ return pci_module_init(&eni_driver);
 }
 
 
@@ -2323,6 +2321,7 @@
          * Well, there's no way to get rid of the driver yet, so we don't
          * have to clean up, right ? :-)
          */
+ /* pci_unregister_driver(&eni_driver); */
 }
 
 
diff -urdN linux/drivers/net/sis900.c linux/drivers/net/sis900.c
--- linux/drivers/net/sis900.c Tue May 23 09:58:55 2000
+++ linux/drivers/net/sis900.c Tue May 23 14:16:30 2000
@@ -1279,11 +1279,7 @@
 
         printk(KERN_INFO "%s", version);
 
- if (!pci_register_driver(&sis900_pci_driver)) {
- pci_unregister_driver(&sis900_pci_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&sis900_pci_driver);
 }
 
 static void __exit sis900_cleanup_module(void)
diff -urdN linux/drivers/net/yellowfin.c linux/drivers/net/yellowfin.c
--- linux/drivers/net/yellowfin.c Tue May 23 09:58:55 2000
+++ linux/drivers/net/yellowfin.c Tue May 23 14:17:01 2000
@@ -1398,11 +1398,7 @@
         if (debug) /* Emit version even if no cards detected. */
                 printk(KERN_INFO "%s", version);
 
- if (pci_register_driver (&yellowfin_driver) > 0)
- return 0;
-
- pci_unregister_driver (&yellowfin_driver);
- return -ENODEV;
+ return pci_module_init (&yellowfin_driver);
 }
 
 
diff -urdN linux/drivers/sound/es1370.c linux/drivers/sound/es1370.c
--- linux/drivers/sound/es1370.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/es1370.c Tue May 23 14:17:29 2000
@@ -2616,12 +2616,7 @@
         if (!pci_present()) /* No PCI bus in this machine! */
                 return -ENODEV;
         printk(KERN_INFO "es1370: version v0.33 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&es1370_driver)) {
- pci_unregister_driver(&es1370_driver);
- return -ENODEV;
- }
- return 0;
-
+ return pci_module_init(&es1370_driver);
 }
 
 static void __exit cleanup_es1370(void)
diff -urdN linux/drivers/sound/es1371.c linux/drivers/sound/es1371.c
--- linux/drivers/sound/es1371.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/es1371.c Tue May 23 14:17:55 2000
@@ -2821,11 +2821,7 @@
         if (!pci_present()) /* No PCI bus in this machine! */
                 return -ENODEV;
         printk(KERN_INFO "es1371: version v0.25 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&es1371_driver)) {
- pci_unregister_driver(&es1371_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&es1371_driver);
 }
 
 static void __exit cleanup_es1371(void)
diff -urdN linux/drivers/sound/esssolo1.c linux/drivers/sound/esssolo1.c
--- linux/drivers/sound/esssolo1.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/esssolo1.c Tue May 23 14:18:18 2000
@@ -2353,11 +2353,7 @@
         if (!pci_present()) /* No PCI bus in this machine! */
                 return -ENODEV;
         printk(KERN_INFO "solo1: version v0.14 time " __TIME__ " " __DATE__ "\n");
- if (!pci_register_driver(&solo1_driver)) {
- pci_unregister_driver(&solo1_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&solo1_driver);
 }
 
 /* --------------------------------------------------------------------- */
diff -urdN linux/drivers/sound/i810_audio.c linux/drivers/sound/i810_audio.c
--- linux/drivers/sound/i810_audio.c Wed May 10 23:57:18 2000
+++ linux/drivers/sound/i810_audio.c Tue May 23 14:18:39 2000
@@ -1848,11 +1848,7 @@
         printk(KERN_INFO "Intel 810 + AC97 Audio, version "
                DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
- if (!pci_register_driver(&i810_pci_driver)) {
- pci_unregister_driver(&i810_pci_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&i810_pci_driver);
 }
 
 static void __exit i810_cleanup_module (void)
diff -urdN linux/drivers/sound/sonicvibes.c linux/drivers/sound/sonicvibes.c
--- linux/drivers/sound/sonicvibes.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/sonicvibes.c Tue May 23 14:19:01 2000
@@ -2655,11 +2655,7 @@
         if (!(wavetable_mem = __get_free_pages(GFP_KERNEL, 20-PAGE_SHIFT)))
                 printk(KERN_INFO "sv: cannot allocate 1MB of contiguous nonpageable memory for wavetable data\n");
 #endif
- if (!pci_register_driver(&sv_driver)) {
- pci_unregister_driver(&sv_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&sv_driver);
 }
 
 static void __exit cleanup_sonicvibes(void)
diff -urdN linux/drivers/sound/trident.c linux/drivers/sound/trident.c
--- linux/drivers/sound/trident.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/trident.c Tue May 23 14:19:21 2000
@@ -2524,11 +2524,7 @@
         printk(KERN_INFO "Trident 4DWave/SiS 7018/ALi 5451 PCI Audio, version "
                DRIVER_VERSION ", " __TIME__ " " __DATE__ "\n");
 
- if (!pci_register_driver(&trident_pci_driver)) {
- pci_unregister_driver(&trident_pci_driver);
- return -ENODEV;
- }
- return 0;
+ return pci_module_init(&trident_pci_driver);
 }
 
 static void __exit trident_cleanup_module (void)
diff -urdN linux/drivers/sound/via82cxxx_audio.c linux/drivers/sound/via82cxxx_audio.c
--- linux/drivers/sound/via82cxxx_audio.c Tue May 23 09:58:56 2000
+++ linux/drivers/sound/via82cxxx_audio.c Tue May 23 14:20:23 2000
@@ -2370,10 +2370,8 @@
                 return rc;
         }
 
- rc = pci_register_driver (&via_driver);
- if (rc < 1) {
- if (rc == 0)
- pci_unregister_driver (&via_driver);
+ rc = pci_module_init (&via_driver);
+ if (rc < 0) {
                 via_cleanup_proc ();
                 MOD_DEC_USE_COUNT;
                 DPRINTK ("EXIT, returning -ENODEV\n");

----- End forwarded message -----

-
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 : Tue May 23 2000 - 21:00:23 EST