diff options
Diffstat (limited to 'arch/i386/kernel/pci-pc.c')
-rw-r--r-- | arch/i386/kernel/pci-pc.c | 98 |
1 files changed, 56 insertions, 42 deletions
diff --git a/arch/i386/kernel/pci-pc.c b/arch/i386/kernel/pci-pc.c index 9ee1d6355..6b7d65589 100644 --- a/arch/i386/kernel/pci-pc.c +++ b/arch/i386/kernel/pci-pc.c @@ -1,7 +1,7 @@ /* * Low-Level PCI Support for PC * - * (c) 1999 Martin Mares <mj@suse.cz> + * (c) 1999--2000 Martin Mares <mj@suse.cz> */ #include <linux/config.h> @@ -22,6 +22,8 @@ unsigned int pci_probe = PCI_PROBE_BIOS | PCI_PROBE_CONF1 | PCI_PROBE_CONF2; +static struct pci_bus *pci_root_bus; + /* * IRQ routing table provided by the BIOS */ @@ -624,26 +626,30 @@ static struct pci_ops * __init pci_find_bios(void) static void __init pcibios_sort(void) { - struct pci_dev *dev = pci_devices; - struct pci_dev **last = &pci_devices; - struct pci_dev *d, **dd, *e; - int idx; + LIST_HEAD(sorted_devices); + struct list_head *ln; + struct pci_dev *dev, *d; + int idx, found; unsigned char bus, devfn; DBG("PCI: Sorting device list...\n"); - while ((e = dev)) { - idx = 0; - while (pci_bios_find_device(e->vendor, e->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { + while (!list_empty(&pci_devices)) { + ln = pci_devices.next; + dev = pci_dev_g(ln); + idx = found = 0; + while (pci_bios_find_device(dev->vendor, dev->device, idx, &bus, &devfn) == PCIBIOS_SUCCESSFUL) { idx++; - for(dd=&dev; (d = *dd); dd = &d->next) { + for (ln=pci_devices.next; ln != &pci_devices; ln=ln->next) { + d = pci_dev_g(ln); if (d->bus->number == bus && d->devfn == devfn) { - *dd = d->next; - *last = d; - last = &d->next; + list_del(&d->global_list); + list_add_tail(&d->global_list, &sorted_devices); + if (d == dev) + found = 1; break; } } - if (!d) { + if (ln == &pci_devices) { printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); /* * We must not continue scanning as several buggy BIOSes @@ -652,16 +658,14 @@ static void __init pcibios_sort(void) break; } } - if (e == dev) { + if (!found) { printk("PCI: Device %02x:%02x not found by BIOS\n", dev->bus->number, dev->devfn); - d = dev; - dev = dev->next; - *last = d; - last = &d->next; + list_del(&dev->global_list); + list_add_tail(&dev->global_list, &sorted_devices); } } - *last = NULL; + list_splice(&sorted_devices, &pci_devices); } /* @@ -736,16 +740,19 @@ static struct irq_routing_table * __init pcibios_get_irq_routing_table(void) static void __init pcibios_fixup_ghosts(struct pci_bus *b) { - struct pci_dev *d, *e, **z; + struct list_head *ln, *mn; + struct pci_dev *d, *e; int mirror = PCI_DEVFN(16,0); int seen_host_bridge = 0; int i; DBG("PCI: Scanning for ghost devices on bus %d\n", b->number); - for(d=b->devices; d && d->devfn < mirror; d=d->sibling) { + for (ln=b->devices.next; ln != &b->devices; ln=ln->next) { + d = pci_dev_b(ln); if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) seen_host_bridge++; - for(e=d->next; e; e=e->sibling) { + for (mn=ln->next; mn != &b->devices; mn=mn->next) { + e = pci_dev_b(mn); if (e->devfn != d->devfn + mirror || e->vendor != d->vendor || e->device != d->device || @@ -758,20 +765,23 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b) continue; break; } - if (!e) + if (mn == &b->devices) return; } if (!seen_host_bridge) return; printk("PCI: Ignoring ghost devices on bus %02x\n", b->number); - for(e=b->devices; e->sibling != d; e=e->sibling); - e->sibling = NULL; - for(z=&pci_devices; (d=*z);) - if (d->bus == b && d->devfn >= mirror) { - *z = d->next; - kfree_s(d, sizeof(*d)); + + ln = &b->devices; + while (ln->next != &b->devices) { + d = pci_dev_b(ln->next); + if (d->devfn >= mirror) { + list_del(&d->global_list); + list_del(&d->bus_list); + kfree(d); } else - z = &d->next; + ln = ln->next; + } } /* @@ -783,10 +793,10 @@ static void __init pcibios_fixup_ghosts(struct pci_bus *b) */ static void __init pcibios_fixup_peer_bridges(void) { - struct pci_bus *b = pci_root; + struct list_head *ln; + struct pci_bus *b = pci_root_bus; int n, cnt=-1; - struct pci_dev *d; - struct pci_ops *ops = pci_root->ops; + struct pci_ops *ops = pci_root_bus->ops; #ifdef CONFIG_PCI_DIRECT /* @@ -798,8 +808,10 @@ static void __init pcibios_fixup_peer_bridges(void) return; #endif - for(d=b->devices; d; d=d->sibling) - if ((d->class >> 8) == PCI_CLASS_BRIDGE_HOST) + DBG("PCI: Peer bridge fixup\n"); + + for(ln=b->devices.next; ln != &b->devices; ln=ln->next) + if ((pci_dev_b(ln)->class >> 8) == PCI_CLASS_BRIDGE_HOST) cnt++; n = b->subordinate + 1; while (n <= 0xff) { @@ -864,9 +876,9 @@ static void __init pci_fixup_i450nx(struct pci_dev *d) pci_read_config_byte(d, reg++, &subb); DBG("i450NX PXB %d: %02x/%02x/%02x\n", pxb, busno, suba, subb); if (busno) - pci_scan_bus(busno, pci_root->ops, NULL); /* Bus A */ + pci_scan_bus(busno, pci_root_bus->ops, NULL); /* Bus A */ if (suba < subb) - pci_scan_bus(suba+1, pci_root->ops, NULL); /* Bus B */ + pci_scan_bus(suba+1, pci_root_bus->ops, NULL); /* Bus B */ } } @@ -879,7 +891,7 @@ static void __init pci_fixup_rcc(struct pci_dev *d) u8 busno; pci_read_config_byte(d, 0x44, &busno); printk("PCI: RCC host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root->ops, NULL); + pci_scan_bus(busno, pci_root_bus->ops, NULL); } static void __init pci_fixup_compaq(struct pci_dev *d) @@ -891,7 +903,7 @@ static void __init pci_fixup_compaq(struct pci_dev *d) u8 busno; pci_read_config_byte(d, 0xc8, &busno); printk("PCI: Compaq host bridge: secondary bus %02x\n", busno); - pci_scan_bus(busno, pci_root->ops, NULL); + pci_scan_bus(busno, pci_root_bus->ops, NULL); } static void __init pci_fixup_umc_ide(struct pci_dev *d) @@ -1000,7 +1012,7 @@ static void __init pcibios_irq_peer_trick(struct irq_routing_table *rt) * It might be a secondary bus, but in this case its parent is already * known (ascending bus order) and therefore pci_scan_bus returns immediately. */ - if (busmap[i] && pci_scan_bus(i, pci_root->ops, NULL)) + if (busmap[i] && pci_scan_bus(i, pci_root_bus->ops, NULL)) printk("PCI: Discovered primary peer bus %02x [IRQ]\n", i); } @@ -1077,6 +1089,7 @@ static char *pcibios_lookup_irq(struct pci_dev *dev, struct irq_routing_table *r } DBG(" -> [PIIX] sink\n"); return NULL; + case ID(PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1533): default: DBG(" -> unknown router %04x/%04x\n", rt->rtr_vendor, rt->rtr_device); if (newirq && mask == (1 << newirq)) { @@ -1095,6 +1108,7 @@ static void __init pcibios_fixup_irqs(void) struct pci_dev *dev; u8 pin; + DBG("PCI: IRQ fixup\n"); rtable = pirq_table = pcibios_find_irq_routing_table(); #ifdef CONFIG_PCI_BIOS if (!rtable && pci_bios_present) @@ -1104,7 +1118,7 @@ static void __init pcibios_fixup_irqs(void) if (rtable) pcibios_irq_peer_trick(rtable); - for(dev=pci_devices; dev; dev=dev->next) { + pci_for_each_dev(dev) { pci_read_config_byte(dev, PCI_INTERRUPT_PIN, &pin); #if defined(CONFIG_X86_IO_APIC) /* @@ -1197,7 +1211,7 @@ void __init pcibios_init(void) } printk("PCI: Probing PCI hardware\n"); - pci_scan_bus(0, ops, NULL); + pci_root_bus = pci_scan_bus(0, ops, NULL); pcibios_fixup_irqs(); if (pci_probe & PCI_PEER_FIXUP) |