lkml.org 
[lkml]   [2000]   [Mar]   [13]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
SubjectSlot 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/

\
 
 \ /
  Last update: 2005-03-22 13:57    [from the cache]
©2003-2011 Jasper Spaans