diff options
Diffstat (limited to 'drivers/pci/setup-bus.c')
| -rw-r--r-- | drivers/pci/setup-bus.c | 134 |
1 files changed, 70 insertions, 64 deletions
diff --git a/drivers/pci/setup-bus.c b/drivers/pci/setup-bus.c index 7c443b4583a..c48cd377b3f 100644 --- a/drivers/pci/setup-bus.c +++ b/drivers/pci/setup-bus.c @@ -71,53 +71,50 @@ static void pbus_assign_resources_sorted(const struct pci_bus *bus) void pci_setup_cardbus(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; + struct resource *res; struct pci_bus_region region; - dev_info(&bridge->dev, "CardBus bridge, secondary bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + dev_info(&bridge->dev, "CardBus bridge to [bus %02x-%02x]\n", + bus->secondary, bus->subordinate); - pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); - if (bus->resource[0]->flags & IORESOURCE_IO) { + res = bus->resource[0]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { /* * The IO resource is allocated a range twice as large as it * would normally need. This allows us to set both IO regs. */ - dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_IO_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_0, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); - if (bus->resource[1]->flags & IORESOURCE_IO) { - dev_info(&bridge->dev, " IO window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[1]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_IO_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_IO_LIMIT_1, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); - if (bus->resource[2]->flags & IORESOURCE_MEM) { - dev_info(&bridge->dev, " PREFETCH window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[2]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_0, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_0, region.end); } - pcibios_resource_to_bus(bridge, ®ion, bus->resource[3]); - if (bus->resource[3]->flags & IORESOURCE_MEM) { - dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + res = bus->resource[3]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { + dev_info(&bridge->dev, " bridge window %pR\n", res); pci_write_config_dword(bridge, PCI_CB_MEMORY_BASE_1, region.start); pci_write_config_dword(bridge, PCI_CB_MEMORY_LIMIT_1, @@ -140,34 +137,33 @@ EXPORT_SYMBOL(pci_setup_cardbus); static void pci_setup_bridge(struct pci_bus *bus) { struct pci_dev *bridge = bus->self; + struct resource *res; struct pci_bus_region region; u32 l, bu, lu, io_upper16; - int pref_mem64; if (pci_is_enabled(bridge)) return; - dev_info(&bridge->dev, "PCI bridge, secondary bus %04x:%02x\n", - pci_domain_nr(bus), bus->number); + dev_info(&bridge->dev, "PCI bridge to [bus %02x-%02x]\n", + bus->secondary, bus->subordinate); /* Set up the top and bottom of the PCI I/O segment for this bus. */ - pcibios_resource_to_bus(bridge, ®ion, bus->resource[0]); - if (bus->resource[0]->flags & IORESOURCE_IO) { + res = bus->resource[0]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_IO) { pci_read_config_dword(bridge, PCI_IO_BASE, &l); l &= 0xffff0000; l |= (region.start >> 8) & 0x00f0; l |= region.end & 0xf000; /* Set up upper 16 bits of I/O base/limit. */ io_upper16 = (region.end & 0xffff0000) | (region.start >> 16); - dev_info(&bridge->dev, " IO window: %#04lx-%#04lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { /* Clear upper 16 bits of I/O base/limit. */ io_upper16 = 0; l = 0x00f0; - dev_info(&bridge->dev, " IO window: disabled\n"); + dev_info(&bridge->dev, " bridge window [io disabled]\n"); } /* Temporarily disable the I/O range before updating PCI_IO_BASE. */ pci_write_config_dword(bridge, PCI_IO_BASE_UPPER16, 0x0000ffff); @@ -178,17 +174,16 @@ static void pci_setup_bridge(struct pci_bus *bus) /* Set up the top and bottom of the PCI Memory segment for this bus. */ - pcibios_resource_to_bus(bridge, ®ion, bus->resource[1]); - if (bus->resource[1]->flags & IORESOURCE_MEM) { + res = bus->resource[1]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_MEM) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - dev_info(&bridge->dev, " MEM window: %#08lx-%#08lx\n", - (unsigned long)region.start, - (unsigned long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " MEM window: disabled\n"); + dev_info(&bridge->dev, " bridge window [mem disabled]\n"); } pci_write_config_dword(bridge, PCI_MEMORY_BASE, l); @@ -198,34 +193,27 @@ static void pci_setup_bridge(struct pci_bus *bus) pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, 0); /* Set up PREF base/limit. */ - pref_mem64 = 0; bu = lu = 0; - pcibios_resource_to_bus(bridge, ®ion, bus->resource[2]); - if (bus->resource[2]->flags & IORESOURCE_PREFETCH) { - int width = 8; + res = bus->resource[2]; + pcibios_resource_to_bus(bridge, ®ion, res); + if (res->flags & IORESOURCE_PREFETCH) { l = (region.start >> 16) & 0xfff0; l |= region.end & 0xfff00000; - if (bus->resource[2]->flags & IORESOURCE_MEM_64) { - pref_mem64 = 1; + if (res->flags & IORESOURCE_MEM_64) { bu = upper_32_bits(region.start); lu = upper_32_bits(region.end); - width = 16; } - dev_info(&bridge->dev, " PREFETCH window: %#0*llx-%#0*llx\n", - width, (unsigned long long)region.start, - width, (unsigned long long)region.end); + dev_info(&bridge->dev, " bridge window %pR\n", res); } else { l = 0x0000fff0; - dev_info(&bridge->dev, " PREFETCH window: disabled\n"); + dev_info(&bridge->dev, " bridge window [mem pref disabled]\n"); } pci_write_config_dword(bridge, PCI_PREF_MEMORY_BASE, l); - if (pref_mem64) { - /* Set the upper 32 bits of PREF base & limit. */ - pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); - pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); - } + /* Set the upper 32 bits of PREF base & limit. */ + pci_write_config_dword(bridge, PCI_PREF_BASE_UPPER32, bu); + pci_write_config_dword(bridge, PCI_PREF_LIMIT_UPPER32, lu); pci_write_config_word(bridge, PCI_BRIDGE_CONTROL, bus->bridge_ctl); } @@ -309,7 +297,7 @@ static struct resource *find_free_bus_resource(struct pci_bus *bus, unsigned lon since these windows have 4K granularity and the IO ranges of non-bridge PCI devices are limited to 256 bytes. We must be careful with the ISA aliasing though. */ -static void pbus_size_io(struct pci_bus *bus) +static void pbus_size_io(struct pci_bus *bus, resource_size_t min_size) { struct pci_dev *dev; struct resource *b_res = find_free_bus_resource(bus, IORESOURCE_IO); @@ -336,6 +324,8 @@ static void pbus_size_io(struct pci_bus *bus) size1 += r_size; } } + if (size < min_size) + size = min_size; /* To be fixed in 2.5: we should have sort of HAVE_ISA flag in the struct pci_bus. */ #if defined(CONFIG_ISA) || defined(CONFIG_EISA) @@ -343,6 +333,10 @@ static void pbus_size_io(struct pci_bus *bus) #endif size = ALIGN(size + size1, 4096); if (!size) { + if (b_res->start || b_res->end) + dev_info(&bus->self->dev, "disabling bridge window " + "%pR to [bus %02x-%02x] (unused)\n", b_res, + bus->secondary, bus->subordinate); b_res->flags = 0; return; } @@ -354,7 +348,8 @@ static void pbus_size_io(struct pci_bus *bus) /* Calculate the size of the bus and minimal alignment which guarantees that all child resources fit in this size. */ -static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long type) +static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, + unsigned long type, resource_size_t min_size) { struct pci_dev *dev; resource_size_t min_align, align, size; @@ -387,8 +382,9 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long align = pci_resource_alignment(dev, r); order = __ffs(align) - 20; if (order > 11) { - dev_warn(&dev->dev, "BAR %d bad alignment %llx: " - "%pR\n", i, (unsigned long long)align, r); + dev_warn(&dev->dev, "disabling BAR %d: %pR " + "(bad alignment %#llx)\n", i, r, + (unsigned long long) align); r->flags = 0; continue; } @@ -404,6 +400,8 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long mem64_mask &= r->flags & IORESOURCE_MEM_64; } } + if (size < min_size) + size = min_size; align = 0; min_align = 0; @@ -420,6 +418,10 @@ static int pbus_size_mem(struct pci_bus *bus, unsigned long mask, unsigned long } size = ALIGN(size, min_align); if (!size) { + if (b_res->start || b_res->end) + dev_info(&bus->self->dev, "disabling bridge window " + "%pR to [bus %02x-%02x] (unused)\n", b_res, + bus->secondary, bus->subordinate); b_res->flags = 0; return 1; } @@ -483,6 +485,7 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) { struct pci_dev *dev; unsigned long mask, prefmask; + resource_size_t min_mem_size = 0, min_io_size = 0; list_for_each_entry(dev, &bus->devices, bus_list) { struct pci_bus *b = dev->subordinate; @@ -512,8 +515,12 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) case PCI_CLASS_BRIDGE_PCI: pci_bridge_check_ranges(bus); + if (bus->self->is_hotplug_bridge) { + min_io_size = pci_hotplug_io_size; + min_mem_size = pci_hotplug_mem_size; + } default: - pbus_size_io(bus); + pbus_size_io(bus, min_io_size); /* If the bridge supports prefetchable range, size it separately. If it doesn't, or its prefetchable window has already been allocated by arch code, try @@ -521,9 +528,11 @@ void __ref pci_bus_size_bridges(struct pci_bus *bus) resources. */ mask = IORESOURCE_MEM; prefmask = IORESOURCE_MEM | IORESOURCE_PREFETCH; - if (pbus_size_mem(bus, prefmask, prefmask)) + if (pbus_size_mem(bus, prefmask, prefmask, min_mem_size)) mask = prefmask; /* Success, size non-prefetch only. */ - pbus_size_mem(bus, mask, IORESOURCE_MEM); + else + min_mem_size += min_mem_size; + pbus_size_mem(bus, mask, IORESOURCE_MEM, min_mem_size); break; } } @@ -570,10 +579,7 @@ static void pci_bus_dump_res(struct pci_bus *bus) if (!res || !res->end) continue; - dev_printk(KERN_DEBUG, &bus->dev, "resource %d %s %pR\n", i, - (res->flags & IORESOURCE_IO) ? "io: " : - ((res->flags & IORESOURCE_PREFETCH)? "pref mem":"mem:"), - res); + dev_printk(KERN_DEBUG, &bus->dev, "resource %d %pR\n", i, res); } } |
