From 05737c7c5bca9a4f3e0f8bb9476445971b64fafd Mon Sep 17 00:00:00 2001 From: Jason Jin Date: Fri, 28 Oct 2011 16:08:00 +0800 Subject: powerpc/fsl-pci: Don't hide resource for pci/e when configured as Agent/EP Current pci/pcie init code will hide the pci/pcie host resource. But did not judge it is host/RC or agent/EP. If configured as agent/EP, we should avoid hiding its resource in the host side. In PCI system, the Programing Interface can be used to judge the host/agent status: Programing Interface = 0: host Programing Interface = 1: Agent In PCIE system, both the Programing Interface and Header type can be used to judge the RC/EP status. Header Type = 0: EP Header Type = 1: RC Signed-off-by: Jason Jin Signed-off-by: Mingkai Hu Signed-off-by: Jia Hongtao Signed-off-by: Li Yang Signed-off-by: Kumar Gala --- arch/powerpc/kernel/pci-common.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 458ed3bee66..069aa75e716 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1747,10 +1747,13 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) static void fixup_hide_host_resource_fsl(struct pci_dev *dev) { int i, class = dev->class >> 8; + /* When configured as agent, programing interface = 1 */ + int prog_if = dev->class & 0xf; if ((class == PCI_CLASS_PROCESSOR_POWERPC || class == PCI_CLASS_BRIDGE_OTHER) && (dev->hdr_type == PCI_HEADER_TYPE_NORMAL) && + (prog_if == 0) && (dev->bus->parent == NULL)) { for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { dev->resource[i].start = 0; -- cgit v1.2.3 From 491b98c315dbe39b20bd4a24a6179c42349f42c0 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 6 Nov 2011 18:55:57 +0000 Subject: powerpc/pci: Add a platform hook after probe and before resource survey Some platforms need to perform resource allocation using a custom algorithm due to HW constraints, or may want to tweak things globally below a host bridge. For example OPAL support for IODA will need to perform a resource allocation pass that applies IODA specific segmentation constraints to MMIO which cannot be done simply using the kernel generic resource management code. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/machdep.h | 3 +++ arch/powerpc/kernel/pci-common.c | 6 ++++++ 2 files changed, 9 insertions(+) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/include/asm/machdep.h b/arch/powerpc/include/asm/machdep.h index b540d6fcedd..bf37931d1ad 100644 --- a/arch/powerpc/include/asm/machdep.h +++ b/arch/powerpc/include/asm/machdep.h @@ -213,6 +213,9 @@ struct machdep_calls { * allow assignment/enabling of the device. */ int (*pcibios_enable_device_hook)(struct pci_dev *); + /* Called after scan and before resource survey */ + void (*pcibios_fixup_phb)(struct pci_controller *hose); + /* Called to shutdown machine specific hardware not already controlled * by other drivers. */ diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 458ed3bee66..f5b753de371 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1732,6 +1732,12 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) if (mode == PCI_PROBE_NORMAL) hose->last_busno = bus->subordinate = pci_scan_child_bus(bus); + /* Platform gets a chance to do some global fixups before + * we proceed to resource allocation + */ + if (ppc_md.pcibios_fixup_phb) + ppc_md.pcibios_fixup_phb(hose); + /* Configure PCI Express settings */ if (bus && !pci_has_flag(PCI_PROBE_ONLY)) { struct pci_bus *child; -- cgit v1.2.3 From 48c2ce97fa406607ca5e11a76cf507d171452dd9 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Sun, 6 Nov 2011 18:55:58 +0000 Subject: powerpc/pci: Change how re-assigning resouces work When PCI_REASSIGN_ALL_RSRC is set, we used to clear all bus resources at the beginning of survey and re-allocate them later. This changes it so instead, during early fixup, we mark all resources as IORESOURCE_UNSET and move them down to be 0-based. Later, if bus resources are still unset at the beginning of the survey, then we clear them. This shouldn't impact the re-assignment case on 4xx, but will enable us to have the platform do some custom resource assignment before the survey, by clearing individual resources IORESOURCE_UNSET bit. Also limits the clutter in the kernel log from fixup when re-assigning since we don't care about the offset applied to the BAR values in this case. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/kernel/pci-common.c | 66 ++++++++++++++++++++++------------------ 1 file changed, 36 insertions(+), 30 deletions(-) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index f5b753de371..8f428fff545 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -921,18 +921,22 @@ static void __devinit pcibios_fixup_resources(struct pci_dev *dev) struct resource *res = dev->resource + i; if (!res->flags) continue; - /* On platforms that have PCI_PROBE_ONLY set, we don't - * consider 0 as an unassigned BAR value. It's technically - * a valid value, but linux doesn't like it... so when we can - * re-assign things, we do so, but if we can't, we keep it - * around and hope for the best... + + /* If we're going to re-assign everything, we mark all resources + * as unset (and 0-base them). In addition, we mark BARs starting + * at 0 as unset as well, except if PCI_PROBE_ONLY is also set + * since in that case, we don't want to re-assign anything */ - if (res->start == 0 && !pci_has_flag(PCI_PROBE_ONLY)) { - 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); + if (pci_has_flag(PCI_REASSIGN_ALL_RSRC) || + (res->start == 0 && !pci_has_flag(PCI_PROBE_ONLY))) { + /* Only print message if not re-assigning */ + if (!pci_has_flag(PCI_REASSIGN_ALL_RSRC)) + 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; @@ -1042,6 +1046,16 @@ static void __devinit pcibios_fixup_bridge(struct pci_bus *bus) if (i >= 3 && bus->self->transparent) continue; + /* If we are going to re-assign everything, mark the resource + * as unset and move it down to 0 + */ + if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) { + res->flags |= IORESOURCE_UNSET; + res->end -= res->start; + res->start = 0; + continue; + } + pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", pci_name(dev), i, (unsigned long long)res->start,\ @@ -1262,18 +1276,15 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) pci_bus_for_each_resource(bus, res, i) { if (!res || !res->flags || res->start > res->end || res->parent) continue; + + /* If the resource was left unset at this point, we clear it */ + if (res->flags & IORESOURCE_UNSET) + goto clear_resource; + if (bus->parent == NULL) pr = (res->flags & IORESOURCE_IO) ? &ioport_resource : &iomem_resource; else { - /* Don't bother with non-root busses when - * re-assigning all resources. We clear the - * resource flags as if they were colliding - * and as such ensure proper re-allocation - * later. - */ - if (pci_has_flag(PCI_REASSIGN_ALL_RSRC)) - goto clear_resource; pr = pci_find_parent_resource(bus->self, res); if (pr == res) { /* this happens when the generic PCI @@ -1304,9 +1315,9 @@ void pcibios_allocate_bus_resources(struct pci_bus *bus) if (reparent_resources(pr, res) == 0) continue; } - printk(KERN_WARNING "PCI: Cannot allocate resource region " - "%d of PCI bridge %d, will remap\n", i, bus->number); -clear_resource: + pr_warning("PCI: Cannot allocate resource region " + "%d of PCI bridge %d, will remap\n", i, bus->number); + clear_resource: res->start = res->end = 0; res->flags = 0; } @@ -1451,16 +1462,11 @@ void __init pcibios_resource_survey(void) { struct pci_bus *b; - /* Allocate and assign resources. If we re-assign everything, then - * we skip the allocate phase - */ + /* Allocate and assign resources */ list_for_each_entry(b, &pci_root_buses, node) pcibios_allocate_bus_resources(b); - - if (!pci_has_flag(PCI_REASSIGN_ALL_RSRC)) { - pcibios_allocate_resources(0); - pcibios_allocate_resources(1); - } + pcibios_allocate_resources(0); + pcibios_allocate_resources(1); /* Before we start assigning unassigned resource, we try to reserve * the low IO area and the VGA memory area if they intersect the -- cgit v1.2.3 From 4666ca2aa344105da0da3afda48d987c82261c05 Mon Sep 17 00:00:00 2001 From: Benjamin Herrenschmidt Date: Tue, 29 Nov 2011 20:16:25 +0000 Subject: powerpc/pci: Make pci_read_irq_line() static It's only used inside the same file where it's defined. There's also no point exporting it anymore. Signed-off-by: Benjamin Herrenschmidt --- arch/powerpc/include/asm/pci.h | 2 -- arch/powerpc/kernel/pci-common.c | 3 +-- 2 files changed, 1 insertion(+), 4 deletions(-) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 49c3de582be..1c92013466e 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -184,8 +184,6 @@ extern void of_scan_pci_bridge(struct pci_dev *dev); extern void of_scan_bus(struct device_node *node, struct pci_bus *bus); extern void of_rescan_bus(struct device_node *node, struct pci_bus *bus); -extern int pci_read_irq_line(struct pci_dev *dev); - struct file; extern pgprot_t pci_phys_mem_access_prot(struct file *file, unsigned long pfn, diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 9bffc028f45..fa4a573d671 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -214,7 +214,7 @@ char __devinit *pcibios_setup(char *str) * If the interrupt is used, then gets the interrupt line from the * openfirmware and sets it in the pci_dev and pci_config line. */ -int pci_read_irq_line(struct pci_dev *pci_dev) +static int pci_read_irq_line(struct pci_dev *pci_dev) { struct of_irq oirq; unsigned int virq; @@ -283,7 +283,6 @@ int pci_read_irq_line(struct pci_dev *pci_dev) return 0; } -EXPORT_SYMBOL(pci_read_irq_line); /* * Platform support for /proc/bus/pci/X/Y mmap()s, -- cgit v1.2.3 From 79c8be8384d8b41ff67b5fda03c7ace3c3af1550 Mon Sep 17 00:00:00 2001 From: Myron Stowe Date: Fri, 28 Oct 2011 15:48:03 -0600 Subject: PCI: PowerPC: convert pcibios_set_master() to a non-inlined function This patch converts PowerPC's architecture-specific 'pcibios_set_master()' routine to a non-inlined function. This will allow follow on patches to create a generic 'pcibios_set_master()' function using the '__weak' attribute which can be used by all architectures as a default which, if necessary, can then be over- ridden by architecture-specific code. Converting 'pci_bios_set_master()' to a non-inlined function will allow PowerPC's 'pcibios_set_master()' implementation to remain architecture-specific after the generic version is introduced and thus, not change current behavior. No functional change. Acked-by: Benjamin Herrenschmidt Signed-off-by: Myron Stowe Signed-off-by: Jesse Barnes --- arch/powerpc/include/asm/pci.h | 5 ----- arch/powerpc/kernel/pci-common.c | 5 +++++ 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/include/asm/pci.h b/arch/powerpc/include/asm/pci.h index 49c3de582be..9284fe85046 100644 --- a/arch/powerpc/include/asm/pci.h +++ b/arch/powerpc/include/asm/pci.h @@ -46,11 +46,6 @@ struct pci_dev; #define pcibios_assign_all_busses() \ (pci_has_flag(PCI_REASSIGN_ALL_BUS)) -static inline void pcibios_set_master(struct pci_dev *dev) -{ - /* No special bus mastering setup handling */ -} - static inline void pcibios_penalize_isa_irq(int irq, int active) { /* We don't do dynamic PCI IRQ allocation */ diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 458ed3bee66..53e1f5e27b3 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1118,6 +1118,11 @@ void __devinit pcibios_setup_bus_devices(struct pci_bus *bus) } } +void pcibios_set_master(struct pci_dev *dev) +{ + /* No special bus mastering setup handling */ +} + void __devinit pcibios_fixup_bus(struct pci_bus *bus) { /* When called from the generic PCI probe, read PCI<->PCI bridge -- cgit v1.2.3 From a46770f5b97ec8d04292db797fbcad795b98cf03 Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 28 Oct 2011 16:27:33 -0600 Subject: powerpc/PCI: make pcibios_setup_phb_resources() static CC: Benjamin Herrenschmidt Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/powerpc/include/asm/pci-bridge.h | 1 - arch/powerpc/kernel/pci-common.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h index 56b879ab3a4..31bf836ad22 100644 --- a/arch/powerpc/include/asm/pci-bridge.h +++ b/arch/powerpc/include/asm/pci-bridge.h @@ -222,7 +222,6 @@ extern void pci_process_bridge_OF_ranges(struct pci_controller *hose, /* Allocate & free a PCI host bridge structure */ extern struct pci_controller *pcibios_alloc_controller(struct device_node *dev); extern void pcibios_free_controller(struct pci_controller *phb); -extern void pcibios_setup_phb_resources(struct pci_controller *hose); #ifdef CONFIG_PCI extern int pcibios_vaddr_is_ioport(void __iomem *address); diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 53e1f5e27b3..88953c8c7dd 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1560,7 +1560,7 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) +static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) { struct pci_bus *bus = hose->bus; struct resource *res; -- cgit v1.2.3 From 45a709f890a7b84930942a5f5f82011312fe727c Mon Sep 17 00:00:00 2001 From: Bjorn Helgaas Date: Fri, 28 Oct 2011 16:27:43 -0600 Subject: powerpc/PCI: convert to pci_create_root_bus() Convert from pci_create_bus() to pci_create_root_bus(). This way the root bus resources are correct immediately. This patch doesn't fix a problem because powerpc fixed the resources before scanning the bus, but it makes powerpc more consistent with other architectures. v2: fix build error with resource pointer passing CC: Benjamin Herrenschmidt Signed-off-by: Bjorn Helgaas Signed-off-by: Jesse Barnes --- arch/powerpc/kernel/pci-common.c | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) (limited to 'arch/powerpc/kernel/pci-common.c') diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 88953c8c7dd..0dbc5fb53c6 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c @@ -1560,14 +1560,13 @@ int pcibios_enable_device(struct pci_dev *dev, int mask) return pci_enable_resources(dev, mask); } -static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) +static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose, struct list_head *resources) { - struct pci_bus *bus = hose->bus; struct resource *res; int i; /* Hookup PHB IO resource */ - bus->resource[0] = res = &hose->io_resource; + res = &hose->io_resource; if (!res->flags) { printk(KERN_WARNING "PCI: I/O resource not set for host" @@ -1585,6 +1584,7 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) (unsigned long long)res->start, (unsigned long long)res->end, (unsigned long)res->flags); + pci_add_resource(resources, res); /* Hookup PHB Memory resources */ for (i = 0; i < 3; ++i) { @@ -1602,12 +1602,12 @@ static void __devinit pcibios_setup_phb_resources(struct pci_controller *hose) res->flags = IORESOURCE_MEM; #endif /* CONFIG_PPC32 */ } - bus->resource[i+1] = res; pr_debug("PCI: PHB MEM resource %d = %016llx-%016llx [%lx]\n", i, (unsigned long long)res->start, (unsigned long long)res->end, (unsigned long)res->flags); + pci_add_resource(resources, res); } pr_debug("PCI: PHB MEM offset = %016llx\n", @@ -1701,6 +1701,7 @@ struct device_node *pcibios_get_phb_of_node(struct pci_bus *bus) */ void __devinit pcibios_scan_phb(struct pci_controller *hose) { + LIST_HEAD(resources); struct pci_bus *bus; struct device_node *node = hose->dn; int mode; @@ -1708,22 +1709,24 @@ void __devinit pcibios_scan_phb(struct pci_controller *hose) pr_debug("PCI: Scanning PHB %s\n", node ? node->full_name : ""); + /* Get some IO space for the new PHB */ + pcibios_setup_phb_io_space(hose); + + /* Wire up PHB bus resources */ + pcibios_setup_phb_resources(hose, &resources); + /* Create an empty bus for the toplevel */ - bus = pci_create_bus(hose->parent, hose->first_busno, hose->ops, hose); + bus = pci_create_root_bus(hose->parent, hose->first_busno, + hose->ops, hose, &resources); if (bus == NULL) { pr_err("Failed to create bus for PCI domain %04x\n", hose->global_number); + pci_free_resource_list(&resources); return; } bus->secondary = hose->first_busno; hose->bus = bus; - /* Get some IO space for the new PHB */ - pcibios_setup_phb_io_space(hose); - - /* Wire up PHB bus resources */ - pcibios_setup_phb_resources(hose); - /* Get probe mode and perform scan */ mode = PCI_PROBE_NORMAL; if (node && ppc_md.pci_probe_mode) -- cgit v1.2.3