diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/pci_32.c | 191 |
1 files changed, 17 insertions, 174 deletions
diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index c1f34d5381a..1020d04b0a5 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -37,10 +37,6 @@ int pcibios_assign_bus_offset = 1; void pcibios_make_OF_bus_map(void); -static int pci_relocate_bridge_resource(struct pci_bus *bus, int i); -static int probe_resource(struct pci_bus *parent, struct resource *pr, - struct resource *res, struct resource **conflict); -static void update_bridge_base(struct pci_bus *bus, int i); static void pcibios_fixup_resources(struct pci_dev* dev); static void fixup_broken_pcnet32(struct pci_dev* dev); static int reparent_resources(struct resource *parent, struct resource *res); @@ -134,7 +130,7 @@ pcibios_fixup_resources(struct pci_dev *dev) if (offset != 0) { res->start = (res->start + offset) & mask; res->end = (res->end + offset) & mask; - DBG("Fixup res %d (%lx) of dev %s: %llx -> %llx\n", + DBG("PCI: Fixup res %d (0x%lx) of dev %s: %llx -> %llx\n", i, res->flags, pci_name(dev), (u64)res->start - offset, (u64)res->start); } @@ -267,9 +263,12 @@ pcibios_allocate_bus_resources(struct list_head *bus_list) } } - DBG("PCI: bridge rsrc %llx..%llx (%lx), parent %p\n", + DBG("PCI: dev %s (bus 0x%02x) bridge rsrc %d: %016llx..%016llx " + "(f:0x%08lx), parent %p\n", + bus->self ? pci_name(bus->self) : "PHB", bus->number, i, (u64)res->start, (u64)res->end, res->flags, pr); - if (pr) { + + if (pr && !(pr->flags & IORESOURCE_UNSET)) { if (request_resource(pr, res) == 0) continue; /* @@ -280,10 +279,11 @@ pcibios_allocate_bus_resources(struct list_head *bus_list) if (reparent_resources(pr, res) == 0) continue; } - printk(KERN_ERR "PCI: Cannot allocate resource region " - "%d of PCI bridge %d\n", i, bus->number); - if (pci_relocate_bridge_resource(bus, i)) - bus->resource[i] = NULL; + printk(KERN_WARNING + "PCI: Cannot allocate resource region " + "%d of PCI bridge %d, will remap\n", + i, bus->number); + res->flags |= IORESOURCE_UNSET; } pcibios_allocate_bus_resources(&bus->children); } @@ -324,112 +324,6 @@ reparent_resources(struct resource *parent, struct resource *res) return 0; } -/* - * A bridge has been allocated a range which is outside the range - * of its parent bridge, so it needs to be moved. - */ -static int __init -pci_relocate_bridge_resource(struct pci_bus *bus, int i) -{ - struct resource *res, *pr, *conflict; - resource_size_t try, size; - struct pci_bus *parent = bus->parent; - int j; - - if (parent == NULL) { - /* shouldn't ever happen */ - printk(KERN_ERR "PCI: can't move host bridge resource\n"); - return -1; - } - res = bus->resource[i]; - if (res == NULL) - return -1; - pr = NULL; - for (j = 0; j < 4; j++) { - struct resource *r = parent->resource[j]; - if (!r) - continue; - if ((res->flags ^ r->flags) & (IORESOURCE_IO | IORESOURCE_MEM)) - continue; - if (!((res->flags ^ r->flags) & IORESOURCE_PREFETCH)) { - pr = r; - break; - } - if (res->flags & IORESOURCE_PREFETCH) - pr = r; - } - if (pr == NULL) - return -1; - size = res->end - res->start; - if (pr->start > pr->end || size > pr->end - pr->start) - return -1; - try = pr->end; - for (;;) { - res->start = try - size; - res->end = try; - if (probe_resource(bus->parent, pr, res, &conflict) == 0) - break; - if (conflict->start <= pr->start + size) - return -1; - try = conflict->start - 1; - } - if (request_resource(pr, res)) { - DBG(KERN_ERR "PCI: huh? couldn't move to %llx..%llx\n", - (u64)res->start, (u64)res->end); - return -1; /* "can't happen" */ - } - update_bridge_base(bus, i); - printk(KERN_INFO "PCI: bridge %d resource %d moved to %llx..%llx\n", - bus->number, i, (unsigned long long)res->start, - (unsigned long long)res->end); - return 0; -} - -static int __init -probe_resource(struct pci_bus *parent, struct resource *pr, - struct resource *res, struct resource **conflict) -{ - struct pci_bus *bus; - struct pci_dev *dev; - struct resource *r; - int i; - - for (r = pr->child; r != NULL; r = r->sibling) { - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - list_for_each_entry(bus, &parent->children, node) { - for (i = 0; i < 4; ++i) { - if ((r = bus->resource[i]) == NULL) - continue; - if (!r->flags || r->start > r->end || r == res) - continue; - if (pci_find_parent_resource(bus->self, r) != pr) - continue; - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - } - list_for_each_entry(dev, &parent->devices, bus_list) { - for (i = 0; i < 6; ++i) { - r = &dev->resource[i]; - if (!r->flags || (r->flags & IORESOURCE_UNSET)) - continue; - if (pci_find_parent_resource(dev, r) != pr) - continue; - if (r->end >= res->start && res->end >= r->start) { - *conflict = r; - return 1; - } - } - } - return 0; -} - void __init update_bridge_resource(struct pci_dev *dev, struct resource *res) { @@ -486,24 +380,16 @@ update_bridge_resource(struct pci_dev *dev, struct resource *res) pci_write_config_word(dev, PCI_COMMAND, cmd); } -static void __init -update_bridge_base(struct pci_bus *bus, int i) -{ - struct resource *res = bus->resource[i]; - struct pci_dev *dev = bus->self; - update_bridge_resource(dev, res); -} - static inline void alloc_resource(struct pci_dev *dev, int idx) { struct resource *pr, *r = &dev->resource[idx]; - DBG("PCI:%s: Resource %d: %016llx-%016llx (f=%lx)\n", + DBG("PCI: Allocating %s: Resource %d: %016llx..%016llx (f=%lx)\n", pci_name(dev), idx, (u64)r->start, (u64)r->end, r->flags); pr = pci_find_parent_resource(dev, r); - if (!pr || request_resource(pr, r) < 0) { - printk(KERN_WARNING "PCI: Remapping resource region %d" - " of device %s\n", idx, pci_name(dev)); + if (!pr || (pr->flags & IORESOURCE_UNSET) || request_resource(pr, r) < 0) { + printk(KERN_WARNING "PCI: Cannot allocate resource region %d" + " of device %s, will remap\n", idx, pci_name(dev)); if (pr) DBG("PCI: parent is %p: %016llx-%016llx (f=%lx)\n", pr, (u64)pr->start, (u64)pr->end, pr->flags); @@ -552,50 +438,6 @@ pcibios_allocate_resources(int pass) } } -static void __init -pcibios_assign_resources(void) -{ - struct pci_dev *dev = NULL; - int idx; - struct resource *r; - - for_each_pci_dev(dev) { - int class = dev->class >> 8; - - /* Don't touch classless devices and host bridges */ - if (!class || class == PCI_CLASS_BRIDGE_HOST) - continue; - - for (idx = 0; idx < 6; idx++) { - r = &dev->resource[idx]; - - /* - * We shall assign a new address to this resource, - * either because the BIOS (sic) forgot to do so - * or because we have decided the old address was - * unusable for some reason. - */ - if ((r->flags & IORESOURCE_UNSET) && r->end && - (!ppc_md.pcibios_enable_device_hook || - !ppc_md.pcibios_enable_device_hook(dev, 1))) { - int rc; - - r->flags &= ~IORESOURCE_UNSET; - rc = pci_assign_resource(dev, idx); - BUG_ON(rc); - } - } - -#if 0 /* don't assign ROMs */ - r = &dev->resource[PCI_ROM_RESOURCE]; - r->end -= r->start; - r->start = 0; - if (r->end) - pci_assign_resource(dev, PCI_ROM_RESOURCE); -#endif - } -} - #ifdef CONFIG_PPC_OF /* * Functions below are used on OpenFirmware machines. @@ -1122,7 +964,8 @@ pcibios_init(void) #ifdef CONFIG_PPC_PMAC pcibios_fixup_p2p_bridges(); #endif /* CONFIG_PPC_PMAC */ - pcibios_assign_resources(); + DBG("PCI: Assigning unassigned resouces...\n"); + pci_assign_unassigned_resources(); /* Call machine dependent post-init code */ if (ppc_md.pcibios_after_init) |