From bf5e2ba28f24f82a64524ef4772c9ebe12e2cd2a Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Thu, 20 Dec 2007 14:54:51 +1100 Subject: [PATCH] [POWERPC] Merge PCI resource fixups The PCI code in 32 and 64 bits fixes up resources differently. 32 bits uses a header quirk plus handles bridges in pcibios_fixup_bus() while 64 bits does things in various places depending on whether you are using OF probing, using PCI hotplug, etc... This merges those by basically using the 32 bits approach for both, with various tweaks to make 64 bits work with the new approach. Signed-off-by: Benjamin Herrenschmidt Signed-off-by: Paul Mackerras --- arch/powerpc/kernel/pci-common.c | 130 +++++++++++++++++++++ arch/powerpc/kernel/pci_32.c | 83 +------------ arch/powerpc/kernel/pci_64.c | 104 +++-------------- arch/powerpc/platforms/pseries/pci_dlpar.c | 14 +-- drivers/pci/hotplug/rpadlpar_core.c | 2 +- include/asm-powerpc/machdep.h | 14 +-- include/asm-powerpc/pci-bridge.h | 2 +- include/asm-powerpc/pci.h | 6 +- 8 files changed, 167 insertions(+), 188 deletions(-) diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 0245c989d3..c61e9324f7 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 f05ef5b178..717c554d46 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 6d1c28fc5e..b9619b9e5e 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 : ""); 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 47f0e0857f..5a5a19e40b 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); diff --git a/drivers/pci/hotplug/rpadlpar_core.c b/drivers/pci/hotplug/rpadlpar_core.c index b169b0e264..191954bc8e 100644 --- a/drivers/pci/hotplug/rpadlpar_core.c +++ b/drivers/pci/hotplug/rpadlpar_core.c @@ -155,7 +155,7 @@ static void dlpar_pci_add_bus(struct device_node *dn) dev->hdr_type == PCI_HEADER_TYPE_CARDBUS) of_scan_pci_bridge(dn, dev); - pcibios_fixup_new_pci_devices(dev->subordinate,0); + pcibios_fixup_new_pci_devices(dev->subordinate); /* Claim new bus resources */ pcibios_claim_one_bus(dev->bus); diff --git a/include/asm-powerpc/machdep.h b/include/asm-powerpc/machdep.h index d5cd98214f..ed91031486 100644 --- a/include/asm-powerpc/machdep.h +++ b/include/asm-powerpc/machdep.h @@ -205,13 +205,6 @@ struct machdep_calls { * optional PCI "hooks" */ - /* Called after PPC generic resource fixup to perform - machine specific fixups */ - void (*pcibios_fixup_resources)(struct pci_dev *); - - /* Called for each PCI bus in the system when it's probed */ - void (*pcibios_fixup_bus)(struct pci_bus *); - /* Called when pci_enable_device() is called (initial=0) or * when a device with no assigned resource is found (initial=1). * Returns 0 to allow assignment/enabling of the device. */ @@ -225,6 +218,13 @@ struct machdep_calls { #endif /* CONFIG_PPC32 */ + /* Called after PPC generic resource fixup to perform + machine specific fixups */ + void (*pcibios_fixup_resources)(struct pci_dev *); + + /* Called for each PCI bus in the system when it's probed */ + void (*pcibios_fixup_bus)(struct pci_bus *); + /* Called to shutdown machine specific hardware not already controlled * by other drivers. */ diff --git a/include/asm-powerpc/pci-bridge.h b/include/asm-powerpc/pci-bridge.h index fed8f52071..4aeef7f3d7 100644 --- a/include/asm-powerpc/pci-bridge.h +++ b/include/asm-powerpc/pci-bridge.h @@ -235,7 +235,7 @@ extern void pcibios_remove_pci_devices(struct pci_bus *bus); /** Discover new pci devices under this bus, and add them */ extern void pcibios_add_pci_devices(struct pci_bus *bus); -extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus, int fix_bus); +extern void pcibios_fixup_new_pci_devices(struct pci_bus *bus); extern int pcibios_remove_root_bus(struct pci_controller *phb); diff --git a/include/asm-powerpc/pci.h b/include/asm-powerpc/pci.h index 2883f56670..9899d893c1 100644 --- a/include/asm-powerpc/pci.h +++ b/include/asm-powerpc/pci.h @@ -196,9 +196,6 @@ static inline struct resource *pcibios_select_root(struct pci_dev *pdev, return root; } -extern void pcibios_fixup_device_resources(struct pci_dev *dev, - struct pci_bus *bus); - extern void pcibios_setup_new_device(struct pci_dev *dev); extern void pcibios_claim_one_bus(struct pci_bus *b); @@ -226,5 +223,8 @@ extern void pci_resource_to_user(const struct pci_dev *dev, int bar, const struct resource *rsrc, resource_size_t *start, resource_size_t *end); +extern void pcibios_do_bus_setup(struct pci_bus *bus); +extern void pcibios_fixup_of_probed_bus(struct pci_bus *bus); + #endif /* __KERNEL__ */ #endif /* __ASM_POWERPC_PCI_H */ -- 2.39.5