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    [W:0.035 / U:0.040 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site