vserver 1.9.5.x5
[linux-2.6.git] / drivers / pci / probe.c
index e88017d..663ce3a 100644 (file)
@@ -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>
@@ -27,12 +28,73 @@ EXPORT_SYMBOL(pci_root_buses);
 
 LIST_HEAD(pci_devices);
 
+#ifdef HAVE_PCI_LEGACY
+/**
+ * pci_create_legacy_files - create legacy I/O port and memory files
+ * @b: bus to create files under
+ *
+ * Some platforms allow access to legacy I/O port and ISA memory space on
+ * a per-bus basis.  This routine creates the files and ties them into
+ * their associated read, write and mmap files from pci-sysfs.c
+ */
+static void pci_create_legacy_files(struct pci_bus *b)
+{
+       b->legacy_io = kmalloc(sizeof(struct bin_attribute) * 2,
+                              GFP_ATOMIC);
+       if (b->legacy_io) {
+               memset(b->legacy_io, 0, sizeof(struct bin_attribute) * 2);
+               b->legacy_io->attr.name = "legacy_io";
+               b->legacy_io->size = 0xffff;
+               b->legacy_io->attr.mode = S_IRUSR | S_IWUSR;
+               b->legacy_io->attr.owner = THIS_MODULE;
+               b->legacy_io->read = pci_read_legacy_io;
+               b->legacy_io->write = pci_write_legacy_io;
+               class_device_create_bin_file(&b->class_dev, b->legacy_io);
+
+               /* Allocated above after the legacy_io struct */
+               b->legacy_mem = b->legacy_io + 1;
+               b->legacy_mem->attr.name = "legacy_mem";
+               b->legacy_mem->size = 1024*1024;
+               b->legacy_mem->attr.mode = S_IRUSR | S_IWUSR;
+               b->legacy_mem->attr.owner = THIS_MODULE;
+               b->legacy_mem->mmap = pci_mmap_legacy_mem;
+               class_device_create_bin_file(&b->class_dev, b->legacy_mem);
+       }
+}
+
+void pci_remove_legacy_files(struct pci_bus *b)
+{
+       class_device_remove_bin_file(&b->class_dev, b->legacy_io);
+       class_device_remove_bin_file(&b->class_dev, b->legacy_mem);
+       kfree(b->legacy_io); /* both are allocated here */
+}
+#else /* !HAVE_PCI_LEGACY */
+static inline void pci_create_legacy_files(struct pci_bus *bus) { return; }
+void pci_remove_legacy_files(struct pci_bus *bus) { return; }
+#endif /* HAVE_PCI_LEGACY */
+
+/*
+ * PCI Bus Class Devices
+ */
+static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
+{
+       cpumask_t cpumask = pcibus_to_cpumask((to_pci_bus(class_dev))->number);
+       int ret;
+
+       ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
+       if (ret < PAGE_SIZE)
+               buf[ret++] = '\n';
+       return ret;
+}
+CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
+
 /*
  * PCI Bus Class
  */
 static void release_pcibus_dev(struct class_device *class_dev)
 {
        struct pci_bus *pci_bus = to_pci_bus(class_dev);
+
        if (pci_bus->bridge)
                put_device(pci_bus->bridge);
        kfree(pci_bus);
@@ -49,21 +111,6 @@ static int __init pcibus_class_init(void)
 }
 postcore_initcall(pcibus_class_init);
 
-/*
- * PCI Bus Class Devices
- */
-static ssize_t pci_bus_show_cpuaffinity(struct class_device *class_dev, char *buf)
-{
-       cpumask_t cpumask = pcibus_to_cpumask((to_pci_bus(class_dev))->number);
-       int ret;
-
-       ret = cpumask_scnprintf(buf, PAGE_SIZE, cpumask);
-       if (ret < PAGE_SIZE)
-               buf[ret++] = '\n';
-       return ret;
-}
-static CLASS_DEVICE_ATTR(cpuaffinity, S_IRUGO, pci_bus_show_cpuaffinity, NULL);
-
 /*
  * Translate the low bits of the PCI base
  * to the resource type
@@ -144,9 +191,11 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                        pci_write_config_dword(dev, reg+4, ~0);
                        pci_read_config_dword(dev, reg+4, &sz);
                        pci_write_config_dword(dev, reg+4, l);
-                       if (~sz)
-                               res->end = res->start + 0xffffffff +
-                                               (((unsigned long) ~sz) << 32);
+                       sz = pci_size(l, sz, 0xffffffff);
+                       if (sz) {
+                               /* This BAR needs > 4GB?  Wow. */
+                               res->end |= (unsigned long)sz<<32;
+                       }
 #else
                        if (l) {
                                printk(KERN_ERR "PCI: Unable to handle 64-bit address for device %s\n", pci_name(dev));
@@ -170,7 +219,7 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
                if (sz && sz != 0xffffffff) {
                        sz = pci_size(l, sz, PCI_ROM_ADDRESS_MASK);
                        if (sz) {
-                               res->flags = (l & PCI_ROM_ADDRESS_ENABLE) |
+                               res->flags = (l & IORESOURCE_ROM_ENABLE) |
                                  IORESOURCE_MEM | IORESOURCE_PREFETCH |
                                  IORESOURCE_READONLY | IORESOURCE_CACHEABLE;
                                res->start = l & PCI_ROM_ADDRESS_MASK;
@@ -243,15 +292,23 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
                u32 mem_base_hi, mem_limit_hi;
                pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
                pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
+
+               /*
+                * Some bridges set the base > limit by default, and some
+                * (broken) BIOSes do not initialize them.  If we find
+                * this, just assume they are not being used.
+                */
+               if (mem_base_hi <= mem_limit_hi) {
 #if BITS_PER_LONG == 64
-               base |= ((long) mem_base_hi) << 32;
-               limit |= ((long) mem_limit_hi) << 32;
+                       base |= ((long) mem_base_hi) << 32;
+                       limit |= ((long) mem_limit_hi) << 32;
 #else
-               if (mem_base_hi || mem_limit_hi) {
-                       printk(KERN_ERR "PCI: Unable to handle 64-bit address space for %s\n", child->name);
-                       return;
-               }
+                       if (mem_base_hi || mem_limit_hi) {
+                               printk(KERN_ERR "PCI: Unable to handle 64-bit address space for bridge %s\n", pci_name(dev));
+                               return;
+                       }
 #endif
+               }
        }
        if (base <= limit) {
                res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM | IORESOURCE_PREFETCH;
@@ -326,6 +383,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);
 
 /*
@@ -356,6 +429,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;
                /*
@@ -365,6 +440,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;
@@ -478,6 +564,10 @@ static int pci_setup_device(struct pci_dev * dev)
        /* "Unknown power state" */
        dev->current_state = 4;
 
+       /* 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 */
                if (class == PCI_CLASS_BRIDGE_PCI)
@@ -589,9 +679,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;
@@ -601,6 +689,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;
@@ -753,6 +860,7 @@ unsigned int __devinit pci_do_scan_bus(struct pci_bus *bus)
 
 struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus, struct pci_ops *ops, void *sysdata)
 {
+       int error;
        struct pci_bus *b;
        struct device *dev;
 
@@ -771,10 +879,8 @@ 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);
-               kfree(dev);
-               kfree(b);
-               return NULL;
+               DBG("PCI: Bus %04x:%02x already known\n", pci_domain_nr(b), bus);
+               goto err_out;
        }
        list_add_tail(&b->node, &pci_root_buses);
 
@@ -782,15 +888,26 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
        dev->parent = parent;
        dev->release = pci_release_bus_bridge_dev;
        sprintf(dev->bus_id, "pci%04x:%02x", pci_domain_nr(b), bus);
-       device_register(dev);
+       error = device_register(dev);
+       if (error)
+               goto dev_reg_err;
        b->bridge = get_device(dev);
 
        b->class_dev.class = &pcibus_class;
        sprintf(b->class_dev.class_id, "%04x:%02x", pci_domain_nr(b), bus);
-       class_device_register(&b->class_dev);
-       class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
+       error = class_device_register(&b->class_dev);
+       if (error)
+               goto class_dev_reg_err;
+       error = class_device_create_file(&b->class_dev, &class_device_attr_cpuaffinity);
+       if (error)
+               goto class_dev_create_file_err;
+
+       /* Create legacy_io and legacy_mem files for this bus */
+       pci_create_legacy_files(b);
 
-       sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
+       error = sysfs_create_link(&b->class_dev.kobj, &b->bridge->kobj, "bridge");
+       if (error)
+               goto sys_create_link_err;
 
        b->number = b->secondary = bus;
        b->resource[0] = &ioport_resource;
@@ -801,6 +918,19 @@ struct pci_bus * __devinit pci_scan_bus_parented(struct device *parent, int bus,
        pci_bus_add_devices(b);
 
        return b;
+
+sys_create_link_err:
+       class_device_remove_file(&b->class_dev, &class_device_attr_cpuaffinity);
+class_dev_create_file_err:
+       class_device_unregister(&b->class_dev);
+class_dev_reg_err:
+       device_unregister(dev);
+dev_reg_err:
+       list_del(&b->node);
+err_out:
+       kfree(dev);
+       kfree(b);
+       return NULL;
 }
 EXPORT_SYMBOL(pci_scan_bus_parented);