diff options
Diffstat (limited to 'drivers/pci/probe.c')
| -rw-r--r-- | drivers/pci/probe.c | 56 |
1 files changed, 52 insertions, 4 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 1c70dd5a19e6..6f69ce367279 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -2,6 +2,7 @@ * probe.c - PCI detection and setup code */ +#include <linux/delay.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/slab.h> @@ -336,6 +337,22 @@ struct pci_bus * __devinit pci_add_new_bus(struct pci_bus *parent, struct pci_de return child; } +static void pci_enable_crs(struct pci_dev *dev) +{ + u16 cap, rpctl; + int rpcap = pci_find_capability(dev, PCI_CAP_ID_EXP); + if (!rpcap) + return; + + pci_read_config_word(dev, rpcap + PCI_CAP_FLAGS, &cap); + if (((cap & PCI_EXP_FLAGS_TYPE) >> 4) != PCI_EXP_TYPE_ROOT_PORT) + return; + + pci_read_config_word(dev, rpcap + PCI_EXP_RTCTL, &rpctl); + rpctl |= PCI_EXP_RTCTL_CRSSVE; + pci_write_config_word(dev, rpcap + PCI_EXP_RTCTL, rpctl); +} + unsigned int __devinit pci_scan_child_bus(struct pci_bus *bus); /* @@ -366,6 +383,8 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max pci_write_config_word(dev, PCI_BRIDGE_CONTROL, bctl & ~PCI_BRIDGE_CTL_MASTER_ABORT); + pci_enable_crs(dev); + if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus) { unsigned int cmax, busnr; /* @@ -375,6 +394,17 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev * dev, int max if (pass) return max; busnr = (buses >> 8) & 0xFF; + + /* + * If we already got to this bus through a different bridge, + * ignore it. This can happen with the i450NX chipset. + */ + if (pci_find_bus(pci_domain_nr(bus), busnr)) { + printk(KERN_INFO "PCI: Bus %04x:%02x already known\n", + pci_domain_nr(bus), busnr); + return max; + } + child = pci_alloc_child_bus(bus, dev, busnr); if (!child) return max; @@ -490,6 +520,7 @@ static int pci_setup_device(struct pci_dev * dev) /* Early fixups, before probing the BARs */ pci_fixup_device(pci_fixup_early, dev); + class = dev->class >> 8; switch (dev->hdr_type) { /* header type */ case PCI_HEADER_TYPE_NORMAL: /* standard header */ @@ -602,9 +633,7 @@ pci_scan_device(struct pci_bus *bus, int devfn) struct pci_dev *dev; u32 l; u8 hdr_type; - - if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) - return NULL; + int delay = 1; if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) return NULL; @@ -614,6 +643,25 @@ pci_scan_device(struct pci_bus *bus, int devfn) l == 0x0000ffff || l == 0xffff0000) return NULL; + /* Configuration request Retry Status */ + while (l == 0xffff0001) { + msleep(delay); + delay *= 2; + if (pci_bus_read_config_dword(bus, devfn, PCI_VENDOR_ID, &l)) + return NULL; + /* Card hasn't responded in 60 seconds? Must be stuck. */ + if (delay > 60 * 1000) { + printk(KERN_WARNING "Device %04x:%02x:%02x.%d not " + "responding\n", pci_domain_nr(bus), + bus->number, PCI_SLOT(devfn), + PCI_FUNC(devfn)); + return NULL; + } + } + + if (pci_bus_read_config_byte(bus, devfn, PCI_HEADER_TYPE, &hdr_type)) + return NULL; + dev = kmalloc(sizeof(struct pci_dev), GFP_KERNEL); if (!dev) return NULL; @@ -785,7 +833,7 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, if (pci_find_bus(pci_domain_nr(b), bus)) { /* If we already got to this bus through a different bridge, ignore it */ - DBG("PCI: Bus %02x already known\n", bus); + DBG("PCI: Bus %04:%02x already known\n", pci_domain_nr(b), bus); goto err_out; } list_add_tail(&b->node, &pci_root_buses); |
