PCI: clearing wakeup flags not needed
[safe/jmp/linux-2.6] / drivers / pci / probe.c
index dd64310..c82548a 100644 (file)
@@ -89,6 +89,7 @@ static void release_pcibus_dev(struct device *dev)
 
        if (pci_bus->bridge)
                put_device(pci_bus->bridge);
+       pci_bus_remove_resources(pci_bus);
        kfree(pci_bus);
 }
 
@@ -281,26 +282,12 @@ static void pci_read_bases(struct pci_dev *dev, unsigned int howmany, int rom)
        }
 }
 
-void __devinit pci_read_bridge_bases(struct pci_bus *child)
+static void __devinit pci_read_bridge_io(struct pci_bus *child)
 {
        struct pci_dev *dev = child->self;
        u8 io_base_lo, io_limit_lo;
-       u16 mem_base_lo, mem_limit_lo;
        unsigned long base, limit;
        struct resource *res;
-       int i;
-
-       if (pci_is_root_bus(child))     /* It's a host bus, nothing to read */
-               return;
-
-       dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
-                child->secondary, child->subordinate,
-                dev->transparent ? " (subtractive decode)": "");
-
-       if (dev->transparent) {
-               for(i = 3; i < PCI_BUS_NUM_RESOURCES; i++)
-                       child->resource[i] = child->parent->resource[i - 3];
-       }
 
        res = child->resource[0];
        pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
@@ -316,26 +303,50 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
                limit |= (io_limit_hi << 16);
        }
 
-       if (base <= limit) {
+       if (base && base <= limit) {
                res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
                if (!res->start)
                        res->start = base;
                if (!res->end)
                        res->end = limit + 0xfff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
+       } else {
+               dev_printk(KERN_DEBUG, &dev->dev,
+                        "  bridge window [io  %#06lx-%#06lx] (disabled)\n",
+                                base, limit);
        }
+}
+
+static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
+{
+       struct pci_dev *dev = child->self;
+       u16 mem_base_lo, mem_limit_lo;
+       unsigned long base, limit;
+       struct resource *res;
 
        res = child->resource[1];
        pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
        pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
        base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
        limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
-       if (base <= limit) {
+       if (base && base <= limit) {
                res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
+       } else {
+               dev_printk(KERN_DEBUG, &dev->dev,
+                       "  bridge window [mem %#010lx-%#010lx] (disabled)\n",
+                                        base, limit + 0xfffff);
        }
+}
+
+static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
+{
+       struct pci_dev *dev = child->self;
+       u16 mem_base_lo, mem_limit_lo;
+       unsigned long base, limit;
+       struct resource *res;
 
        res = child->resource[2];
        pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
@@ -366,7 +377,7 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
 #endif
                }
        }
-       if (base <= limit) {
+       if (base && base <= limit) {
                res->flags = (mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) |
                                         IORESOURCE_MEM | IORESOURCE_PREFETCH;
                if (res->flags & PCI_PREF_RANGE_TYPE_64)
@@ -374,6 +385,44 @@ void __devinit pci_read_bridge_bases(struct pci_bus *child)
                res->start = base;
                res->end = limit + 0xfffff;
                dev_printk(KERN_DEBUG, &dev->dev, "  bridge window %pR\n", res);
+       } else {
+               dev_printk(KERN_DEBUG, &dev->dev,
+                    "  bridge window [mem %#010lx-%#010lx pref] (disabled)\n",
+                                        base, limit + 0xfffff);
+       }
+}
+
+void __devinit pci_read_bridge_bases(struct pci_bus *child)
+{
+       struct pci_dev *dev = child->self;
+       struct resource *res;
+       int i;
+
+       if (pci_is_root_bus(child))     /* It's a host bus, nothing to read */
+               return;
+
+       dev_info(&dev->dev, "PCI bridge to [bus %02x-%02x]%s\n",
+                child->secondary, child->subordinate,
+                dev->transparent ? " (subtractive decode)" : "");
+
+       pci_bus_remove_resources(child);
+       for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++)
+               child->resource[i] = &dev->resource[PCI_BRIDGE_RESOURCES+i];
+
+       pci_read_bridge_io(child);
+       pci_read_bridge_mmio(child);
+       pci_read_bridge_mmio_pref(child);
+
+       if (dev->transparent) {
+               pci_bus_for_each_resource(child->parent, res, i) {
+                       if (res) {
+                               pci_bus_add_resource(child, res,
+                                                    PCI_SUBTRACTIVE_DECODE);
+                               dev_printk(KERN_DEBUG, &dev->dev,
+                                          "  bridge window %pR (subtractive decode)\n",
+                                          res);
+                       }
+               }
        }
 }
 
@@ -387,10 +436,147 @@ static struct pci_bus * pci_alloc_bus(void)
                INIT_LIST_HEAD(&b->children);
                INIT_LIST_HEAD(&b->devices);
                INIT_LIST_HEAD(&b->slots);
+               INIT_LIST_HEAD(&b->resources);
+               b->max_bus_speed = PCI_SPEED_UNKNOWN;
+               b->cur_bus_speed = PCI_SPEED_UNKNOWN;
        }
        return b;
 }
 
+static unsigned char pcix_bus_speed[] = {
+       PCI_SPEED_UNKNOWN,              /* 0 */
+       PCI_SPEED_66MHz_PCIX,           /* 1 */
+       PCI_SPEED_100MHz_PCIX,          /* 2 */
+       PCI_SPEED_133MHz_PCIX,          /* 3 */
+       PCI_SPEED_UNKNOWN,              /* 4 */
+       PCI_SPEED_66MHz_PCIX_ECC,       /* 5 */
+       PCI_SPEED_100MHz_PCIX_ECC,      /* 6 */
+       PCI_SPEED_133MHz_PCIX_ECC,      /* 7 */
+       PCI_SPEED_UNKNOWN,              /* 8 */
+       PCI_SPEED_66MHz_PCIX_266,       /* 9 */
+       PCI_SPEED_100MHz_PCIX_266,      /* A */
+       PCI_SPEED_133MHz_PCIX_266,      /* B */
+       PCI_SPEED_UNKNOWN,              /* C */
+       PCI_SPEED_66MHz_PCIX_533,       /* D */
+       PCI_SPEED_100MHz_PCIX_533,      /* E */
+       PCI_SPEED_133MHz_PCIX_533       /* F */
+};
+
+static unsigned char pcie_link_speed[] = {
+       PCI_SPEED_UNKNOWN,              /* 0 */
+       PCIE_SPEED_2_5GT,               /* 1 */
+       PCIE_SPEED_5_0GT,               /* 2 */
+       PCIE_SPEED_8_0GT,               /* 3 */
+       PCI_SPEED_UNKNOWN,              /* 4 */
+       PCI_SPEED_UNKNOWN,              /* 5 */
+       PCI_SPEED_UNKNOWN,              /* 6 */
+       PCI_SPEED_UNKNOWN,              /* 7 */
+       PCI_SPEED_UNKNOWN,              /* 8 */
+       PCI_SPEED_UNKNOWN,              /* 9 */
+       PCI_SPEED_UNKNOWN,              /* A */
+       PCI_SPEED_UNKNOWN,              /* B */
+       PCI_SPEED_UNKNOWN,              /* C */
+       PCI_SPEED_UNKNOWN,              /* D */
+       PCI_SPEED_UNKNOWN,              /* E */
+       PCI_SPEED_UNKNOWN               /* F */
+};
+
+void pcie_update_link_speed(struct pci_bus *bus, u16 linksta)
+{
+       bus->cur_bus_speed = pcie_link_speed[linksta & 0xf];
+}
+EXPORT_SYMBOL_GPL(pcie_update_link_speed);
+
+static unsigned char agp_speeds[] = {
+       AGP_UNKNOWN,
+       AGP_1X,
+       AGP_2X,
+       AGP_4X,
+       AGP_8X
+};
+
+static enum pci_bus_speed agp_speed(int agp3, int agpstat)
+{
+       int index = 0;
+
+       if (agpstat & 4)
+               index = 3;
+       else if (agpstat & 2)
+               index = 2;
+       else if (agpstat & 1)
+               index = 1;
+       else
+               goto out;
+       
+       if (agp3) {
+               index += 2;
+               if (index == 5)
+                       index = 0;
+       }
+
+ out:
+       return agp_speeds[index];
+}
+
+
+static void pci_set_bus_speed(struct pci_bus *bus)
+{
+       struct pci_dev *bridge = bus->self;
+       int pos;
+
+       pos = pci_find_capability(bridge, PCI_CAP_ID_AGP);
+       if (!pos)
+               pos = pci_find_capability(bridge, PCI_CAP_ID_AGP3);
+       if (pos) {
+               u32 agpstat, agpcmd;
+
+               pci_read_config_dword(bridge, pos + PCI_AGP_STATUS, &agpstat);
+               bus->max_bus_speed = agp_speed(agpstat & 8, agpstat & 7);
+
+               pci_read_config_dword(bridge, pos + PCI_AGP_COMMAND, &agpcmd);
+               bus->cur_bus_speed = agp_speed(agpstat & 8, agpcmd & 7);
+       }
+
+       pos = pci_find_capability(bridge, PCI_CAP_ID_PCIX);
+       if (pos) {
+               u16 status;
+               enum pci_bus_speed max;
+               pci_read_config_word(bridge, pos + 2, &status);
+
+               if (status & 0x8000) {
+                       max = PCI_SPEED_133MHz_PCIX_533;
+               } else if (status & 0x4000) {
+                       max = PCI_SPEED_133MHz_PCIX_266;
+               } else if (status & 0x0002) {
+                       if (((status >> 12) & 0x3) == 2) {
+                               max = PCI_SPEED_133MHz_PCIX_ECC;
+                       } else {
+                               max = PCI_SPEED_133MHz_PCIX;
+                       }
+               } else {
+                       max = PCI_SPEED_66MHz_PCIX;
+               }
+
+               bus->max_bus_speed = max;
+               bus->cur_bus_speed = pcix_bus_speed[(status >> 6) & 0xf];
+
+               return;
+       }
+
+       pos = pci_find_capability(bridge, PCI_CAP_ID_EXP);
+       if (pos) {
+               u32 linkcap;
+               u16 linksta;
+
+               pci_read_config_dword(bridge, pos + PCI_EXP_LNKCAP, &linkcap);
+               bus->max_bus_speed = pcie_link_speed[linkcap & 0xf];
+
+               pci_read_config_word(bridge, pos + PCI_EXP_LNKSTA, &linksta);
+               pcie_update_link_speed(bus, linksta);
+       }
+}
+
+
 static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
                                           struct pci_dev *bridge, int busnr)
 {
@@ -430,6 +616,8 @@ static struct pci_bus *pci_alloc_child_bus(struct pci_bus *parent,
        child->self = bridge;
        child->bridge = get_device(&bridge->dev);
 
+       pci_set_bus_speed(child);
+
        /* Set up default resource pointers and names.. */
        for (i = 0; i < PCI_BRIDGE_RESOURCE_NUM; i++) {
                child->resource[i] = &bridge->resource[PCI_BRIDGE_RESOURCES+i];
@@ -485,16 +673,20 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
        int is_cardbus = (dev->hdr_type == PCI_HEADER_TYPE_CARDBUS);
        u32 buses, i, j = 0;
        u16 bctl;
+       u8 primary, secondary, subordinate;
        int broken = 0;
 
        pci_read_config_dword(dev, PCI_PRIMARY_BUS, &buses);
+       primary = buses & 0xFF;
+       secondary = (buses >> 8) & 0xFF;
+       subordinate = (buses >> 16) & 0xFF;
 
-       dev_dbg(&dev->dev, "scanning behind bridge, config %06x, pass %d\n",
-               buses & 0xffffff, pass);
+       dev_dbg(&dev->dev, "scanning [bus %02x-%02x] behind bridge, pass %d\n",
+               secondary, subordinate, pass);
 
        /* Check if setup is sensible at all */
        if (!pass &&
-           ((buses & 0xff) != bus->number || ((buses >> 8) & 0xff) <= bus->number)) {
+           (primary != bus->number || secondary <= bus->number)) {
                dev_dbg(&dev->dev, "bus configuration invalid, reconfiguring\n");
                broken = 1;
        }
@@ -505,15 +697,15 @@ 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);
 
-       if ((buses & 0xffff00) && !pcibios_assign_all_busses() && !is_cardbus && !broken) {
-               unsigned int cmax, busnr;
+       if ((secondary || subordinate) && !pcibios_assign_all_busses() &&
+           !is_cardbus && !broken) {
+               unsigned int cmax;
                /*
                 * Bus already configured by firmware, process it in the first
                 * pass and just note the configuration.
                 */
                if (pass)
                        goto out;
-               busnr = (buses >> 8) & 0xFF;
 
                /*
                 * If we already got to this bus through a different bridge,
@@ -522,13 +714,13 @@ int __devinit pci_scan_bridge(struct pci_bus *bus, struct pci_dev *dev, int max,
                 * However, we continue to descend down the hierarchy and
                 * scan remaining child buses.
                 */
-               child = pci_find_bus(pci_domain_nr(bus), busnr);
+               child = pci_find_bus(pci_domain_nr(bus), secondary);
                if (!child) {
-                       child = pci_add_new_bus(bus, dev, busnr);
+                       child = pci_add_new_bus(bus, dev, secondary);
                        if (!child)
                                goto out;
-                       child->primary = buses & 0xFF;
-                       child->subordinate = (buses >> 16) & 0xFF;
+                       child->primary = primary;
+                       child->subordinate = subordinate;
                        child->bridge_ctl = bctl;
                }
 
@@ -1084,11 +1276,19 @@ EXPORT_SYMBOL(pci_scan_single_device);
 static unsigned next_ari_fn(struct pci_dev *dev, unsigned fn)
 {
        u16 cap;
-       unsigned pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
+       unsigned pos, next_fn;
+
+       if (!dev)
+               return 0;
+
+       pos = pci_find_ext_capability(dev, PCI_EXT_CAP_ID_ARI);
        if (!pos)
                return 0;
        pci_read_config_word(dev, pos + 4, &cap);
-       return cap >> 8;
+       next_fn = cap >> 8;
+       if (next_fn <= fn)
+               return 0;
+       return next_fn;
 }
 
 static unsigned next_trad_fn(struct pci_dev *dev, unsigned fn)
@@ -1133,12 +1333,14 @@ int pci_scan_slot(struct pci_bus *bus, int devfn)
                return 0; /* Already scanned the entire slot */
 
        dev = pci_scan_single_device(bus, devfn);
-       if (dev && !dev->is_added)      /* new device? */
+       if (!dev)
+               return 0;
+       if (!dev->is_added)
                nr++;
 
        if (pci_ari_enabled(bus))
                next_fn = next_ari_fn;
-       else if (dev && dev->multifunction)
+       else if (dev->multifunction)
                next_fn = next_trad_fn;
 
        for (fn = next_fn(dev, 0); fn > 0; fn = next_fn(dev, fn)) {
@@ -1238,6 +1440,7 @@ struct pci_bus * pci_create_bus(struct device *parent,
        if (error)
                goto dev_reg_err;
        b->bridge = get_device(dev);
+       device_enable_async_suspend(b->bridge);
 
        if (!parent)
                set_dev_node(b->bridge, pcibus_to_node(b));