diff options
Diffstat (limited to 'arch/powerpc')
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 130 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_32.c | 83 | ||||
-rw-r--r-- | arch/powerpc/kernel/pci_64.c | 104 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/pci_dlpar.c | 14 |
4 files changed, 155 insertions, 176 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 0245c98..c61e932 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -691,3 +691,133 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, res->end = (region->end + offset) & mask; } EXPORT_SYMBOL(pcibios_bus_to_resource); + +/* Fixup a bus resource into a linux resource */ +static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + resource_size_t offset = 0, mask = (resource_size_t)-1; + + if (res->flags & IORESOURCE_IO) { + offset = (unsigned long)hose->io_base_virt - _IO_BASE; + mask = 0xffffffffu; + } else if (res->flags & IORESOURCE_MEM) + offset = hose->pci_mem_offset; + + res->start = (res->start + offset) & mask; + res->end = (res->end + offset) & mask; + + pr_debug("PCI:%s %016llx-%016llx\n", + pci_name(dev), + (unsigned long long)res->start, + (unsigned long long)res->end); +} + + +/* This header fixup will do the resource fixup for all devices as they are + * probed, but not for bridge ranges + */ +static void __devinit pcibios_fixup_resources(struct pci_dev *dev) +{ + struct pci_controller *hose = pci_bus_to_host(dev->bus); + int i; + + if (!hose) { + printk(KERN_ERR "No host bridge for PCI dev %s !\n", + pci_name(dev)); + return; + } + for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { + struct resource *res = dev->resource + i; + if (!res->flags) + continue; + if (res->end == 0xffffffff) { + pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n", + pci_name(dev), i, + (unsigned long long)res->start, + (unsigned long long)res->end, + (unsigned int)res->flags); + res->end -= res->start; + res->start = 0; + res->flags |= IORESOURCE_UNSET; + continue; + } + + pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n", + pci_name(dev), i, + (unsigned long long)res->start,\ + (unsigned long long)res->end, + (unsigned int)res->flags); + + fixup_resource(res, dev); + } + + /* Call machine specific resource fixup */ + if (ppc_md.pcibios_fixup_resources) + ppc_md.pcibios_fixup_resources(dev); +} +DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); + +static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) +{ + struct pci_dev *dev = bus->self; + + pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); + + /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for + * now differently between 32 and 64 bits. + */ + if (dev != NULL) { + struct resource *res; + int i; + + for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { + if ((res = bus->resource[i]) == NULL) + continue; + if (!res->flags || bus->self->transparent) + continue; + + pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", + pci_name(dev), i, + (unsigned long long)res->start,\ + (unsigned long long)res->end, + (unsigned int)res->flags); + + fixup_resource(res, dev); + } + } + + /* Additional setup that is different between 32 and 64 bits for now */ + pcibios_do_bus_setup(bus); + + /* Platform specific bus fixups */ + if (ppc_md.pcibios_fixup_bus) + ppc_md.pcibios_fixup_bus(bus); + + /* Read default IRQs and fixup if necessary */ + list_for_each_entry(dev, &bus->devices, bus_list) { + pci_read_irq_line(dev); + if (ppc_md.pci_irq_fixup) + ppc_md.pci_irq_fixup(dev); + } +} + +void __devinit pcibios_fixup_bus(struct pci_bus *bus) +{ + /* When called from the generic PCI probe, read PCI<->PCI bridge + * bases before proceeding + */ + if (bus->self != NULL) + pci_read_bridge_bases(bus); + __pcibios_fixup_bus(bus); +} +EXPORT_SYMBOL(pcibios_fixup_bus); + +/* When building a bus from the OF tree rather than probing, we need a + * slightly different version of the fixup which doesn't read the + * bridge bases using config space accesses + */ +void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) +{ + __pcibios_fixup_bus(bus); +} diff --git a/arch/powerpc/kernel/pci_32.c b/arch/powerpc/kernel/pci_32.c index f05ef5b..717c554 100644 --- a/arch/powerpc/kernel/pci_32.c +++ b/arch/powerpc/kernel/pci_32.c @@ -40,7 +40,6 @@ unsigned int ppc_pci_flags; void pcibios_make_OF_bus_map(void); -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); static void fixup_cpc710_pci64(struct pci_dev* dev); @@ -98,53 +97,6 @@ fixup_cpc710_pci64(struct pci_dev* dev) } DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_IBM, PCI_DEVICE_ID_IBM_CPC710_PCI64, fixup_cpc710_pci64); -static void -pcibios_fixup_resources(struct pci_dev *dev) -{ - struct pci_controller* hose = (struct pci_controller *)dev->sysdata; - int i; - resource_size_t offset, mask; - - if (!hose) { - printk(KERN_ERR "No hose for PCI dev %s!\n", pci_name(dev)); - return; - } - for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { - struct resource *res = dev->resource + i; - if (!res->flags) - continue; - if (res->end == 0xffffffff) { - DBG("PCI:%s Resource %d [%016llx-%016llx] is unassigned\n", - pci_name(dev), i, (u64)res->start, (u64)res->end); - res->end -= res->start; - res->start = 0; - res->flags |= IORESOURCE_UNSET; - continue; - } - offset = 0; - mask = (resource_size_t)-1; - if (res->flags & IORESOURCE_MEM) { - offset = hose->pci_mem_offset; - } else if (res->flags & IORESOURCE_IO) { - offset = (unsigned long) hose->io_base_virt - - isa_io_base; - mask = 0xffffffffu; - } - if (offset != 0) { - res->start = (res->start + offset) & mask; - res->end = (res->end + offset) & mask; - 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); - } - } - - /* Call machine specific resource fixup */ - if (ppc_md.pcibios_fixup_resources) - ppc_md.pcibios_fixup_resources(dev); -} -DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); - static int skip_isa_ioresource_align(struct pci_dev *dev) { if ((ppc_pci_flags & PPC_PCI_CAN_SKIP_ISA_ALIGN) && @@ -757,14 +709,14 @@ pcibios_init(void) subsys_initcall(pcibios_init); -void pcibios_fixup_bus(struct pci_bus *bus) +void __devinit pcibios_do_bus_setup(struct pci_bus *bus) { struct pci_controller *hose = (struct pci_controller *) bus->sysdata; unsigned long io_offset; struct resource *res; - struct pci_dev *dev; int i; + /* Hookup PHB resources */ io_offset = (unsigned long)hose->io_base_virt - isa_io_base; if (bus->parent == NULL) { /* This is a host bridge - fill in its resources */ @@ -795,37 +747,6 @@ void pcibios_fixup_bus(struct pci_bus *bus) } bus->resource[i+1] = res; } - } else { - /* This is a subordinate bridge */ - pci_read_bridge_bases(bus); - - for (i = 0; i < 4; ++i) { - if ((res = bus->resource[i]) == NULL) - continue; - if (!res->flags || bus->self->transparent) - continue; - if (io_offset && (res->flags & IORESOURCE_IO)) { - res->start = (res->start + io_offset) & - 0xffffffffu; - res->end = (res->end + io_offset) & - 0xffffffffu; - } else if (hose->pci_mem_offset - && (res->flags & IORESOURCE_MEM)) { - res->start += hose->pci_mem_offset; - res->end += hose->pci_mem_offset; - } - } - } - - /* Platform specific bus fixups */ - if (ppc_md.pcibios_fixup_bus) - ppc_md.pcibios_fixup_bus(bus); - - /* Read default IRQs and fixup if necessary */ - list_for_each_entry(dev, &bus->devices, bus_list) { - pci_read_irq_line(dev); - if (ppc_md.pci_irq_fixup) - ppc_md.pci_irq_fixup(dev); } } diff --git a/arch/powerpc/kernel/pci_64.c b/arch/powerpc/kernel/pci_64.c index 6d1c28f..b9619b9 100644 --- a/arch/powerpc/kernel/pci_64.c +++ b/arch/powerpc/kernel/pci_64.c @@ -41,9 +41,6 @@ unsigned long pci_probe_only = 1; -static void fixup_resource(struct resource *res, struct pci_dev *dev); -static void do_bus_setup(struct pci_bus *bus); - /* pci_io_base -- the base address from which io bars are offsets. * This is the lowest I/O base address (so bar values are always positive), * and it *must* be the start of ISA space if an ISA bus exists because @@ -239,7 +236,6 @@ static void pci_parse_of_addrs(struct device_node *node, struct pci_dev *dev) res->end = base + size - 1; res->flags = flags; res->name = pci_name(dev); - fixup_resource(res, dev); } } @@ -308,7 +304,7 @@ struct pci_dev *of_create_pci_dev(struct device_node *node, EXPORT_SYMBOL(of_create_pci_dev); void __devinit of_scan_bus(struct device_node *node, - struct pci_bus *bus) + struct pci_bus *bus) { struct device_node *child = NULL; const u32 *reg; @@ -317,6 +313,7 @@ void __devinit of_scan_bus(struct device_node *node, DBG("of_scan_bus(%s) bus no %d... \n", node->full_name, bus->number); + /* Scan direct children */ while ((child = of_get_next_child(node, child)) != NULL) { DBG(" * %s\n", child->full_name); reg = of_get_property(child, "reg", ®len); @@ -328,19 +325,26 @@ void __devinit of_scan_bus(struct device_node *node, dev = of_create_pci_dev(child, bus, devfn); if (!dev) continue; - DBG("dev header type: %x\n", dev->hdr_type); + DBG(" dev header type: %x\n", dev->hdr_type); + } + + /* Ally all fixups */ + pcibios_fixup_of_probed_bus(bus); + /* Now scan child busses */ + list_for_each_entry(dev, &bus->devices, bus_list) { if (dev->hdr_type == PCI_HEADER_TYPE_BRIDGE || - dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) - of_scan_pci_bridge(child, dev); + dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) { + struct device_node *child = pci_device_to_OF_node(dev); + if (dev) + of_scan_pci_bridge(child, dev); + } } - - do_bus_setup(bus); } EXPORT_SYMBOL(of_scan_bus); void __devinit of_scan_pci_bridge(struct device_node *node, - struct pci_dev *dev) + struct pci_dev *dev) { struct pci_bus *bus; const u32 *busrange, *ranges; @@ -410,7 +414,6 @@ void __devinit of_scan_pci_bridge(struct device_node *node, res->start = of_read_number(&ranges[1], 2); res->end = res->start + size - 1; res->flags = flags; - fixup_resource(res, dev); } sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), bus->number); @@ -659,51 +662,13 @@ int __devinit pcibios_map_io_space(struct pci_bus *bus) } EXPORT_SYMBOL_GPL(pcibios_map_io_space); -static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) -{ - struct pci_controller *hose = pci_bus_to_host(dev->bus); - unsigned long offset; - - if (res->flags & IORESOURCE_IO) { - offset = (unsigned long)hose->io_base_virt - _IO_BASE; - res->start += offset; - res->end += offset; - } else if (res->flags & IORESOURCE_MEM) { - res->start += hose->pci_mem_offset; - res->end += hose->pci_mem_offset; - } -} - -void __devinit pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus) -{ - /* Update device resources. */ - int i; - - DBG("%s: Fixup resources:\n", pci_name(dev)); - for (i = 0; i < PCI_NUM_RESOURCES; i++) { - struct resource *res = &dev->resource[i]; - if (!res->flags) - continue; - - DBG(" 0x%02x < %08lx:0x%016lx...0x%016lx\n", - i, res->flags, res->start, res->end); - - fixup_resource(res, dev); - - DBG(" > %08lx:0x%016lx...0x%016lx\n", - res->flags, res->start, res->end); - } -} -EXPORT_SYMBOL(pcibios_fixup_device_resources); - void __devinit pcibios_setup_new_device(struct pci_dev *dev) { struct dev_archdata *sd = &dev->dev.archdata; sd->of_node = pci_device_to_OF_node(dev); - DBG("PCI device %s OF node: %s\n", pci_name(dev), + DBG("PCI: device %s OF node: %s\n", pci_name(dev), sd->of_node ? sd->of_node->full_name : "<none>"); sd->dma_ops = pci_dma_ops; @@ -717,7 +682,7 @@ void __devinit pcibios_setup_new_device(struct pci_dev *dev) } EXPORT_SYMBOL(pcibios_setup_new_device); -static void __devinit do_bus_setup(struct pci_bus *bus) +void __devinit pcibios_do_bus_setup(struct pci_bus *bus) { struct pci_dev *dev; @@ -726,42 +691,7 @@ static void __devinit do_bus_setup(struct pci_bus *bus) list_for_each_entry(dev, &bus->devices, bus_list) pcibios_setup_new_device(dev); - - /* Read default IRQs and fixup if necessary */ - list_for_each_entry(dev, &bus->devices, bus_list) { - pci_read_irq_line(dev); - if (ppc_md.pci_irq_fixup) - ppc_md.pci_irq_fixup(dev); - } -} - -void __devinit pcibios_fixup_bus(struct pci_bus *bus) -{ - struct pci_dev *dev = bus->self; - struct device_node *np; - - np = pci_bus_to_OF_node(bus); - - DBG("pcibios_fixup_bus(%s)\n", np ? np->full_name : "<???>"); - - if (dev && pci_probe_only && - (dev->class >> 8) == PCI_CLASS_BRIDGE_PCI) { - /* This is a subordinate bridge */ - - pci_read_bridge_bases(bus); - pcibios_fixup_device_resources(dev, bus); - } - - do_bus_setup(bus); - - if (!pci_probe_only) - return; - - list_for_each_entry(dev, &bus->devices, bus_list) - if ((dev->class >> 8) != PCI_CLASS_BRIDGE_PCI) - pcibios_fixup_device_resources(dev, bus); } -EXPORT_SYMBOL(pcibios_fixup_bus); unsigned long pci_address_to_pio(phys_addr_t address) { diff --git a/arch/powerpc/platforms/pseries/pci_dlpar.c b/arch/powerpc/platforms/pseries/pci_dlpar.c index 47f0e08..5a5a19e 100644 --- a/arch/powerpc/platforms/pseries/pci_dlpar.c +++ b/arch/powerpc/platforms/pseries/pci_dlpar.c @@ -83,7 +83,7 @@ EXPORT_SYMBOL_GPL(pcibios_remove_pci_devices); /* Must be called before pci_bus_add_devices */ void -pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) +pcibios_fixup_new_pci_devices(struct pci_bus *bus) { struct pci_dev *dev; @@ -98,8 +98,6 @@ pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus) /* Fill device archdata and setup iommu table */ pcibios_setup_new_device(dev); - if(fix_bus) - pcibios_fixup_device_resources(dev, bus); pci_read_irq_line(dev); for (i = 0; i < PCI_NUM_RESOURCES; i++) { struct resource *r = &dev->resource[i]; @@ -132,8 +130,8 @@ pcibios_pci_config_bridge(struct pci_dev *dev) pci_scan_child_bus(child_bus); - /* Fixup new pci devices without touching bus struct */ - pcibios_fixup_new_pci_devices(child_bus, 0); + /* Fixup new pci devices */ + pcibios_fixup_new_pci_devices(child_bus); /* Make the discovered devices available */ pci_bus_add_devices(child_bus); @@ -169,7 +167,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) /* use ofdt-based probe */ of_scan_bus(dn, bus); if (!list_empty(&bus->devices)) { - pcibios_fixup_new_pci_devices(bus, 0); + pcibios_fixup_new_pci_devices(bus); pci_bus_add_devices(bus); eeh_add_device_tree_late(bus); } @@ -178,7 +176,7 @@ pcibios_add_pci_devices(struct pci_bus * bus) slotno = PCI_SLOT(PCI_DN(dn->child)->devfn); num = pci_scan_slot(bus, PCI_DEVFN(slotno, 0)); if (num) { - pcibios_fixup_new_pci_devices(bus, 1); + pcibios_fixup_new_pci_devices(bus); pci_bus_add_devices(bus); eeh_add_device_tree_late(bus); } @@ -208,7 +206,7 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn) eeh_add_device_tree_early(dn); scan_phb(phb); - pcibios_fixup_new_pci_devices(phb->bus, 0); + pcibios_fixup_new_pci_devices(phb->bus); pci_bus_add_devices(phb->bus); eeh_add_device_tree_late(phb->bus); |