* [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-15 12:57 ` Thomas Petazzoni
0 siblings, 0 replies; 43+ messages in thread
From: Thomas Petazzoni @ 2013-04-15 12:57 UTC (permalink / raw)
To: linux-arm-kernel
Michal, Ben,
Would you have some time to look at this patch and give your comments
and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
need your agreement to merge this code, and quite a bit of code pending
for 3.10 depends on this patch.
Rob, alternatively, could we imagine doing a different version of the
'of/pci: Provide support for parsing PCI DT ranges property' that
introduces the new API only, leaving the PowerPC and Microblaze rework
as follow-up efforts, so that all the PCIe drivers that depend on this
patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
driver that has been worked on since 4+ months does not get into 3.10
just because this patch cannot be merged.
Thanks!
Thomas
On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
> The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> property of a PCI host device, is found in both Microblaze and PowerPC
> architectures. These implementations are nearly identical. This patch
> moves this common code to a common place.
>
> Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> ---
> arch/microblaze/include/asm/pci-bridge.h | 5 +-
> arch/microblaze/pci/pci-common.c | 192 ----------------------------
> arch/powerpc/include/asm/pci-bridge.h | 5 +-
> arch/powerpc/kernel/pci-common.c | 192 ----------------------------
> drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
> include/linux/of_pci.h | 4 +
> 6 files changed, 206 insertions(+), 392 deletions(-)
>
> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> index cb5d397..5783cd6 100644
> --- a/arch/microblaze/include/asm/pci-bridge.h
> +++ b/arch/microblaze/include/asm/pci-bridge.h
> @@ -10,6 +10,7 @@
> #include <linux/pci.h>
> #include <linux/list.h>
> #include <linux/ioport.h>
> +#include <linux/of_pci.h>
>
> struct device_node;
>
> @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
> extern struct pci_controller *pci_find_hose_for_OF_device(
> struct device_node *node);
>
> -/* Fill up host controller resources from the OF node */
> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary);
> -
> /* 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);
> diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> index 9ea521e..2735ad9 100644
> --- a/arch/microblaze/pci/pci-common.c
> +++ b/arch/microblaze/pci/pci-common.c
> @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> *end = rsrc->end - offset;
> }
>
> -/**
> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> - * @hose: newly allocated pci_controller to be setup
> - * @dev: device node of the host bridge
> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> - *
> - * This function will parse the "ranges" property of a PCI host bridge device
> - * node and setup the resource mapping of a pci controller based on its
> - * content.
> - *
> - * Life would be boring if it wasn't for a few issues that we have to deal
> - * with here:
> - *
> - * - We can only cope with one IO space range and up to 3 Memory space
> - * ranges. However, some machines (thanks Apple !) tend to split their
> - * space into lots of small contiguous ranges. So we have to coalesce.
> - *
> - * - We can only cope with all memory ranges having the same offset
> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> - * are setup for a large 1:1 mapping along with a small "window" which
> - * maps PCI address 0 to some arbitrary high address of the CPU space in
> - * order to give access to the ISA memory hole.
> - * The way out of here that I've chosen for now is to always set the
> - * offset based on the first resource found, then override it if we
> - * have a different offset and the previous was set by an ISA hole.
> - *
> - * - Some busses have IO space not starting at 0, which causes trouble with
> - * the way we do our IO resource renumbering. The code somewhat deals with
> - * it for 64 bits but I would expect problems on 32 bits.
> - *
> - * - Some 32 bits platforms such as 4xx can have physical space larger than
> - * 32 bits so we need to use 64 bits values for the parsing
> - */
> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary)
> -{
> - const u32 *ranges;
> - int rlen;
> - int pna = of_n_addr_cells(dev);
> - int np = pna + 5;
> - int memno = 0, isa_hole = -1;
> - u32 pci_space;
> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> - unsigned long long isa_mb = 0;
> - struct resource *res;
> -
> - pr_info("PCI host bridge %s %s ranges:\n",
> - dev->full_name, primary ? "(primary)" : "");
> -
> - /* Get ranges property */
> - ranges = of_get_property(dev, "ranges", &rlen);
> - if (ranges == NULL)
> - return;
> -
> - /* Parse it */
> - pr_debug("Parsing ranges property...\n");
> - while ((rlen -= np * 4) >= 0) {
> - /* Read next ranges element */
> - pci_space = ranges[0];
> - pci_addr = of_read_number(ranges + 1, 2);
> - cpu_addr = of_translate_address(dev, ranges + 3);
> - size = of_read_number(ranges + pna + 3, 2);
> -
> - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> - pci_space, pci_addr);
> - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> - cpu_addr, size);
> -
> - ranges += np;
> -
> - /* If we failed translation or got a zero-sized region
> - * (some FW try to feed us with non sensical zero sized regions
> - * such as power3 which look like some kind of attempt
> - * at exposing the VGA memory hole)
> - */
> - if (cpu_addr == OF_BAD_ADDR || size == 0)
> - continue;
> -
> - /* Now consume following elements while they are contiguous */
> - for (; rlen >= np * sizeof(u32);
> - ranges += np, rlen -= np * 4) {
> - if (ranges[0] != pci_space)
> - break;
> - pci_next = of_read_number(ranges + 1, 2);
> - cpu_next = of_translate_address(dev, ranges + 3);
> - if (pci_next != pci_addr + size ||
> - cpu_next != cpu_addr + size)
> - break;
> - size += of_read_number(ranges + pna + 3, 2);
> - }
> -
> - /* Act based on address space type */
> - res = NULL;
> - switch ((pci_space >> 24) & 0x3) {
> - case 1: /* PCI IO space */
> - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr);
> -
> - /* We support only one IO range */
> - if (hose->pci_io_size) {
> - pr_info(" \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* On 32 bits, limit I/O space to 16MB */
> - if (size > 0x01000000)
> - size = 0x01000000;
> -
> - /* 32 bits needs to map IOs here */
> - hose->io_base_virt = ioremap(cpu_addr, size);
> -
> - /* Expect trouble if pci_addr is not 0 */
> - if (primary)
> - isa_io_base =
> - (unsigned long)hose->io_base_virt;
> - /* pci_io_size and io_base_phys always represent IO
> - * space starting at 0 so we factor in pci_addr
> - */
> - hose->pci_io_size = pci_addr + size;
> - hose->io_base_phys = cpu_addr - pci_addr;
> -
> - /* Build resource */
> - res = &hose->io_resource;
> - res->flags = IORESOURCE_IO;
> - res->start = pci_addr;
> - break;
> - case 2: /* PCI Memory space */
> - case 3: /* PCI 64 bits Memory space */
> - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr,
> - (pci_space & 0x40000000) ? "Prefetch" : "");
> -
> - /* We support only 3 memory ranges */
> - if (memno >= 3) {
> - pr_info(" \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* Handles ISA memory hole space here */
> - if (pci_addr == 0) {
> - isa_mb = cpu_addr;
> - isa_hole = memno;
> - if (primary || isa_mem_base == 0)
> - isa_mem_base = cpu_addr;
> - hose->isa_mem_phys = cpu_addr;
> - hose->isa_mem_size = size;
> - }
> -
> - /* We get the PCI/Mem offset from the first range or
> - * the, current one if the offset came from an ISA
> - * hole. If they don't match, bugger.
> - */
> - if (memno == 0 ||
> - (isa_hole >= 0 && pci_addr != 0 &&
> - hose->pci_mem_offset == isa_mb))
> - hose->pci_mem_offset = cpu_addr - pci_addr;
> - else if (pci_addr != 0 &&
> - hose->pci_mem_offset != cpu_addr - pci_addr) {
> - pr_info(" \\--> Skipped (offset mismatch) !\n");
> - continue;
> - }
> -
> - /* Build resource */
> - res = &hose->mem_resources[memno++];
> - res->flags = IORESOURCE_MEM;
> - if (pci_space & 0x40000000)
> - res->flags |= IORESOURCE_PREFETCH;
> - res->start = cpu_addr;
> - break;
> - }
> - if (res != NULL) {
> - res->name = dev->full_name;
> - res->end = res->start + size - 1;
> - res->parent = NULL;
> - res->sibling = NULL;
> - res->child = NULL;
> - }
> - }
> -
> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> - * the ISA hole offset, then we need to remove the ISA hole from
> - * the resource list for that brige
> - */
> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> - unsigned int next = isa_hole + 1;
> - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> - if (next < memno)
> - memmove(&hose->mem_resources[isa_hole],
> - &hose->mem_resources[next],
> - sizeof(struct resource) * (memno - next));
> - hose->mem_resources[--memno].flags = 0;
> - }
> -}
> -
> /* Decide whether to display the domain number in /proc */
> int pci_proc_domain(struct pci_bus *bus)
> {
> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> index 025a130..205bfba 100644
> --- a/arch/powerpc/include/asm/pci-bridge.h
> +++ b/arch/powerpc/include/asm/pci-bridge.h
> @@ -10,6 +10,7 @@
> #include <linux/pci.h>
> #include <linux/list.h>
> #include <linux/ioport.h>
> +#include <linux/of_pci.h>
> #include <asm-generic/pci-bridge.h>
>
> struct device_node;
> @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
> extern struct pci_controller *pci_find_hose_for_OF_device(
> struct device_node* node);
>
> -/* Fill up host controller resources from the OF node */
> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary);
> -
> /* 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);
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index fa12ae4..6edf396 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> *end = rsrc->end - offset;
> }
>
> -/**
> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> - * @hose: newly allocated pci_controller to be setup
> - * @dev: device node of the host bridge
> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> - *
> - * This function will parse the "ranges" property of a PCI host bridge device
> - * node and setup the resource mapping of a pci controller based on its
> - * content.
> - *
> - * Life would be boring if it wasn't for a few issues that we have to deal
> - * with here:
> - *
> - * - We can only cope with one IO space range and up to 3 Memory space
> - * ranges. However, some machines (thanks Apple !) tend to split their
> - * space into lots of small contiguous ranges. So we have to coalesce.
> - *
> - * - We can only cope with all memory ranges having the same offset
> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> - * are setup for a large 1:1 mapping along with a small "window" which
> - * maps PCI address 0 to some arbitrary high address of the CPU space in
> - * order to give access to the ISA memory hole.
> - * The way out of here that I've chosen for now is to always set the
> - * offset based on the first resource found, then override it if we
> - * have a different offset and the previous was set by an ISA hole.
> - *
> - * - Some busses have IO space not starting at 0, which causes trouble with
> - * the way we do our IO resource renumbering. The code somewhat deals with
> - * it for 64 bits but I would expect problems on 32 bits.
> - *
> - * - Some 32 bits platforms such as 4xx can have physical space larger than
> - * 32 bits so we need to use 64 bits values for the parsing
> - */
> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary)
> -{
> - const u32 *ranges;
> - int rlen;
> - int pna = of_n_addr_cells(dev);
> - int np = pna + 5;
> - int memno = 0, isa_hole = -1;
> - u32 pci_space;
> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> - unsigned long long isa_mb = 0;
> - struct resource *res;
> -
> - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
> - dev->full_name, primary ? "(primary)" : "");
> -
> - /* Get ranges property */
> - ranges = of_get_property(dev, "ranges", &rlen);
> - if (ranges == NULL)
> - return;
> -
> - /* Parse it */
> - while ((rlen -= np * 4) >= 0) {
> - /* Read next ranges element */
> - pci_space = ranges[0];
> - pci_addr = of_read_number(ranges + 1, 2);
> - cpu_addr = of_translate_address(dev, ranges + 3);
> - size = of_read_number(ranges + pna + 3, 2);
> - ranges += np;
> -
> - /* If we failed translation or got a zero-sized region
> - * (some FW try to feed us with non sensical zero sized regions
> - * such as power3 which look like some kind of attempt at exposing
> - * the VGA memory hole)
> - */
> - if (cpu_addr == OF_BAD_ADDR || size == 0)
> - continue;
> -
> - /* Now consume following elements while they are contiguous */
> - for (; rlen >= np * sizeof(u32);
> - ranges += np, rlen -= np * 4) {
> - if (ranges[0] != pci_space)
> - break;
> - pci_next = of_read_number(ranges + 1, 2);
> - cpu_next = of_translate_address(dev, ranges + 3);
> - if (pci_next != pci_addr + size ||
> - cpu_next != cpu_addr + size)
> - break;
> - size += of_read_number(ranges + pna + 3, 2);
> - }
> -
> - /* Act based on address space type */
> - res = NULL;
> - switch ((pci_space >> 24) & 0x3) {
> - case 1: /* PCI IO space */
> - printk(KERN_INFO
> - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr);
> -
> - /* We support only one IO range */
> - if (hose->pci_io_size) {
> - printk(KERN_INFO
> - " \\--> Skipped (too many) !\n");
> - continue;
> - }
> -#ifdef CONFIG_PPC32
> - /* On 32 bits, limit I/O space to 16MB */
> - if (size > 0x01000000)
> - size = 0x01000000;
> -
> - /* 32 bits needs to map IOs here */
> - hose->io_base_virt = ioremap(cpu_addr, size);
> -
> - /* Expect trouble if pci_addr is not 0 */
> - if (primary)
> - isa_io_base =
> - (unsigned long)hose->io_base_virt;
> -#endif /* CONFIG_PPC32 */
> - /* pci_io_size and io_base_phys always represent IO
> - * space starting at 0 so we factor in pci_addr
> - */
> - hose->pci_io_size = pci_addr + size;
> - hose->io_base_phys = cpu_addr - pci_addr;
> -
> - /* Build resource */
> - res = &hose->io_resource;
> - res->flags = IORESOURCE_IO;
> - res->start = pci_addr;
> - break;
> - case 2: /* PCI Memory space */
> - case 3: /* PCI 64 bits Memory space */
> - printk(KERN_INFO
> - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr,
> - (pci_space & 0x40000000) ? "Prefetch" : "");
> -
> - /* We support only 3 memory ranges */
> - if (memno >= 3) {
> - printk(KERN_INFO
> - " \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* Handles ISA memory hole space here */
> - if (pci_addr == 0) {
> - isa_mb = cpu_addr;
> - isa_hole = memno;
> - if (primary || isa_mem_base == 0)
> - isa_mem_base = cpu_addr;
> - hose->isa_mem_phys = cpu_addr;
> - hose->isa_mem_size = size;
> - }
> -
> - /* We get the PCI/Mem offset from the first range or
> - * the, current one if the offset came from an ISA
> - * hole. If they don't match, bugger.
> - */
> - if (memno == 0 ||
> - (isa_hole >= 0 && pci_addr != 0 &&
> - hose->pci_mem_offset == isa_mb))
> - hose->pci_mem_offset = cpu_addr - pci_addr;
> - else if (pci_addr != 0 &&
> - hose->pci_mem_offset != cpu_addr - pci_addr) {
> - printk(KERN_INFO
> - " \\--> Skipped (offset mismatch) !\n");
> - continue;
> - }
> -
> - /* Build resource */
> - res = &hose->mem_resources[memno++];
> - res->flags = IORESOURCE_MEM;
> - if (pci_space & 0x40000000)
> - res->flags |= IORESOURCE_PREFETCH;
> - res->start = cpu_addr;
> - break;
> - }
> - if (res != NULL) {
> - res->name = dev->full_name;
> - res->end = res->start + size - 1;
> - res->parent = NULL;
> - res->sibling = NULL;
> - res->child = NULL;
> - }
> - }
> -
> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> - * the ISA hole offset, then we need to remove the ISA hole from
> - * the resource list for that brige
> - */
> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> - unsigned int next = isa_hole + 1;
> - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
> - if (next < memno)
> - memmove(&hose->mem_resources[isa_hole],
> - &hose->mem_resources[next],
> - sizeof(struct resource) * (memno - next));
> - hose->mem_resources[--memno].flags = 0;
> - }
> -}
> -
> /* Decide whether to display the domain number in /proc */
> int pci_proc_domain(struct pci_bus *bus)
> {
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 13e37e2..1626172 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -4,6 +4,10 @@
> #include <linux/of_pci.h>
> #include <asm/prom.h>
>
> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> +#include <asm/pci-bridge.h>
> +#endif
> +
> static inline int __of_pci_pci_compare(struct device_node *node,
> unsigned int devfn)
> {
> @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> return NULL;
> }
> EXPORT_SYMBOL_GPL(of_pci_find_child_device);
> +
> +/**
> + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> + * @hose: newly allocated pci_controller to be setup
> + * @dev: device node of the host bridge
> + * @primary: set if primary bus (32 bits only, soon to be deprecated)
> + *
> + * This function will parse the "ranges" property of a PCI host bridge device
> + * node and setup the resource mapping of a pci controller based on its
> + * content.
> + *
> + * Life would be boring if it wasn't for a few issues that we have to deal
> + * with here:
> + *
> + * - We can only cope with one IO space range and up to 3 Memory space
> + * ranges. However, some machines (thanks Apple !) tend to split their
> + * space into lots of small contiguous ranges. So we have to coalesce.
> + *
> + * - We can only cope with all memory ranges having the same offset
> + * between CPU addresses and PCI addresses. Unfortunately, some bridges
> + * are setup for a large 1:1 mapping along with a small "window" which
> + * maps PCI address 0 to some arbitrary high address of the CPU space in
> + * order to give access to the ISA memory hole.
> + * The way out of here that I've chosen for now is to always set the
> + * offset based on the first resource found, then override it if we
> + * have a different offset and the previous was set by an ISA hole.
> + *
> + * - Some busses have IO space not starting at 0, which causes trouble with
> + * the way we do our IO resource renumbering. The code somewhat deals with
> + * it for 64 bits but I would expect problems on 32 bits.
> + *
> + * - Some 32 bits platforms such as 4xx can have physical space larger than
> + * 32 bits so we need to use 64 bits values for the parsing
> + */
> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> + struct device_node *dev, int primary)
> +{
> + const u32 *ranges;
> + int rlen;
> + int pna = of_n_addr_cells(dev);
> + int np = pna + 5;
> + int memno = 0, isa_hole = -1;
> + u32 pci_space;
> + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> + unsigned long long isa_mb = 0;
> + struct resource *res;
> +
> + pr_info("PCI host bridge %s %s ranges:\n",
> + dev->full_name, primary ? "(primary)" : "");
> +
> + /* Get ranges property */
> + ranges = of_get_property(dev, "ranges", &rlen);
> + if (ranges == NULL)
> + return;
> +
> + /* Parse it */
> + pr_debug("Parsing ranges property...\n");
> + while ((rlen -= np * 4) >= 0) {
> + /* Read next ranges element */
> + pci_space = ranges[0];
> + pci_addr = of_read_number(ranges + 1, 2);
> + cpu_addr = of_translate_address(dev, ranges + 3);
> + size = of_read_number(ranges + pna + 3, 2);
> +
> + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> + pci_space, pci_addr);
> + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> + cpu_addr, size);
> +
> + ranges += np;
> +
> + /* If we failed translation or got a zero-sized region
> + * (some FW try to feed us with non sensical zero sized regions
> + * such as power3 which look like some kind of attempt
> + * at exposing the VGA memory hole)
> + */
> + if (cpu_addr == OF_BAD_ADDR || size == 0)
> + continue;
> +
> + /* Now consume following elements while they are contiguous */
> + for (; rlen >= np * sizeof(u32);
> + ranges += np, rlen -= np * 4) {
> + if (ranges[0] != pci_space)
> + break;
> + pci_next = of_read_number(ranges + 1, 2);
> + cpu_next = of_translate_address(dev, ranges + 3);
> + if (pci_next != pci_addr + size ||
> + cpu_next != cpu_addr + size)
> + break;
> + size += of_read_number(ranges + pna + 3, 2);
> + }
> +
> + /* Act based on address space type */
> + res = NULL;
> + switch ((pci_space >> 24) & 0x3) {
> + case 1: /* PCI IO space */
> + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> + cpu_addr, cpu_addr + size - 1, pci_addr);
> +
> + /* We support only one IO range */
> + if (hose->pci_io_size) {
> + pr_info(" \\--> Skipped (too many) !\n");
> + continue;
> + }
> +#if (!IS_ENABLED(CONFIG_64BIT))
> + /* On 32 bits, limit I/O space to 16MB */
> + if (size > 0x01000000)
> + size = 0x01000000;
> +
> + /* 32 bits needs to map IOs here */
> + hose->io_base_virt = ioremap(cpu_addr, size);
> +
> + /* Expect trouble if pci_addr is not 0 */
> + if (primary)
> + isa_io_base =
> + (unsigned long)hose->io_base_virt;
> +#endif /* !CONFIG_64BIT */
> + /* pci_io_size and io_base_phys always represent IO
> + * space starting at 0 so we factor in pci_addr
> + */
> + hose->pci_io_size = pci_addr + size;
> + hose->io_base_phys = cpu_addr - pci_addr;
> +
> + /* Build resource */
> + res = &hose->io_resource;
> + res->flags = IORESOURCE_IO;
> + res->start = pci_addr;
> + break;
> + case 2: /* PCI Memory space */
> + case 3: /* PCI 64 bits Memory space */
> + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> + cpu_addr, cpu_addr + size - 1, pci_addr,
> + (pci_space & 0x40000000) ? "Prefetch" : "");
> +
> + /* We support only 3 memory ranges */
> + if (memno >= 3) {
> + pr_info(" \\--> Skipped (too many) !\n");
> + continue;
> + }
> + /* Handles ISA memory hole space here */
> + if (pci_addr == 0) {
> + isa_mb = cpu_addr;
> + isa_hole = memno;
> + if (primary || isa_mem_base == 0)
> + isa_mem_base = cpu_addr;
> + hose->isa_mem_phys = cpu_addr;
> + hose->isa_mem_size = size;
> + }
> +
> + /* We get the PCI/Mem offset from the first range or
> + * the, current one if the offset came from an ISA
> + * hole. If they don't match, bugger.
> + */
> + if (memno == 0 ||
> + (isa_hole >= 0 && pci_addr != 0 &&
> + hose->pci_mem_offset == isa_mb))
> + hose->pci_mem_offset = cpu_addr - pci_addr;
> + else if (pci_addr != 0 &&
> + hose->pci_mem_offset != cpu_addr - pci_addr) {
> + pr_info(" \\--> Skipped (offset mismatch) !\n");
> + continue;
> + }
> +
> + /* Build resource */
> + res = &hose->mem_resources[memno++];
> + res->flags = IORESOURCE_MEM;
> + if (pci_space & 0x40000000)
> + res->flags |= IORESOURCE_PREFETCH;
> + res->start = cpu_addr;
> + break;
> + }
> + if (res != NULL) {
> + res->name = dev->full_name;
> + res->end = res->start + size - 1;
> + res->parent = NULL;
> + res->sibling = NULL;
> + res->child = NULL;
> + }
> + }
> +
> + /* If there's an ISA hole and the pci_mem_offset is -not- matching
> + * the ISA hole offset, then we need to remove the ISA hole from
> + * the resource list for that brige
> + */
> + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> + unsigned int next = isa_hole + 1;
> + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> + if (next < memno)
> + memmove(&hose->mem_resources[isa_hole],
> + &hose->mem_resources[next],
> + sizeof(struct resource) * (memno - next));
> + hose->mem_resources[--memno].flags = 0;
> + }
> +}
> +#endif
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index bb115de..33e8ead 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -11,4 +11,8 @@ struct device_node;
> struct device_node *of_pci_find_child_device(struct device_node *parent,
> unsigned int devfn);
>
> +struct pci_controller;
> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> + struct device_node *dev, int primary);
> +
> #endif
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-15 12:57 ` Thomas Petazzoni
0 siblings, 0 replies; 43+ messages in thread
From: Thomas Petazzoni @ 2013-04-15 12:57 UTC (permalink / raw)
To: monstr-pSz03upnqPeHXe+LvDLADg,
benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r
Cc: linux-samsung-soc-u79uwXL29TY76Z2rM5mHXA,
linux-lFZ/pmaqli7XmaaqVzeoHQ, siva.kallam-Sze3O3UU22JBDgjK7y7TUQ,
linux-pci-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
jg1.han-Sze3O3UU22JBDgjK7y7TUQ, Liviu.Dudau-5wv7dgnIgG8,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
rob.herring-bsGFqQB8/DxBDgjK7y7TUQ,
jgunthorpe-ePGOBjL8dl3ta4EC/59zMFaTQe2KTcn/,
kgene.kim-Sze3O3UU22JBDgjK7y7TUQ, paulus-eUNUBHrolfbYtjvyW6yDsg,
bhelgaas-hpIqsD4AKlfQT0dZR+AlfA, Andrew Murray,
suren.reddy-Sze3O3UU22JBDgjK7y7TUQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r
Michal, Ben,
Would you have some time to look at this patch and give your comments
and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
need your agreement to merge this code, and quite a bit of code pending
for 3.10 depends on this patch.
Rob, alternatively, could we imagine doing a different version of the
'of/pci: Provide support for parsing PCI DT ranges property' that
introduces the new API only, leaving the PowerPC and Microblaze rework
as follow-up efforts, so that all the PCIe drivers that depend on this
patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
driver that has been worked on since 4+ months does not get into 3.10
just because this patch cannot be merged.
Thanks!
Thomas
On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
> The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> property of a PCI host device, is found in both Microblaze and PowerPC
> architectures. These implementations are nearly identical. This patch
> moves this common code to a common place.
>
> Signed-off-by: Andrew Murray <Andrew.Murray-5wv7dgnIgG8@public.gmane.org>
> Signed-off-by: Liviu Dudau <Liviu.Dudau-5wv7dgnIgG8@public.gmane.org>
> Reviewed-by: Rob Herring <rob.herring-bsGFqQB8/DxBDgjK7y7TUQ@public.gmane.org>
> Tested-by: Thomas Petazzoni <thomas.petazzoni-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8@public.gmane.org>
> ---
> arch/microblaze/include/asm/pci-bridge.h | 5 +-
> arch/microblaze/pci/pci-common.c | 192 ----------------------------
> arch/powerpc/include/asm/pci-bridge.h | 5 +-
> arch/powerpc/kernel/pci-common.c | 192 ----------------------------
> drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
> include/linux/of_pci.h | 4 +
> 6 files changed, 206 insertions(+), 392 deletions(-)
>
> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> index cb5d397..5783cd6 100644
> --- a/arch/microblaze/include/asm/pci-bridge.h
> +++ b/arch/microblaze/include/asm/pci-bridge.h
> @@ -10,6 +10,7 @@
> #include <linux/pci.h>
> #include <linux/list.h>
> #include <linux/ioport.h>
> +#include <linux/of_pci.h>
>
> struct device_node;
>
> @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
> extern struct pci_controller *pci_find_hose_for_OF_device(
> struct device_node *node);
>
> -/* Fill up host controller resources from the OF node */
> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary);
> -
> /* 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);
> diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> index 9ea521e..2735ad9 100644
> --- a/arch/microblaze/pci/pci-common.c
> +++ b/arch/microblaze/pci/pci-common.c
> @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> *end = rsrc->end - offset;
> }
>
> -/**
> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> - * @hose: newly allocated pci_controller to be setup
> - * @dev: device node of the host bridge
> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> - *
> - * This function will parse the "ranges" property of a PCI host bridge device
> - * node and setup the resource mapping of a pci controller based on its
> - * content.
> - *
> - * Life would be boring if it wasn't for a few issues that we have to deal
> - * with here:
> - *
> - * - We can only cope with one IO space range and up to 3 Memory space
> - * ranges. However, some machines (thanks Apple !) tend to split their
> - * space into lots of small contiguous ranges. So we have to coalesce.
> - *
> - * - We can only cope with all memory ranges having the same offset
> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> - * are setup for a large 1:1 mapping along with a small "window" which
> - * maps PCI address 0 to some arbitrary high address of the CPU space in
> - * order to give access to the ISA memory hole.
> - * The way out of here that I've chosen for now is to always set the
> - * offset based on the first resource found, then override it if we
> - * have a different offset and the previous was set by an ISA hole.
> - *
> - * - Some busses have IO space not starting at 0, which causes trouble with
> - * the way we do our IO resource renumbering. The code somewhat deals with
> - * it for 64 bits but I would expect problems on 32 bits.
> - *
> - * - Some 32 bits platforms such as 4xx can have physical space larger than
> - * 32 bits so we need to use 64 bits values for the parsing
> - */
> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary)
> -{
> - const u32 *ranges;
> - int rlen;
> - int pna = of_n_addr_cells(dev);
> - int np = pna + 5;
> - int memno = 0, isa_hole = -1;
> - u32 pci_space;
> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> - unsigned long long isa_mb = 0;
> - struct resource *res;
> -
> - pr_info("PCI host bridge %s %s ranges:\n",
> - dev->full_name, primary ? "(primary)" : "");
> -
> - /* Get ranges property */
> - ranges = of_get_property(dev, "ranges", &rlen);
> - if (ranges == NULL)
> - return;
> -
> - /* Parse it */
> - pr_debug("Parsing ranges property...\n");
> - while ((rlen -= np * 4) >= 0) {
> - /* Read next ranges element */
> - pci_space = ranges[0];
> - pci_addr = of_read_number(ranges + 1, 2);
> - cpu_addr = of_translate_address(dev, ranges + 3);
> - size = of_read_number(ranges + pna + 3, 2);
> -
> - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> - pci_space, pci_addr);
> - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> - cpu_addr, size);
> -
> - ranges += np;
> -
> - /* If we failed translation or got a zero-sized region
> - * (some FW try to feed us with non sensical zero sized regions
> - * such as power3 which look like some kind of attempt
> - * at exposing the VGA memory hole)
> - */
> - if (cpu_addr == OF_BAD_ADDR || size == 0)
> - continue;
> -
> - /* Now consume following elements while they are contiguous */
> - for (; rlen >= np * sizeof(u32);
> - ranges += np, rlen -= np * 4) {
> - if (ranges[0] != pci_space)
> - break;
> - pci_next = of_read_number(ranges + 1, 2);
> - cpu_next = of_translate_address(dev, ranges + 3);
> - if (pci_next != pci_addr + size ||
> - cpu_next != cpu_addr + size)
> - break;
> - size += of_read_number(ranges + pna + 3, 2);
> - }
> -
> - /* Act based on address space type */
> - res = NULL;
> - switch ((pci_space >> 24) & 0x3) {
> - case 1: /* PCI IO space */
> - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr);
> -
> - /* We support only one IO range */
> - if (hose->pci_io_size) {
> - pr_info(" \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* On 32 bits, limit I/O space to 16MB */
> - if (size > 0x01000000)
> - size = 0x01000000;
> -
> - /* 32 bits needs to map IOs here */
> - hose->io_base_virt = ioremap(cpu_addr, size);
> -
> - /* Expect trouble if pci_addr is not 0 */
> - if (primary)
> - isa_io_base =
> - (unsigned long)hose->io_base_virt;
> - /* pci_io_size and io_base_phys always represent IO
> - * space starting at 0 so we factor in pci_addr
> - */
> - hose->pci_io_size = pci_addr + size;
> - hose->io_base_phys = cpu_addr - pci_addr;
> -
> - /* Build resource */
> - res = &hose->io_resource;
> - res->flags = IORESOURCE_IO;
> - res->start = pci_addr;
> - break;
> - case 2: /* PCI Memory space */
> - case 3: /* PCI 64 bits Memory space */
> - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr,
> - (pci_space & 0x40000000) ? "Prefetch" : "");
> -
> - /* We support only 3 memory ranges */
> - if (memno >= 3) {
> - pr_info(" \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* Handles ISA memory hole space here */
> - if (pci_addr == 0) {
> - isa_mb = cpu_addr;
> - isa_hole = memno;
> - if (primary || isa_mem_base == 0)
> - isa_mem_base = cpu_addr;
> - hose->isa_mem_phys = cpu_addr;
> - hose->isa_mem_size = size;
> - }
> -
> - /* We get the PCI/Mem offset from the first range or
> - * the, current one if the offset came from an ISA
> - * hole. If they don't match, bugger.
> - */
> - if (memno == 0 ||
> - (isa_hole >= 0 && pci_addr != 0 &&
> - hose->pci_mem_offset == isa_mb))
> - hose->pci_mem_offset = cpu_addr - pci_addr;
> - else if (pci_addr != 0 &&
> - hose->pci_mem_offset != cpu_addr - pci_addr) {
> - pr_info(" \\--> Skipped (offset mismatch) !\n");
> - continue;
> - }
> -
> - /* Build resource */
> - res = &hose->mem_resources[memno++];
> - res->flags = IORESOURCE_MEM;
> - if (pci_space & 0x40000000)
> - res->flags |= IORESOURCE_PREFETCH;
> - res->start = cpu_addr;
> - break;
> - }
> - if (res != NULL) {
> - res->name = dev->full_name;
> - res->end = res->start + size - 1;
> - res->parent = NULL;
> - res->sibling = NULL;
> - res->child = NULL;
> - }
> - }
> -
> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> - * the ISA hole offset, then we need to remove the ISA hole from
> - * the resource list for that brige
> - */
> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> - unsigned int next = isa_hole + 1;
> - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> - if (next < memno)
> - memmove(&hose->mem_resources[isa_hole],
> - &hose->mem_resources[next],
> - sizeof(struct resource) * (memno - next));
> - hose->mem_resources[--memno].flags = 0;
> - }
> -}
> -
> /* Decide whether to display the domain number in /proc */
> int pci_proc_domain(struct pci_bus *bus)
> {
> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> index 025a130..205bfba 100644
> --- a/arch/powerpc/include/asm/pci-bridge.h
> +++ b/arch/powerpc/include/asm/pci-bridge.h
> @@ -10,6 +10,7 @@
> #include <linux/pci.h>
> #include <linux/list.h>
> #include <linux/ioport.h>
> +#include <linux/of_pci.h>
> #include <asm-generic/pci-bridge.h>
>
> struct device_node;
> @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
> extern struct pci_controller *pci_find_hose_for_OF_device(
> struct device_node* node);
>
> -/* Fill up host controller resources from the OF node */
> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary);
> -
> /* 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);
> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> index fa12ae4..6edf396 100644
> --- a/arch/powerpc/kernel/pci-common.c
> +++ b/arch/powerpc/kernel/pci-common.c
> @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> *end = rsrc->end - offset;
> }
>
> -/**
> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> - * @hose: newly allocated pci_controller to be setup
> - * @dev: device node of the host bridge
> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> - *
> - * This function will parse the "ranges" property of a PCI host bridge device
> - * node and setup the resource mapping of a pci controller based on its
> - * content.
> - *
> - * Life would be boring if it wasn't for a few issues that we have to deal
> - * with here:
> - *
> - * - We can only cope with one IO space range and up to 3 Memory space
> - * ranges. However, some machines (thanks Apple !) tend to split their
> - * space into lots of small contiguous ranges. So we have to coalesce.
> - *
> - * - We can only cope with all memory ranges having the same offset
> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> - * are setup for a large 1:1 mapping along with a small "window" which
> - * maps PCI address 0 to some arbitrary high address of the CPU space in
> - * order to give access to the ISA memory hole.
> - * The way out of here that I've chosen for now is to always set the
> - * offset based on the first resource found, then override it if we
> - * have a different offset and the previous was set by an ISA hole.
> - *
> - * - Some busses have IO space not starting at 0, which causes trouble with
> - * the way we do our IO resource renumbering. The code somewhat deals with
> - * it for 64 bits but I would expect problems on 32 bits.
> - *
> - * - Some 32 bits platforms such as 4xx can have physical space larger than
> - * 32 bits so we need to use 64 bits values for the parsing
> - */
> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> - struct device_node *dev, int primary)
> -{
> - const u32 *ranges;
> - int rlen;
> - int pna = of_n_addr_cells(dev);
> - int np = pna + 5;
> - int memno = 0, isa_hole = -1;
> - u32 pci_space;
> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> - unsigned long long isa_mb = 0;
> - struct resource *res;
> -
> - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
> - dev->full_name, primary ? "(primary)" : "");
> -
> - /* Get ranges property */
> - ranges = of_get_property(dev, "ranges", &rlen);
> - if (ranges == NULL)
> - return;
> -
> - /* Parse it */
> - while ((rlen -= np * 4) >= 0) {
> - /* Read next ranges element */
> - pci_space = ranges[0];
> - pci_addr = of_read_number(ranges + 1, 2);
> - cpu_addr = of_translate_address(dev, ranges + 3);
> - size = of_read_number(ranges + pna + 3, 2);
> - ranges += np;
> -
> - /* If we failed translation or got a zero-sized region
> - * (some FW try to feed us with non sensical zero sized regions
> - * such as power3 which look like some kind of attempt at exposing
> - * the VGA memory hole)
> - */
> - if (cpu_addr == OF_BAD_ADDR || size == 0)
> - continue;
> -
> - /* Now consume following elements while they are contiguous */
> - for (; rlen >= np * sizeof(u32);
> - ranges += np, rlen -= np * 4) {
> - if (ranges[0] != pci_space)
> - break;
> - pci_next = of_read_number(ranges + 1, 2);
> - cpu_next = of_translate_address(dev, ranges + 3);
> - if (pci_next != pci_addr + size ||
> - cpu_next != cpu_addr + size)
> - break;
> - size += of_read_number(ranges + pna + 3, 2);
> - }
> -
> - /* Act based on address space type */
> - res = NULL;
> - switch ((pci_space >> 24) & 0x3) {
> - case 1: /* PCI IO space */
> - printk(KERN_INFO
> - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr);
> -
> - /* We support only one IO range */
> - if (hose->pci_io_size) {
> - printk(KERN_INFO
> - " \\--> Skipped (too many) !\n");
> - continue;
> - }
> -#ifdef CONFIG_PPC32
> - /* On 32 bits, limit I/O space to 16MB */
> - if (size > 0x01000000)
> - size = 0x01000000;
> -
> - /* 32 bits needs to map IOs here */
> - hose->io_base_virt = ioremap(cpu_addr, size);
> -
> - /* Expect trouble if pci_addr is not 0 */
> - if (primary)
> - isa_io_base =
> - (unsigned long)hose->io_base_virt;
> -#endif /* CONFIG_PPC32 */
> - /* pci_io_size and io_base_phys always represent IO
> - * space starting at 0 so we factor in pci_addr
> - */
> - hose->pci_io_size = pci_addr + size;
> - hose->io_base_phys = cpu_addr - pci_addr;
> -
> - /* Build resource */
> - res = &hose->io_resource;
> - res->flags = IORESOURCE_IO;
> - res->start = pci_addr;
> - break;
> - case 2: /* PCI Memory space */
> - case 3: /* PCI 64 bits Memory space */
> - printk(KERN_INFO
> - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> - cpu_addr, cpu_addr + size - 1, pci_addr,
> - (pci_space & 0x40000000) ? "Prefetch" : "");
> -
> - /* We support only 3 memory ranges */
> - if (memno >= 3) {
> - printk(KERN_INFO
> - " \\--> Skipped (too many) !\n");
> - continue;
> - }
> - /* Handles ISA memory hole space here */
> - if (pci_addr == 0) {
> - isa_mb = cpu_addr;
> - isa_hole = memno;
> - if (primary || isa_mem_base == 0)
> - isa_mem_base = cpu_addr;
> - hose->isa_mem_phys = cpu_addr;
> - hose->isa_mem_size = size;
> - }
> -
> - /* We get the PCI/Mem offset from the first range or
> - * the, current one if the offset came from an ISA
> - * hole. If they don't match, bugger.
> - */
> - if (memno == 0 ||
> - (isa_hole >= 0 && pci_addr != 0 &&
> - hose->pci_mem_offset == isa_mb))
> - hose->pci_mem_offset = cpu_addr - pci_addr;
> - else if (pci_addr != 0 &&
> - hose->pci_mem_offset != cpu_addr - pci_addr) {
> - printk(KERN_INFO
> - " \\--> Skipped (offset mismatch) !\n");
> - continue;
> - }
> -
> - /* Build resource */
> - res = &hose->mem_resources[memno++];
> - res->flags = IORESOURCE_MEM;
> - if (pci_space & 0x40000000)
> - res->flags |= IORESOURCE_PREFETCH;
> - res->start = cpu_addr;
> - break;
> - }
> - if (res != NULL) {
> - res->name = dev->full_name;
> - res->end = res->start + size - 1;
> - res->parent = NULL;
> - res->sibling = NULL;
> - res->child = NULL;
> - }
> - }
> -
> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> - * the ISA hole offset, then we need to remove the ISA hole from
> - * the resource list for that brige
> - */
> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> - unsigned int next = isa_hole + 1;
> - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
> - if (next < memno)
> - memmove(&hose->mem_resources[isa_hole],
> - &hose->mem_resources[next],
> - sizeof(struct resource) * (memno - next));
> - hose->mem_resources[--memno].flags = 0;
> - }
> -}
> -
> /* Decide whether to display the domain number in /proc */
> int pci_proc_domain(struct pci_bus *bus)
> {
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 13e37e2..1626172 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -4,6 +4,10 @@
> #include <linux/of_pci.h>
> #include <asm/prom.h>
>
> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> +#include <asm/pci-bridge.h>
> +#endif
> +
> static inline int __of_pci_pci_compare(struct device_node *node,
> unsigned int devfn)
> {
> @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> return NULL;
> }
> EXPORT_SYMBOL_GPL(of_pci_find_child_device);
> +
> +/**
> + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> + * @hose: newly allocated pci_controller to be setup
> + * @dev: device node of the host bridge
> + * @primary: set if primary bus (32 bits only, soon to be deprecated)
> + *
> + * This function will parse the "ranges" property of a PCI host bridge device
> + * node and setup the resource mapping of a pci controller based on its
> + * content.
> + *
> + * Life would be boring if it wasn't for a few issues that we have to deal
> + * with here:
> + *
> + * - We can only cope with one IO space range and up to 3 Memory space
> + * ranges. However, some machines (thanks Apple !) tend to split their
> + * space into lots of small contiguous ranges. So we have to coalesce.
> + *
> + * - We can only cope with all memory ranges having the same offset
> + * between CPU addresses and PCI addresses. Unfortunately, some bridges
> + * are setup for a large 1:1 mapping along with a small "window" which
> + * maps PCI address 0 to some arbitrary high address of the CPU space in
> + * order to give access to the ISA memory hole.
> + * The way out of here that I've chosen for now is to always set the
> + * offset based on the first resource found, then override it if we
> + * have a different offset and the previous was set by an ISA hole.
> + *
> + * - Some busses have IO space not starting at 0, which causes trouble with
> + * the way we do our IO resource renumbering. The code somewhat deals with
> + * it for 64 bits but I would expect problems on 32 bits.
> + *
> + * - Some 32 bits platforms such as 4xx can have physical space larger than
> + * 32 bits so we need to use 64 bits values for the parsing
> + */
> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> + struct device_node *dev, int primary)
> +{
> + const u32 *ranges;
> + int rlen;
> + int pna = of_n_addr_cells(dev);
> + int np = pna + 5;
> + int memno = 0, isa_hole = -1;
> + u32 pci_space;
> + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> + unsigned long long isa_mb = 0;
> + struct resource *res;
> +
> + pr_info("PCI host bridge %s %s ranges:\n",
> + dev->full_name, primary ? "(primary)" : "");
> +
> + /* Get ranges property */
> + ranges = of_get_property(dev, "ranges", &rlen);
> + if (ranges == NULL)
> + return;
> +
> + /* Parse it */
> + pr_debug("Parsing ranges property...\n");
> + while ((rlen -= np * 4) >= 0) {
> + /* Read next ranges element */
> + pci_space = ranges[0];
> + pci_addr = of_read_number(ranges + 1, 2);
> + cpu_addr = of_translate_address(dev, ranges + 3);
> + size = of_read_number(ranges + pna + 3, 2);
> +
> + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> + pci_space, pci_addr);
> + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> + cpu_addr, size);
> +
> + ranges += np;
> +
> + /* If we failed translation or got a zero-sized region
> + * (some FW try to feed us with non sensical zero sized regions
> + * such as power3 which look like some kind of attempt
> + * at exposing the VGA memory hole)
> + */
> + if (cpu_addr == OF_BAD_ADDR || size == 0)
> + continue;
> +
> + /* Now consume following elements while they are contiguous */
> + for (; rlen >= np * sizeof(u32);
> + ranges += np, rlen -= np * 4) {
> + if (ranges[0] != pci_space)
> + break;
> + pci_next = of_read_number(ranges + 1, 2);
> + cpu_next = of_translate_address(dev, ranges + 3);
> + if (pci_next != pci_addr + size ||
> + cpu_next != cpu_addr + size)
> + break;
> + size += of_read_number(ranges + pna + 3, 2);
> + }
> +
> + /* Act based on address space type */
> + res = NULL;
> + switch ((pci_space >> 24) & 0x3) {
> + case 1: /* PCI IO space */
> + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> + cpu_addr, cpu_addr + size - 1, pci_addr);
> +
> + /* We support only one IO range */
> + if (hose->pci_io_size) {
> + pr_info(" \\--> Skipped (too many) !\n");
> + continue;
> + }
> +#if (!IS_ENABLED(CONFIG_64BIT))
> + /* On 32 bits, limit I/O space to 16MB */
> + if (size > 0x01000000)
> + size = 0x01000000;
> +
> + /* 32 bits needs to map IOs here */
> + hose->io_base_virt = ioremap(cpu_addr, size);
> +
> + /* Expect trouble if pci_addr is not 0 */
> + if (primary)
> + isa_io_base =
> + (unsigned long)hose->io_base_virt;
> +#endif /* !CONFIG_64BIT */
> + /* pci_io_size and io_base_phys always represent IO
> + * space starting at 0 so we factor in pci_addr
> + */
> + hose->pci_io_size = pci_addr + size;
> + hose->io_base_phys = cpu_addr - pci_addr;
> +
> + /* Build resource */
> + res = &hose->io_resource;
> + res->flags = IORESOURCE_IO;
> + res->start = pci_addr;
> + break;
> + case 2: /* PCI Memory space */
> + case 3: /* PCI 64 bits Memory space */
> + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> + cpu_addr, cpu_addr + size - 1, pci_addr,
> + (pci_space & 0x40000000) ? "Prefetch" : "");
> +
> + /* We support only 3 memory ranges */
> + if (memno >= 3) {
> + pr_info(" \\--> Skipped (too many) !\n");
> + continue;
> + }
> + /* Handles ISA memory hole space here */
> + if (pci_addr == 0) {
> + isa_mb = cpu_addr;
> + isa_hole = memno;
> + if (primary || isa_mem_base == 0)
> + isa_mem_base = cpu_addr;
> + hose->isa_mem_phys = cpu_addr;
> + hose->isa_mem_size = size;
> + }
> +
> + /* We get the PCI/Mem offset from the first range or
> + * the, current one if the offset came from an ISA
> + * hole. If they don't match, bugger.
> + */
> + if (memno == 0 ||
> + (isa_hole >= 0 && pci_addr != 0 &&
> + hose->pci_mem_offset == isa_mb))
> + hose->pci_mem_offset = cpu_addr - pci_addr;
> + else if (pci_addr != 0 &&
> + hose->pci_mem_offset != cpu_addr - pci_addr) {
> + pr_info(" \\--> Skipped (offset mismatch) !\n");
> + continue;
> + }
> +
> + /* Build resource */
> + res = &hose->mem_resources[memno++];
> + res->flags = IORESOURCE_MEM;
> + if (pci_space & 0x40000000)
> + res->flags |= IORESOURCE_PREFETCH;
> + res->start = cpu_addr;
> + break;
> + }
> + if (res != NULL) {
> + res->name = dev->full_name;
> + res->end = res->start + size - 1;
> + res->parent = NULL;
> + res->sibling = NULL;
> + res->child = NULL;
> + }
> + }
> +
> + /* If there's an ISA hole and the pci_mem_offset is -not- matching
> + * the ISA hole offset, then we need to remove the ISA hole from
> + * the resource list for that brige
> + */
> + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> + unsigned int next = isa_hole + 1;
> + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> + if (next < memno)
> + memmove(&hose->mem_resources[isa_hole],
> + &hose->mem_resources[next],
> + sizeof(struct resource) * (memno - next));
> + hose->mem_resources[--memno].flags = 0;
> + }
> +}
> +#endif
> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> index bb115de..33e8ead 100644
> --- a/include/linux/of_pci.h
> +++ b/include/linux/of_pci.h
> @@ -11,4 +11,8 @@ struct device_node;
> struct device_node *of_pci_find_child_device(struct device_node *parent,
> unsigned int devfn);
>
> +struct pci_controller;
> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> + struct device_node *dev, int primary);
> +
> #endif
--
Thomas Petazzoni, Free Electrons
Kernel, drivers, real-time and embedded Linux
development, consulting, training and support.
http://free-electrons.com
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
2013-04-15 12:57 ` Thomas Petazzoni
(?)
@ 2013-04-15 15:32 ` Benjamin Herrenschmidt
-1 siblings, 0 replies; 43+ messages in thread
From: Benjamin Herrenschmidt @ 2013-04-15 15:32 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: monstr, Andrew Murray, rob.herring, jgunthorpe, linux,
siva.kallam, linux-pci, devicetree-discuss, jg1.han, Liviu.Dudau,
linux-kernel, linux-samsung-soc, kgene.kim, bhelgaas, suren.reddy,
linux-arm-kernel, paulus, grant.likely, thierry.reding,
thomas.abraham, arnd, linus.walleij
On Mon, 2013-04-15 at 14:57 +0200, Thomas Petazzoni wrote:
> Michal, Ben,
>
> Would you have some time to look at this patch and give your comments
> and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
> need your agreement to merge this code, and quite a bit of code pending
> for 3.10 depends on this patch.
I'm currently still on vacation. I will be able to look at this after
I'm back in about a week.
> Rob, alternatively, could we imagine doing a different version of the
> 'of/pci: Provide support for parsing PCI DT ranges property' that
> introduces the new API only, leaving the PowerPC and Microblaze rework
> as follow-up efforts, so that all the PCIe drivers that depend on this
> patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
> driver that has been worked on since 4+ months does not get into 3.10
> just because this patch cannot be merged.
Cheers,
Ben.
> Thanks!
>
> Thomas
>
> On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
> > The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> > property of a PCI host device, is found in both Microblaze and PowerPC
> > architectures. These implementations are nearly identical. This patch
> > moves this common code to a common place.
> >
> > Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> > Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> > ---
> > arch/microblaze/include/asm/pci-bridge.h | 5 +-
> > arch/microblaze/pci/pci-common.c | 192 ----------------------------
> > arch/powerpc/include/asm/pci-bridge.h | 5 +-
> > arch/powerpc/kernel/pci-common.c | 192 ----------------------------
> > drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
> > include/linux/of_pci.h | 4 +
> > 6 files changed, 206 insertions(+), 392 deletions(-)
> >
> > diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> > index cb5d397..5783cd6 100644
> > --- a/arch/microblaze/include/asm/pci-bridge.h
> > +++ b/arch/microblaze/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> >
> > struct device_node;
> >
> > @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node *node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> > index 9ea521e..2735ad9 100644
> > --- a/arch/microblaze/pci/pci-common.c
> > +++ b/arch/microblaze/pci/pci-common.c
> > @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - pr_info("PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - pr_debug("Parsing ranges property...\n");
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > -
> > - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > - pci_space, pci_addr);
> > - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > - cpu_addr, size);
> > -
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt
> > - * at exposing the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - pr_info(" \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> > index 025a130..205bfba 100644
> > --- a/arch/powerpc/include/asm/pci-bridge.h
> > +++ b/arch/powerpc/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> > #include <asm-generic/pci-bridge.h>
> >
> > struct device_node;
> > @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node* node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> > index fa12ae4..6edf396 100644
> > --- a/arch/powerpc/kernel/pci-common.c
> > +++ b/arch/powerpc/kernel/pci-common.c
> > @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt at exposing
> > - * the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - printk(KERN_INFO
> > - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > -#ifdef CONFIG_PPC32
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > -#endif /* CONFIG_PPC32 */
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - printk(KERN_INFO
> > - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> > index 13e37e2..1626172 100644
> > --- a/drivers/of/of_pci.c
> > +++ b/drivers/of/of_pci.c
> > @@ -4,6 +4,10 @@
> > #include <linux/of_pci.h>
> > #include <asm/prom.h>
> >
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +#include <asm/pci-bridge.h>
> > +#endif
> > +
> > static inline int __of_pci_pci_compare(struct device_node *node,
> > unsigned int devfn)
> > {
> > @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> > return NULL;
> > }
> > EXPORT_SYMBOL_GPL(of_pci_find_child_device);
> > +
> > +/**
> > + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > + * @hose: newly allocated pci_controller to be setup
> > + * @dev: device node of the host bridge
> > + * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > + *
> > + * This function will parse the "ranges" property of a PCI host bridge device
> > + * node and setup the resource mapping of a pci controller based on its
> > + * content.
> > + *
> > + * Life would be boring if it wasn't for a few issues that we have to deal
> > + * with here:
> > + *
> > + * - We can only cope with one IO space range and up to 3 Memory space
> > + * ranges. However, some machines (thanks Apple !) tend to split their
> > + * space into lots of small contiguous ranges. So we have to coalesce.
> > + *
> > + * - We can only cope with all memory ranges having the same offset
> > + * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > + * are setup for a large 1:1 mapping along with a small "window" which
> > + * maps PCI address 0 to some arbitrary high address of the CPU space in
> > + * order to give access to the ISA memory hole.
> > + * The way out of here that I've chosen for now is to always set the
> > + * offset based on the first resource found, then override it if we
> > + * have a different offset and the previous was set by an ISA hole.
> > + *
> > + * - Some busses have IO space not starting at 0, which causes trouble with
> > + * the way we do our IO resource renumbering. The code somewhat deals with
> > + * it for 64 bits but I would expect problems on 32 bits.
> > + *
> > + * - Some 32 bits platforms such as 4xx can have physical space larger than
> > + * 32 bits so we need to use 64 bits values for the parsing
> > + */
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary)
> > +{
> > + const u32 *ranges;
> > + int rlen;
> > + int pna = of_n_addr_cells(dev);
> > + int np = pna + 5;
> > + int memno = 0, isa_hole = -1;
> > + u32 pci_space;
> > + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > + unsigned long long isa_mb = 0;
> > + struct resource *res;
> > +
> > + pr_info("PCI host bridge %s %s ranges:\n",
> > + dev->full_name, primary ? "(primary)" : "");
> > +
> > + /* Get ranges property */
> > + ranges = of_get_property(dev, "ranges", &rlen);
> > + if (ranges == NULL)
> > + return;
> > +
> > + /* Parse it */
> > + pr_debug("Parsing ranges property...\n");
> > + while ((rlen -= np * 4) >= 0) {
> > + /* Read next ranges element */
> > + pci_space = ranges[0];
> > + pci_addr = of_read_number(ranges + 1, 2);
> > + cpu_addr = of_translate_address(dev, ranges + 3);
> > + size = of_read_number(ranges + pna + 3, 2);
> > +
> > + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > + pci_space, pci_addr);
> > + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > + cpu_addr, size);
> > +
> > + ranges += np;
> > +
> > + /* If we failed translation or got a zero-sized region
> > + * (some FW try to feed us with non sensical zero sized regions
> > + * such as power3 which look like some kind of attempt
> > + * at exposing the VGA memory hole)
> > + */
> > + if (cpu_addr == OF_BAD_ADDR || size == 0)
> > + continue;
> > +
> > + /* Now consume following elements while they are contiguous */
> > + for (; rlen >= np * sizeof(u32);
> > + ranges += np, rlen -= np * 4) {
> > + if (ranges[0] != pci_space)
> > + break;
> > + pci_next = of_read_number(ranges + 1, 2);
> > + cpu_next = of_translate_address(dev, ranges + 3);
> > + if (pci_next != pci_addr + size ||
> > + cpu_next != cpu_addr + size)
> > + break;
> > + size += of_read_number(ranges + pna + 3, 2);
> > + }
> > +
> > + /* Act based on address space type */
> > + res = NULL;
> > + switch ((pci_space >> 24) & 0x3) {
> > + case 1: /* PCI IO space */
> > + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr);
> > +
> > + /* We support only one IO range */
> > + if (hose->pci_io_size) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > +#if (!IS_ENABLED(CONFIG_64BIT))
> > + /* On 32 bits, limit I/O space to 16MB */
> > + if (size > 0x01000000)
> > + size = 0x01000000;
> > +
> > + /* 32 bits needs to map IOs here */
> > + hose->io_base_virt = ioremap(cpu_addr, size);
> > +
> > + /* Expect trouble if pci_addr is not 0 */
> > + if (primary)
> > + isa_io_base =
> > + (unsigned long)hose->io_base_virt;
> > +#endif /* !CONFIG_64BIT */
> > + /* pci_io_size and io_base_phys always represent IO
> > + * space starting at 0 so we factor in pci_addr
> > + */
> > + hose->pci_io_size = pci_addr + size;
> > + hose->io_base_phys = cpu_addr - pci_addr;
> > +
> > + /* Build resource */
> > + res = &hose->io_resource;
> > + res->flags = IORESOURCE_IO;
> > + res->start = pci_addr;
> > + break;
> > + case 2: /* PCI Memory space */
> > + case 3: /* PCI 64 bits Memory space */
> > + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr,
> > + (pci_space & 0x40000000) ? "Prefetch" : "");
> > +
> > + /* We support only 3 memory ranges */
> > + if (memno >= 3) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > + /* Handles ISA memory hole space here */
> > + if (pci_addr == 0) {
> > + isa_mb = cpu_addr;
> > + isa_hole = memno;
> > + if (primary || isa_mem_base == 0)
> > + isa_mem_base = cpu_addr;
> > + hose->isa_mem_phys = cpu_addr;
> > + hose->isa_mem_size = size;
> > + }
> > +
> > + /* We get the PCI/Mem offset from the first range or
> > + * the, current one if the offset came from an ISA
> > + * hole. If they don't match, bugger.
> > + */
> > + if (memno == 0 ||
> > + (isa_hole >= 0 && pci_addr != 0 &&
> > + hose->pci_mem_offset == isa_mb))
> > + hose->pci_mem_offset = cpu_addr - pci_addr;
> > + else if (pci_addr != 0 &&
> > + hose->pci_mem_offset != cpu_addr - pci_addr) {
> > + pr_info(" \\--> Skipped (offset mismatch) !\n");
> > + continue;
> > + }
> > +
> > + /* Build resource */
> > + res = &hose->mem_resources[memno++];
> > + res->flags = IORESOURCE_MEM;
> > + if (pci_space & 0x40000000)
> > + res->flags |= IORESOURCE_PREFETCH;
> > + res->start = cpu_addr;
> > + break;
> > + }
> > + if (res != NULL) {
> > + res->name = dev->full_name;
> > + res->end = res->start + size - 1;
> > + res->parent = NULL;
> > + res->sibling = NULL;
> > + res->child = NULL;
> > + }
> > + }
> > +
> > + /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > + * the ISA hole offset, then we need to remove the ISA hole from
> > + * the resource list for that brige
> > + */
> > + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > + unsigned int next = isa_hole + 1;
> > + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > + if (next < memno)
> > + memmove(&hose->mem_resources[isa_hole],
> > + &hose->mem_resources[next],
> > + sizeof(struct resource) * (memno - next));
> > + hose->mem_resources[--memno].flags = 0;
> > + }
> > +}
> > +#endif
> > diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> > index bb115de..33e8ead 100644
> > --- a/include/linux/of_pci.h
> > +++ b/include/linux/of_pci.h
> > @@ -11,4 +11,8 @@ struct device_node;
> > struct device_node *of_pci_find_child_device(struct device_node *parent,
> > unsigned int devfn);
> >
> > +struct pci_controller;
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary);
> > +
> > #endif
>
>
>
^ permalink raw reply [flat|nested] 43+ messages in thread* [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-15 15:32 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 43+ messages in thread
From: Benjamin Herrenschmidt @ 2013-04-15 15:32 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, 2013-04-15 at 14:57 +0200, Thomas Petazzoni wrote:
> Michal, Ben,
>
> Would you have some time to look at this patch and give your comments
> and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
> need your agreement to merge this code, and quite a bit of code pending
> for 3.10 depends on this patch.
I'm currently still on vacation. I will be able to look at this after
I'm back in about a week.
> Rob, alternatively, could we imagine doing a different version of the
> 'of/pci: Provide support for parsing PCI DT ranges property' that
> introduces the new API only, leaving the PowerPC and Microblaze rework
> as follow-up efforts, so that all the PCIe drivers that depend on this
> patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
> driver that has been worked on since 4+ months does not get into 3.10
> just because this patch cannot be merged.
Cheers,
Ben.
> Thanks!
>
> Thomas
>
> On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
> > The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> > property of a PCI host device, is found in both Microblaze and PowerPC
> > architectures. These implementations are nearly identical. This patch
> > moves this common code to a common place.
> >
> > Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> > Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> > ---
> > arch/microblaze/include/asm/pci-bridge.h | 5 +-
> > arch/microblaze/pci/pci-common.c | 192 ----------------------------
> > arch/powerpc/include/asm/pci-bridge.h | 5 +-
> > arch/powerpc/kernel/pci-common.c | 192 ----------------------------
> > drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
> > include/linux/of_pci.h | 4 +
> > 6 files changed, 206 insertions(+), 392 deletions(-)
> >
> > diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> > index cb5d397..5783cd6 100644
> > --- a/arch/microblaze/include/asm/pci-bridge.h
> > +++ b/arch/microblaze/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> >
> > struct device_node;
> >
> > @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node *node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> > index 9ea521e..2735ad9 100644
> > --- a/arch/microblaze/pci/pci-common.c
> > +++ b/arch/microblaze/pci/pci-common.c
> > @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - pr_info("PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - pr_debug("Parsing ranges property...\n");
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > -
> > - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > - pci_space, pci_addr);
> > - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > - cpu_addr, size);
> > -
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt
> > - * at exposing the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - pr_info(" \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> > index 025a130..205bfba 100644
> > --- a/arch/powerpc/include/asm/pci-bridge.h
> > +++ b/arch/powerpc/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> > #include <asm-generic/pci-bridge.h>
> >
> > struct device_node;
> > @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node* node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> > index fa12ae4..6edf396 100644
> > --- a/arch/powerpc/kernel/pci-common.c
> > +++ b/arch/powerpc/kernel/pci-common.c
> > @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt at exposing
> > - * the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - printk(KERN_INFO
> > - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > -#ifdef CONFIG_PPC32
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > -#endif /* CONFIG_PPC32 */
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - printk(KERN_INFO
> > - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> > index 13e37e2..1626172 100644
> > --- a/drivers/of/of_pci.c
> > +++ b/drivers/of/of_pci.c
> > @@ -4,6 +4,10 @@
> > #include <linux/of_pci.h>
> > #include <asm/prom.h>
> >
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +#include <asm/pci-bridge.h>
> > +#endif
> > +
> > static inline int __of_pci_pci_compare(struct device_node *node,
> > unsigned int devfn)
> > {
> > @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> > return NULL;
> > }
> > EXPORT_SYMBOL_GPL(of_pci_find_child_device);
> > +
> > +/**
> > + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > + * @hose: newly allocated pci_controller to be setup
> > + * @dev: device node of the host bridge
> > + * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > + *
> > + * This function will parse the "ranges" property of a PCI host bridge device
> > + * node and setup the resource mapping of a pci controller based on its
> > + * content.
> > + *
> > + * Life would be boring if it wasn't for a few issues that we have to deal
> > + * with here:
> > + *
> > + * - We can only cope with one IO space range and up to 3 Memory space
> > + * ranges. However, some machines (thanks Apple !) tend to split their
> > + * space into lots of small contiguous ranges. So we have to coalesce.
> > + *
> > + * - We can only cope with all memory ranges having the same offset
> > + * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > + * are setup for a large 1:1 mapping along with a small "window" which
> > + * maps PCI address 0 to some arbitrary high address of the CPU space in
> > + * order to give access to the ISA memory hole.
> > + * The way out of here that I've chosen for now is to always set the
> > + * offset based on the first resource found, then override it if we
> > + * have a different offset and the previous was set by an ISA hole.
> > + *
> > + * - Some busses have IO space not starting at 0, which causes trouble with
> > + * the way we do our IO resource renumbering. The code somewhat deals with
> > + * it for 64 bits but I would expect problems on 32 bits.
> > + *
> > + * - Some 32 bits platforms such as 4xx can have physical space larger than
> > + * 32 bits so we need to use 64 bits values for the parsing
> > + */
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary)
> > +{
> > + const u32 *ranges;
> > + int rlen;
> > + int pna = of_n_addr_cells(dev);
> > + int np = pna + 5;
> > + int memno = 0, isa_hole = -1;
> > + u32 pci_space;
> > + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > + unsigned long long isa_mb = 0;
> > + struct resource *res;
> > +
> > + pr_info("PCI host bridge %s %s ranges:\n",
> > + dev->full_name, primary ? "(primary)" : "");
> > +
> > + /* Get ranges property */
> > + ranges = of_get_property(dev, "ranges", &rlen);
> > + if (ranges == NULL)
> > + return;
> > +
> > + /* Parse it */
> > + pr_debug("Parsing ranges property...\n");
> > + while ((rlen -= np * 4) >= 0) {
> > + /* Read next ranges element */
> > + pci_space = ranges[0];
> > + pci_addr = of_read_number(ranges + 1, 2);
> > + cpu_addr = of_translate_address(dev, ranges + 3);
> > + size = of_read_number(ranges + pna + 3, 2);
> > +
> > + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > + pci_space, pci_addr);
> > + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > + cpu_addr, size);
> > +
> > + ranges += np;
> > +
> > + /* If we failed translation or got a zero-sized region
> > + * (some FW try to feed us with non sensical zero sized regions
> > + * such as power3 which look like some kind of attempt
> > + * at exposing the VGA memory hole)
> > + */
> > + if (cpu_addr == OF_BAD_ADDR || size == 0)
> > + continue;
> > +
> > + /* Now consume following elements while they are contiguous */
> > + for (; rlen >= np * sizeof(u32);
> > + ranges += np, rlen -= np * 4) {
> > + if (ranges[0] != pci_space)
> > + break;
> > + pci_next = of_read_number(ranges + 1, 2);
> > + cpu_next = of_translate_address(dev, ranges + 3);
> > + if (pci_next != pci_addr + size ||
> > + cpu_next != cpu_addr + size)
> > + break;
> > + size += of_read_number(ranges + pna + 3, 2);
> > + }
> > +
> > + /* Act based on address space type */
> > + res = NULL;
> > + switch ((pci_space >> 24) & 0x3) {
> > + case 1: /* PCI IO space */
> > + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr);
> > +
> > + /* We support only one IO range */
> > + if (hose->pci_io_size) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > +#if (!IS_ENABLED(CONFIG_64BIT))
> > + /* On 32 bits, limit I/O space to 16MB */
> > + if (size > 0x01000000)
> > + size = 0x01000000;
> > +
> > + /* 32 bits needs to map IOs here */
> > + hose->io_base_virt = ioremap(cpu_addr, size);
> > +
> > + /* Expect trouble if pci_addr is not 0 */
> > + if (primary)
> > + isa_io_base =
> > + (unsigned long)hose->io_base_virt;
> > +#endif /* !CONFIG_64BIT */
> > + /* pci_io_size and io_base_phys always represent IO
> > + * space starting at 0 so we factor in pci_addr
> > + */
> > + hose->pci_io_size = pci_addr + size;
> > + hose->io_base_phys = cpu_addr - pci_addr;
> > +
> > + /* Build resource */
> > + res = &hose->io_resource;
> > + res->flags = IORESOURCE_IO;
> > + res->start = pci_addr;
> > + break;
> > + case 2: /* PCI Memory space */
> > + case 3: /* PCI 64 bits Memory space */
> > + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr,
> > + (pci_space & 0x40000000) ? "Prefetch" : "");
> > +
> > + /* We support only 3 memory ranges */
> > + if (memno >= 3) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > + /* Handles ISA memory hole space here */
> > + if (pci_addr == 0) {
> > + isa_mb = cpu_addr;
> > + isa_hole = memno;
> > + if (primary || isa_mem_base == 0)
> > + isa_mem_base = cpu_addr;
> > + hose->isa_mem_phys = cpu_addr;
> > + hose->isa_mem_size = size;
> > + }
> > +
> > + /* We get the PCI/Mem offset from the first range or
> > + * the, current one if the offset came from an ISA
> > + * hole. If they don't match, bugger.
> > + */
> > + if (memno == 0 ||
> > + (isa_hole >= 0 && pci_addr != 0 &&
> > + hose->pci_mem_offset == isa_mb))
> > + hose->pci_mem_offset = cpu_addr - pci_addr;
> > + else if (pci_addr != 0 &&
> > + hose->pci_mem_offset != cpu_addr - pci_addr) {
> > + pr_info(" \\--> Skipped (offset mismatch) !\n");
> > + continue;
> > + }
> > +
> > + /* Build resource */
> > + res = &hose->mem_resources[memno++];
> > + res->flags = IORESOURCE_MEM;
> > + if (pci_space & 0x40000000)
> > + res->flags |= IORESOURCE_PREFETCH;
> > + res->start = cpu_addr;
> > + break;
> > + }
> > + if (res != NULL) {
> > + res->name = dev->full_name;
> > + res->end = res->start + size - 1;
> > + res->parent = NULL;
> > + res->sibling = NULL;
> > + res->child = NULL;
> > + }
> > + }
> > +
> > + /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > + * the ISA hole offset, then we need to remove the ISA hole from
> > + * the resource list for that brige
> > + */
> > + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > + unsigned int next = isa_hole + 1;
> > + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > + if (next < memno)
> > + memmove(&hose->mem_resources[isa_hole],
> > + &hose->mem_resources[next],
> > + sizeof(struct resource) * (memno - next));
> > + hose->mem_resources[--memno].flags = 0;
> > + }
> > +}
> > +#endif
> > diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> > index bb115de..33e8ead 100644
> > --- a/include/linux/of_pci.h
> > +++ b/include/linux/of_pci.h
> > @@ -11,4 +11,8 @@ struct device_node;
> > struct device_node *of_pci_find_child_device(struct device_node *parent,
> > unsigned int devfn);
> >
> > +struct pci_controller;
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary);
> > +
> > #endif
>
>
>
^ permalink raw reply [flat|nested] 43+ messages in thread* Re: [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-15 15:32 ` Benjamin Herrenschmidt
0 siblings, 0 replies; 43+ messages in thread
From: Benjamin Herrenschmidt @ 2013-04-15 15:32 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: siva.kallam, linux-pci, linus.walleij, thierry.reding,
Liviu.Dudau, grant.likely, paulus, linux-samsung-soc, linux,
jg1.han, jgunthorpe, thomas.abraham, arnd, devicetree-discuss,
rob.herring, kgene.kim, bhelgaas, linux-arm-kernel, monstr,
linux-kernel, suren.reddy, Andrew Murray
On Mon, 2013-04-15 at 14:57 +0200, Thomas Petazzoni wrote:
> Michal, Ben,
>
> Would you have some time to look at this patch and give your comments
> and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
> need your agreement to merge this code, and quite a bit of code pending
> for 3.10 depends on this patch.
I'm currently still on vacation. I will be able to look at this after
I'm back in about a week.
> Rob, alternatively, could we imagine doing a different version of the
> 'of/pci: Provide support for parsing PCI DT ranges property' that
> introduces the new API only, leaving the PowerPC and Microblaze rework
> as follow-up efforts, so that all the PCIe drivers that depend on this
> patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
> driver that has been worked on since 4+ months does not get into 3.10
> just because this patch cannot be merged.
Cheers,
Ben.
> Thanks!
>
> Thomas
>
> On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
> > The pci_process_bridge_OF_ranges function, used to parse the "ranges"
> > property of a PCI host device, is found in both Microblaze and PowerPC
> > architectures. These implementations are nearly identical. This patch
> > moves this common code to a common place.
> >
> > Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
> > Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
> > Reviewed-by: Rob Herring <rob.herring@calxeda.com>
> > Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
> > ---
> > arch/microblaze/include/asm/pci-bridge.h | 5 +-
> > arch/microblaze/pci/pci-common.c | 192 ----------------------------
> > arch/powerpc/include/asm/pci-bridge.h | 5 +-
> > arch/powerpc/kernel/pci-common.c | 192 ----------------------------
> > drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
> > include/linux/of_pci.h | 4 +
> > 6 files changed, 206 insertions(+), 392 deletions(-)
> >
> > diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
> > index cb5d397..5783cd6 100644
> > --- a/arch/microblaze/include/asm/pci-bridge.h
> > +++ b/arch/microblaze/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> >
> > struct device_node;
> >
> > @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node *node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
> > index 9ea521e..2735ad9 100644
> > --- a/arch/microblaze/pci/pci-common.c
> > +++ b/arch/microblaze/pci/pci-common.c
> > @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - pr_info("PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - pr_debug("Parsing ranges property...\n");
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > -
> > - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > - pci_space, pci_addr);
> > - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > - cpu_addr, size);
> > -
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt
> > - * at exposing the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - pr_info(" \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - pr_info(" \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
> > index 025a130..205bfba 100644
> > --- a/arch/powerpc/include/asm/pci-bridge.h
> > +++ b/arch/powerpc/include/asm/pci-bridge.h
> > @@ -10,6 +10,7 @@
> > #include <linux/pci.h>
> > #include <linux/list.h>
> > #include <linux/ioport.h>
> > +#include <linux/of_pci.h>
> > #include <asm-generic/pci-bridge.h>
> >
> > struct device_node;
> > @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
> > extern struct pci_controller *pci_find_hose_for_OF_device(
> > struct device_node* node);
> >
> > -/* Fill up host controller resources from the OF node */
> > -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary);
> > -
> > /* 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);
> > diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
> > index fa12ae4..6edf396 100644
> > --- a/arch/powerpc/kernel/pci-common.c
> > +++ b/arch/powerpc/kernel/pci-common.c
> > @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
> > *end = rsrc->end - offset;
> > }
> >
> > -/**
> > - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > - * @hose: newly allocated pci_controller to be setup
> > - * @dev: device node of the host bridge
> > - * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > - *
> > - * This function will parse the "ranges" property of a PCI host bridge device
> > - * node and setup the resource mapping of a pci controller based on its
> > - * content.
> > - *
> > - * Life would be boring if it wasn't for a few issues that we have to deal
> > - * with here:
> > - *
> > - * - We can only cope with one IO space range and up to 3 Memory space
> > - * ranges. However, some machines (thanks Apple !) tend to split their
> > - * space into lots of small contiguous ranges. So we have to coalesce.
> > - *
> > - * - We can only cope with all memory ranges having the same offset
> > - * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > - * are setup for a large 1:1 mapping along with a small "window" which
> > - * maps PCI address 0 to some arbitrary high address of the CPU space in
> > - * order to give access to the ISA memory hole.
> > - * The way out of here that I've chosen for now is to always set the
> > - * offset based on the first resource found, then override it if we
> > - * have a different offset and the previous was set by an ISA hole.
> > - *
> > - * - Some busses have IO space not starting at 0, which causes trouble with
> > - * the way we do our IO resource renumbering. The code somewhat deals with
> > - * it for 64 bits but I would expect problems on 32 bits.
> > - *
> > - * - Some 32 bits platforms such as 4xx can have physical space larger than
> > - * 32 bits so we need to use 64 bits values for the parsing
> > - */
> > -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > - struct device_node *dev, int primary)
> > -{
> > - const u32 *ranges;
> > - int rlen;
> > - int pna = of_n_addr_cells(dev);
> > - int np = pna + 5;
> > - int memno = 0, isa_hole = -1;
> > - u32 pci_space;
> > - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > - unsigned long long isa_mb = 0;
> > - struct resource *res;
> > -
> > - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
> > - dev->full_name, primary ? "(primary)" : "");
> > -
> > - /* Get ranges property */
> > - ranges = of_get_property(dev, "ranges", &rlen);
> > - if (ranges == NULL)
> > - return;
> > -
> > - /* Parse it */
> > - while ((rlen -= np * 4) >= 0) {
> > - /* Read next ranges element */
> > - pci_space = ranges[0];
> > - pci_addr = of_read_number(ranges + 1, 2);
> > - cpu_addr = of_translate_address(dev, ranges + 3);
> > - size = of_read_number(ranges + pna + 3, 2);
> > - ranges += np;
> > -
> > - /* If we failed translation or got a zero-sized region
> > - * (some FW try to feed us with non sensical zero sized regions
> > - * such as power3 which look like some kind of attempt at exposing
> > - * the VGA memory hole)
> > - */
> > - if (cpu_addr == OF_BAD_ADDR || size == 0)
> > - continue;
> > -
> > - /* Now consume following elements while they are contiguous */
> > - for (; rlen >= np * sizeof(u32);
> > - ranges += np, rlen -= np * 4) {
> > - if (ranges[0] != pci_space)
> > - break;
> > - pci_next = of_read_number(ranges + 1, 2);
> > - cpu_next = of_translate_address(dev, ranges + 3);
> > - if (pci_next != pci_addr + size ||
> > - cpu_next != cpu_addr + size)
> > - break;
> > - size += of_read_number(ranges + pna + 3, 2);
> > - }
> > -
> > - /* Act based on address space type */
> > - res = NULL;
> > - switch ((pci_space >> 24) & 0x3) {
> > - case 1: /* PCI IO space */
> > - printk(KERN_INFO
> > - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr);
> > -
> > - /* We support only one IO range */
> > - if (hose->pci_io_size) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > -#ifdef CONFIG_PPC32
> > - /* On 32 bits, limit I/O space to 16MB */
> > - if (size > 0x01000000)
> > - size = 0x01000000;
> > -
> > - /* 32 bits needs to map IOs here */
> > - hose->io_base_virt = ioremap(cpu_addr, size);
> > -
> > - /* Expect trouble if pci_addr is not 0 */
> > - if (primary)
> > - isa_io_base =
> > - (unsigned long)hose->io_base_virt;
> > -#endif /* CONFIG_PPC32 */
> > - /* pci_io_size and io_base_phys always represent IO
> > - * space starting at 0 so we factor in pci_addr
> > - */
> > - hose->pci_io_size = pci_addr + size;
> > - hose->io_base_phys = cpu_addr - pci_addr;
> > -
> > - /* Build resource */
> > - res = &hose->io_resource;
> > - res->flags = IORESOURCE_IO;
> > - res->start = pci_addr;
> > - break;
> > - case 2: /* PCI Memory space */
> > - case 3: /* PCI 64 bits Memory space */
> > - printk(KERN_INFO
> > - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > - cpu_addr, cpu_addr + size - 1, pci_addr,
> > - (pci_space & 0x40000000) ? "Prefetch" : "");
> > -
> > - /* We support only 3 memory ranges */
> > - if (memno >= 3) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (too many) !\n");
> > - continue;
> > - }
> > - /* Handles ISA memory hole space here */
> > - if (pci_addr == 0) {
> > - isa_mb = cpu_addr;
> > - isa_hole = memno;
> > - if (primary || isa_mem_base == 0)
> > - isa_mem_base = cpu_addr;
> > - hose->isa_mem_phys = cpu_addr;
> > - hose->isa_mem_size = size;
> > - }
> > -
> > - /* We get the PCI/Mem offset from the first range or
> > - * the, current one if the offset came from an ISA
> > - * hole. If they don't match, bugger.
> > - */
> > - if (memno == 0 ||
> > - (isa_hole >= 0 && pci_addr != 0 &&
> > - hose->pci_mem_offset == isa_mb))
> > - hose->pci_mem_offset = cpu_addr - pci_addr;
> > - else if (pci_addr != 0 &&
> > - hose->pci_mem_offset != cpu_addr - pci_addr) {
> > - printk(KERN_INFO
> > - " \\--> Skipped (offset mismatch) !\n");
> > - continue;
> > - }
> > -
> > - /* Build resource */
> > - res = &hose->mem_resources[memno++];
> > - res->flags = IORESOURCE_MEM;
> > - if (pci_space & 0x40000000)
> > - res->flags |= IORESOURCE_PREFETCH;
> > - res->start = cpu_addr;
> > - break;
> > - }
> > - if (res != NULL) {
> > - res->name = dev->full_name;
> > - res->end = res->start + size - 1;
> > - res->parent = NULL;
> > - res->sibling = NULL;
> > - res->child = NULL;
> > - }
> > - }
> > -
> > - /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > - * the ISA hole offset, then we need to remove the ISA hole from
> > - * the resource list for that brige
> > - */
> > - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > - unsigned int next = isa_hole + 1;
> > - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
> > - if (next < memno)
> > - memmove(&hose->mem_resources[isa_hole],
> > - &hose->mem_resources[next],
> > - sizeof(struct resource) * (memno - next));
> > - hose->mem_resources[--memno].flags = 0;
> > - }
> > -}
> > -
> > /* Decide whether to display the domain number in /proc */
> > int pci_proc_domain(struct pci_bus *bus)
> > {
> > diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> > index 13e37e2..1626172 100644
> > --- a/drivers/of/of_pci.c
> > +++ b/drivers/of/of_pci.c
> > @@ -4,6 +4,10 @@
> > #include <linux/of_pci.h>
> > #include <asm/prom.h>
> >
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +#include <asm/pci-bridge.h>
> > +#endif
> > +
> > static inline int __of_pci_pci_compare(struct device_node *node,
> > unsigned int devfn)
> > {
> > @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
> > return NULL;
> > }
> > EXPORT_SYMBOL_GPL(of_pci_find_child_device);
> > +
> > +/**
> > + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
> > + * @hose: newly allocated pci_controller to be setup
> > + * @dev: device node of the host bridge
> > + * @primary: set if primary bus (32 bits only, soon to be deprecated)
> > + *
> > + * This function will parse the "ranges" property of a PCI host bridge device
> > + * node and setup the resource mapping of a pci controller based on its
> > + * content.
> > + *
> > + * Life would be boring if it wasn't for a few issues that we have to deal
> > + * with here:
> > + *
> > + * - We can only cope with one IO space range and up to 3 Memory space
> > + * ranges. However, some machines (thanks Apple !) tend to split their
> > + * space into lots of small contiguous ranges. So we have to coalesce.
> > + *
> > + * - We can only cope with all memory ranges having the same offset
> > + * between CPU addresses and PCI addresses. Unfortunately, some bridges
> > + * are setup for a large 1:1 mapping along with a small "window" which
> > + * maps PCI address 0 to some arbitrary high address of the CPU space in
> > + * order to give access to the ISA memory hole.
> > + * The way out of here that I've chosen for now is to always set the
> > + * offset based on the first resource found, then override it if we
> > + * have a different offset and the previous was set by an ISA hole.
> > + *
> > + * - Some busses have IO space not starting at 0, which causes trouble with
> > + * the way we do our IO resource renumbering. The code somewhat deals with
> > + * it for 64 bits but I would expect problems on 32 bits.
> > + *
> > + * - Some 32 bits platforms such as 4xx can have physical space larger than
> > + * 32 bits so we need to use 64 bits values for the parsing
> > + */
> > +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary)
> > +{
> > + const u32 *ranges;
> > + int rlen;
> > + int pna = of_n_addr_cells(dev);
> > + int np = pna + 5;
> > + int memno = 0, isa_hole = -1;
> > + u32 pci_space;
> > + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
> > + unsigned long long isa_mb = 0;
> > + struct resource *res;
> > +
> > + pr_info("PCI host bridge %s %s ranges:\n",
> > + dev->full_name, primary ? "(primary)" : "");
> > +
> > + /* Get ranges property */
> > + ranges = of_get_property(dev, "ranges", &rlen);
> > + if (ranges == NULL)
> > + return;
> > +
> > + /* Parse it */
> > + pr_debug("Parsing ranges property...\n");
> > + while ((rlen -= np * 4) >= 0) {
> > + /* Read next ranges element */
> > + pci_space = ranges[0];
> > + pci_addr = of_read_number(ranges + 1, 2);
> > + cpu_addr = of_translate_address(dev, ranges + 3);
> > + size = of_read_number(ranges + pna + 3, 2);
> > +
> > + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
> > + pci_space, pci_addr);
> > + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
> > + cpu_addr, size);
> > +
> > + ranges += np;
> > +
> > + /* If we failed translation or got a zero-sized region
> > + * (some FW try to feed us with non sensical zero sized regions
> > + * such as power3 which look like some kind of attempt
> > + * at exposing the VGA memory hole)
> > + */
> > + if (cpu_addr == OF_BAD_ADDR || size == 0)
> > + continue;
> > +
> > + /* Now consume following elements while they are contiguous */
> > + for (; rlen >= np * sizeof(u32);
> > + ranges += np, rlen -= np * 4) {
> > + if (ranges[0] != pci_space)
> > + break;
> > + pci_next = of_read_number(ranges + 1, 2);
> > + cpu_next = of_translate_address(dev, ranges + 3);
> > + if (pci_next != pci_addr + size ||
> > + cpu_next != cpu_addr + size)
> > + break;
> > + size += of_read_number(ranges + pna + 3, 2);
> > + }
> > +
> > + /* Act based on address space type */
> > + res = NULL;
> > + switch ((pci_space >> 24) & 0x3) {
> > + case 1: /* PCI IO space */
> > + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr);
> > +
> > + /* We support only one IO range */
> > + if (hose->pci_io_size) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > +#if (!IS_ENABLED(CONFIG_64BIT))
> > + /* On 32 bits, limit I/O space to 16MB */
> > + if (size > 0x01000000)
> > + size = 0x01000000;
> > +
> > + /* 32 bits needs to map IOs here */
> > + hose->io_base_virt = ioremap(cpu_addr, size);
> > +
> > + /* Expect trouble if pci_addr is not 0 */
> > + if (primary)
> > + isa_io_base =
> > + (unsigned long)hose->io_base_virt;
> > +#endif /* !CONFIG_64BIT */
> > + /* pci_io_size and io_base_phys always represent IO
> > + * space starting at 0 so we factor in pci_addr
> > + */
> > + hose->pci_io_size = pci_addr + size;
> > + hose->io_base_phys = cpu_addr - pci_addr;
> > +
> > + /* Build resource */
> > + res = &hose->io_resource;
> > + res->flags = IORESOURCE_IO;
> > + res->start = pci_addr;
> > + break;
> > + case 2: /* PCI Memory space */
> > + case 3: /* PCI 64 bits Memory space */
> > + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
> > + cpu_addr, cpu_addr + size - 1, pci_addr,
> > + (pci_space & 0x40000000) ? "Prefetch" : "");
> > +
> > + /* We support only 3 memory ranges */
> > + if (memno >= 3) {
> > + pr_info(" \\--> Skipped (too many) !\n");
> > + continue;
> > + }
> > + /* Handles ISA memory hole space here */
> > + if (pci_addr == 0) {
> > + isa_mb = cpu_addr;
> > + isa_hole = memno;
> > + if (primary || isa_mem_base == 0)
> > + isa_mem_base = cpu_addr;
> > + hose->isa_mem_phys = cpu_addr;
> > + hose->isa_mem_size = size;
> > + }
> > +
> > + /* We get the PCI/Mem offset from the first range or
> > + * the, current one if the offset came from an ISA
> > + * hole. If they don't match, bugger.
> > + */
> > + if (memno == 0 ||
> > + (isa_hole >= 0 && pci_addr != 0 &&
> > + hose->pci_mem_offset == isa_mb))
> > + hose->pci_mem_offset = cpu_addr - pci_addr;
> > + else if (pci_addr != 0 &&
> > + hose->pci_mem_offset != cpu_addr - pci_addr) {
> > + pr_info(" \\--> Skipped (offset mismatch) !\n");
> > + continue;
> > + }
> > +
> > + /* Build resource */
> > + res = &hose->mem_resources[memno++];
> > + res->flags = IORESOURCE_MEM;
> > + if (pci_space & 0x40000000)
> > + res->flags |= IORESOURCE_PREFETCH;
> > + res->start = cpu_addr;
> > + break;
> > + }
> > + if (res != NULL) {
> > + res->name = dev->full_name;
> > + res->end = res->start + size - 1;
> > + res->parent = NULL;
> > + res->sibling = NULL;
> > + res->child = NULL;
> > + }
> > + }
> > +
> > + /* If there's an ISA hole and the pci_mem_offset is -not- matching
> > + * the ISA hole offset, then we need to remove the ISA hole from
> > + * the resource list for that brige
> > + */
> > + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
> > + unsigned int next = isa_hole + 1;
> > + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
> > + if (next < memno)
> > + memmove(&hose->mem_resources[isa_hole],
> > + &hose->mem_resources[next],
> > + sizeof(struct resource) * (memno - next));
> > + hose->mem_resources[--memno].flags = 0;
> > + }
> > +}
> > +#endif
> > diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
> > index bb115de..33e8ead 100644
> > --- a/include/linux/of_pci.h
> > +++ b/include/linux/of_pci.h
> > @@ -11,4 +11,8 @@ struct device_node;
> > struct device_node *of_pci_find_child_device(struct device_node *parent,
> > unsigned int devfn);
> >
> > +struct pci_controller;
> > +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
> > + struct device_node *dev, int primary);
> > +
> > #endif
>
>
>
^ permalink raw reply [flat|nested] 43+ messages in thread
* Re: [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
2013-04-15 12:57 ` Thomas Petazzoni
@ 2013-04-15 16:50 ` Michal Simek
-1 siblings, 0 replies; 43+ messages in thread
From: Michal Simek @ 2013-04-15 16:50 UTC (permalink / raw)
To: Thomas Petazzoni
Cc: benh, Andrew Murray, rob.herring, jgunthorpe, linux, siva.kallam,
linux-pci, devicetree-discuss, jg1.han, Liviu.Dudau, linux-kernel,
linux-samsung-soc, kgene.kim, bhelgaas, suren.reddy,
linux-arm-kernel, paulus, grant.likely, thierry.reding,
thomas.abraham, arnd, linus.walleij
Hi Thomas and Andrew,
First of all I would recommend you to add your tree to 0-day testing
system where you can easily catch up compilation failures for
microblaze and others.
Getting this compilation failure:
drivers/of/of_pci.c: In function 'pci_process_bridge_OF_ranges':
drivers/of/of_pci.c:88:22: error: storage size of 'range' isn't known
drivers/of/of_pci.c:89:29: error: storage size of 'parser' isn't known
drivers/of/of_pci.c:96:2: error: implicit declaration of function 'of_pci_range_parser' [-Werror=implicit-function-declaration]
drivers/of/of_pci.c:100:2: error: implicit declaration of function 'for_each_of_pci_range' [-Werror=implicit-function-declaration]
drivers/of/of_pci.c:100:41: error: expected ';' before '{' token
drivers/of/of_pci.c:90:6: warning: unused variable 'res_type' [-Wunused-variable]
drivers/of/of_pci.c:89:29: warning: unused variable 'parser' [-Wunused-variable]
drivers/of/of_pci.c:88:22: warning: unused variable 'range' [-Wunused-variable]
drivers/of/of_pci.c:87:19: warning: unused variable 'res' [-Wunused-variable]
drivers/of/of_pci.c:86:21: warning: unused variable 'isa_mb' [-Wunused-variable]
drivers/of/of_pci.c:85:17: warning: unused variable 'isa_hole' [-Wunused-variable]
drivers/of/of_pci.c:85:6: warning: unused variable 'memno' [-Wunused-variable]
which is caused missing linux/of_addresss.h in of_pci.c.
PowerPC probably won't have this problem because you have this header in asm/prom.h
but based on the same comment it is better to add it directly to the files.
That's why please add this header to this patch.
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 3e428a1..f30887e 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <asm/prom.h>
When you fix it:
Acked-by: Michal Simek <monstr@monstr.eu>
Thanks,
Michal
On 04/15/2013 02:57 PM, Thomas Petazzoni wrote:
> Michal, Ben,
>
> Would you have some time to look at this patch and give your comments
> and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
> need your agreement to merge this code, and quite a bit of code pending
> for 3.10 depends on this patch.
>
> Rob, alternatively, could we imagine doing a different version of the
> 'of/pci: Provide support for parsing PCI DT ranges property' that
> introduces the new API only, leaving the PowerPC and Microblaze rework
> as follow-up efforts, so that all the PCIe drivers that depend on this
> patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
> driver that has been worked on since 4+ months does not get into 3.10
> just because this patch cannot be merged.
>
> Thanks!
>
> Thomas
>
> On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
>> The pci_process_bridge_OF_ranges function, used to parse the "ranges"
>> property of a PCI host device, is found in both Microblaze and PowerPC
>> architectures. These implementations are nearly identical. This patch
>> moves this common code to a common place.
>>
>> Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
>> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
>> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
>> ---
>> arch/microblaze/include/asm/pci-bridge.h | 5 +-
>> arch/microblaze/pci/pci-common.c | 192 ----------------------------
>> arch/powerpc/include/asm/pci-bridge.h | 5 +-
>> arch/powerpc/kernel/pci-common.c | 192 ----------------------------
>> drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
>> include/linux/of_pci.h | 4 +
>> 6 files changed, 206 insertions(+), 392 deletions(-)
>>
>> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
>> index cb5d397..5783cd6 100644
>> --- a/arch/microblaze/include/asm/pci-bridge.h
>> +++ b/arch/microblaze/include/asm/pci-bridge.h
>> @@ -10,6 +10,7 @@
>> #include <linux/pci.h>
>> #include <linux/list.h>
>> #include <linux/ioport.h>
>> +#include <linux/of_pci.h>
>>
>> struct device_node;
>>
>> @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
>> extern struct pci_controller *pci_find_hose_for_OF_device(
>> struct device_node *node);
>>
>> -/* Fill up host controller resources from the OF node */
>> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary);
>> -
>> /* 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);
>> diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
>> index 9ea521e..2735ad9 100644
>> --- a/arch/microblaze/pci/pci-common.c
>> +++ b/arch/microblaze/pci/pci-common.c
>> @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
>> *end = rsrc->end - offset;
>> }
>>
>> -/**
>> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> - * @hose: newly allocated pci_controller to be setup
>> - * @dev: device node of the host bridge
>> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> - *
>> - * This function will parse the "ranges" property of a PCI host bridge device
>> - * node and setup the resource mapping of a pci controller based on its
>> - * content.
>> - *
>> - * Life would be boring if it wasn't for a few issues that we have to deal
>> - * with here:
>> - *
>> - * - We can only cope with one IO space range and up to 3 Memory space
>> - * ranges. However, some machines (thanks Apple !) tend to split their
>> - * space into lots of small contiguous ranges. So we have to coalesce.
>> - *
>> - * - We can only cope with all memory ranges having the same offset
>> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> - * are setup for a large 1:1 mapping along with a small "window" which
>> - * maps PCI address 0 to some arbitrary high address of the CPU space in
>> - * order to give access to the ISA memory hole.
>> - * The way out of here that I've chosen for now is to always set the
>> - * offset based on the first resource found, then override it if we
>> - * have a different offset and the previous was set by an ISA hole.
>> - *
>> - * - Some busses have IO space not starting at 0, which causes trouble with
>> - * the way we do our IO resource renumbering. The code somewhat deals with
>> - * it for 64 bits but I would expect problems on 32 bits.
>> - *
>> - * - Some 32 bits platforms such as 4xx can have physical space larger than
>> - * 32 bits so we need to use 64 bits values for the parsing
>> - */
>> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary)
>> -{
>> - const u32 *ranges;
>> - int rlen;
>> - int pna = of_n_addr_cells(dev);
>> - int np = pna + 5;
>> - int memno = 0, isa_hole = -1;
>> - u32 pci_space;
>> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> - unsigned long long isa_mb = 0;
>> - struct resource *res;
>> -
>> - pr_info("PCI host bridge %s %s ranges:\n",
>> - dev->full_name, primary ? "(primary)" : "");
>> -
>> - /* Get ranges property */
>> - ranges = of_get_property(dev, "ranges", &rlen);
>> - if (ranges == NULL)
>> - return;
>> -
>> - /* Parse it */
>> - pr_debug("Parsing ranges property...\n");
>> - while ((rlen -= np * 4) >= 0) {
>> - /* Read next ranges element */
>> - pci_space = ranges[0];
>> - pci_addr = of_read_number(ranges + 1, 2);
>> - cpu_addr = of_translate_address(dev, ranges + 3);
>> - size = of_read_number(ranges + pna + 3, 2);
>> -
>> - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
>> - pci_space, pci_addr);
>> - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
>> - cpu_addr, size);
>> -
>> - ranges += np;
>> -
>> - /* If we failed translation or got a zero-sized region
>> - * (some FW try to feed us with non sensical zero sized regions
>> - * such as power3 which look like some kind of attempt
>> - * at exposing the VGA memory hole)
>> - */
>> - if (cpu_addr == OF_BAD_ADDR || size == 0)
>> - continue;
>> -
>> - /* Now consume following elements while they are contiguous */
>> - for (; rlen >= np * sizeof(u32);
>> - ranges += np, rlen -= np * 4) {
>> - if (ranges[0] != pci_space)
>> - break;
>> - pci_next = of_read_number(ranges + 1, 2);
>> - cpu_next = of_translate_address(dev, ranges + 3);
>> - if (pci_next != pci_addr + size ||
>> - cpu_next != cpu_addr + size)
>> - break;
>> - size += of_read_number(ranges + pna + 3, 2);
>> - }
>> -
>> - /* Act based on address space type */
>> - res = NULL;
>> - switch ((pci_space >> 24) & 0x3) {
>> - case 1: /* PCI IO space */
>> - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr);
>> -
>> - /* We support only one IO range */
>> - if (hose->pci_io_size) {
>> - pr_info(" \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* On 32 bits, limit I/O space to 16MB */
>> - if (size > 0x01000000)
>> - size = 0x01000000;
>> -
>> - /* 32 bits needs to map IOs here */
>> - hose->io_base_virt = ioremap(cpu_addr, size);
>> -
>> - /* Expect trouble if pci_addr is not 0 */
>> - if (primary)
>> - isa_io_base =
>> - (unsigned long)hose->io_base_virt;
>> - /* pci_io_size and io_base_phys always represent IO
>> - * space starting at 0 so we factor in pci_addr
>> - */
>> - hose->pci_io_size = pci_addr + size;
>> - hose->io_base_phys = cpu_addr - pci_addr;
>> -
>> - /* Build resource */
>> - res = &hose->io_resource;
>> - res->flags = IORESOURCE_IO;
>> - res->start = pci_addr;
>> - break;
>> - case 2: /* PCI Memory space */
>> - case 3: /* PCI 64 bits Memory space */
>> - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr,
>> - (pci_space & 0x40000000) ? "Prefetch" : "");
>> -
>> - /* We support only 3 memory ranges */
>> - if (memno >= 3) {
>> - pr_info(" \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* Handles ISA memory hole space here */
>> - if (pci_addr == 0) {
>> - isa_mb = cpu_addr;
>> - isa_hole = memno;
>> - if (primary || isa_mem_base == 0)
>> - isa_mem_base = cpu_addr;
>> - hose->isa_mem_phys = cpu_addr;
>> - hose->isa_mem_size = size;
>> - }
>> -
>> - /* We get the PCI/Mem offset from the first range or
>> - * the, current one if the offset came from an ISA
>> - * hole. If they don't match, bugger.
>> - */
>> - if (memno == 0 ||
>> - (isa_hole >= 0 && pci_addr != 0 &&
>> - hose->pci_mem_offset == isa_mb))
>> - hose->pci_mem_offset = cpu_addr - pci_addr;
>> - else if (pci_addr != 0 &&
>> - hose->pci_mem_offset != cpu_addr - pci_addr) {
>> - pr_info(" \\--> Skipped (offset mismatch) !\n");
>> - continue;
>> - }
>> -
>> - /* Build resource */
>> - res = &hose->mem_resources[memno++];
>> - res->flags = IORESOURCE_MEM;
>> - if (pci_space & 0x40000000)
>> - res->flags |= IORESOURCE_PREFETCH;
>> - res->start = cpu_addr;
>> - break;
>> - }
>> - if (res != NULL) {
>> - res->name = dev->full_name;
>> - res->end = res->start + size - 1;
>> - res->parent = NULL;
>> - res->sibling = NULL;
>> - res->child = NULL;
>> - }
>> - }
>> -
>> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> - * the ISA hole offset, then we need to remove the ISA hole from
>> - * the resource list for that brige
>> - */
>> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> - unsigned int next = isa_hole + 1;
>> - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
>> - if (next < memno)
>> - memmove(&hose->mem_resources[isa_hole],
>> - &hose->mem_resources[next],
>> - sizeof(struct resource) * (memno - next));
>> - hose->mem_resources[--memno].flags = 0;
>> - }
>> -}
>> -
>> /* Decide whether to display the domain number in /proc */
>> int pci_proc_domain(struct pci_bus *bus)
>> {
>> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
>> index 025a130..205bfba 100644
>> --- a/arch/powerpc/include/asm/pci-bridge.h
>> +++ b/arch/powerpc/include/asm/pci-bridge.h
>> @@ -10,6 +10,7 @@
>> #include <linux/pci.h>
>> #include <linux/list.h>
>> #include <linux/ioport.h>
>> +#include <linux/of_pci.h>
>> #include <asm-generic/pci-bridge.h>
>>
>> struct device_node;
>> @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
>> extern struct pci_controller *pci_find_hose_for_OF_device(
>> struct device_node* node);
>>
>> -/* Fill up host controller resources from the OF node */
>> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary);
>> -
>> /* 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);
>> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
>> index fa12ae4..6edf396 100644
>> --- a/arch/powerpc/kernel/pci-common.c
>> +++ b/arch/powerpc/kernel/pci-common.c
>> @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
>> *end = rsrc->end - offset;
>> }
>>
>> -/**
>> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> - * @hose: newly allocated pci_controller to be setup
>> - * @dev: device node of the host bridge
>> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> - *
>> - * This function will parse the "ranges" property of a PCI host bridge device
>> - * node and setup the resource mapping of a pci controller based on its
>> - * content.
>> - *
>> - * Life would be boring if it wasn't for a few issues that we have to deal
>> - * with here:
>> - *
>> - * - We can only cope with one IO space range and up to 3 Memory space
>> - * ranges. However, some machines (thanks Apple !) tend to split their
>> - * space into lots of small contiguous ranges. So we have to coalesce.
>> - *
>> - * - We can only cope with all memory ranges having the same offset
>> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> - * are setup for a large 1:1 mapping along with a small "window" which
>> - * maps PCI address 0 to some arbitrary high address of the CPU space in
>> - * order to give access to the ISA memory hole.
>> - * The way out of here that I've chosen for now is to always set the
>> - * offset based on the first resource found, then override it if we
>> - * have a different offset and the previous was set by an ISA hole.
>> - *
>> - * - Some busses have IO space not starting at 0, which causes trouble with
>> - * the way we do our IO resource renumbering. The code somewhat deals with
>> - * it for 64 bits but I would expect problems on 32 bits.
>> - *
>> - * - Some 32 bits platforms such as 4xx can have physical space larger than
>> - * 32 bits so we need to use 64 bits values for the parsing
>> - */
>> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary)
>> -{
>> - const u32 *ranges;
>> - int rlen;
>> - int pna = of_n_addr_cells(dev);
>> - int np = pna + 5;
>> - int memno = 0, isa_hole = -1;
>> - u32 pci_space;
>> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> - unsigned long long isa_mb = 0;
>> - struct resource *res;
>> -
>> - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
>> - dev->full_name, primary ? "(primary)" : "");
>> -
>> - /* Get ranges property */
>> - ranges = of_get_property(dev, "ranges", &rlen);
>> - if (ranges == NULL)
>> - return;
>> -
>> - /* Parse it */
>> - while ((rlen -= np * 4) >= 0) {
>> - /* Read next ranges element */
>> - pci_space = ranges[0];
>> - pci_addr = of_read_number(ranges + 1, 2);
>> - cpu_addr = of_translate_address(dev, ranges + 3);
>> - size = of_read_number(ranges + pna + 3, 2);
>> - ranges += np;
>> -
>> - /* If we failed translation or got a zero-sized region
>> - * (some FW try to feed us with non sensical zero sized regions
>> - * such as power3 which look like some kind of attempt at exposing
>> - * the VGA memory hole)
>> - */
>> - if (cpu_addr == OF_BAD_ADDR || size == 0)
>> - continue;
>> -
>> - /* Now consume following elements while they are contiguous */
>> - for (; rlen >= np * sizeof(u32);
>> - ranges += np, rlen -= np * 4) {
>> - if (ranges[0] != pci_space)
>> - break;
>> - pci_next = of_read_number(ranges + 1, 2);
>> - cpu_next = of_translate_address(dev, ranges + 3);
>> - if (pci_next != pci_addr + size ||
>> - cpu_next != cpu_addr + size)
>> - break;
>> - size += of_read_number(ranges + pna + 3, 2);
>> - }
>> -
>> - /* Act based on address space type */
>> - res = NULL;
>> - switch ((pci_space >> 24) & 0x3) {
>> - case 1: /* PCI IO space */
>> - printk(KERN_INFO
>> - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr);
>> -
>> - /* We support only one IO range */
>> - if (hose->pci_io_size) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> -#ifdef CONFIG_PPC32
>> - /* On 32 bits, limit I/O space to 16MB */
>> - if (size > 0x01000000)
>> - size = 0x01000000;
>> -
>> - /* 32 bits needs to map IOs here */
>> - hose->io_base_virt = ioremap(cpu_addr, size);
>> -
>> - /* Expect trouble if pci_addr is not 0 */
>> - if (primary)
>> - isa_io_base =
>> - (unsigned long)hose->io_base_virt;
>> -#endif /* CONFIG_PPC32 */
>> - /* pci_io_size and io_base_phys always represent IO
>> - * space starting at 0 so we factor in pci_addr
>> - */
>> - hose->pci_io_size = pci_addr + size;
>> - hose->io_base_phys = cpu_addr - pci_addr;
>> -
>> - /* Build resource */
>> - res = &hose->io_resource;
>> - res->flags = IORESOURCE_IO;
>> - res->start = pci_addr;
>> - break;
>> - case 2: /* PCI Memory space */
>> - case 3: /* PCI 64 bits Memory space */
>> - printk(KERN_INFO
>> - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr,
>> - (pci_space & 0x40000000) ? "Prefetch" : "");
>> -
>> - /* We support only 3 memory ranges */
>> - if (memno >= 3) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* Handles ISA memory hole space here */
>> - if (pci_addr == 0) {
>> - isa_mb = cpu_addr;
>> - isa_hole = memno;
>> - if (primary || isa_mem_base == 0)
>> - isa_mem_base = cpu_addr;
>> - hose->isa_mem_phys = cpu_addr;
>> - hose->isa_mem_size = size;
>> - }
>> -
>> - /* We get the PCI/Mem offset from the first range or
>> - * the, current one if the offset came from an ISA
>> - * hole. If they don't match, bugger.
>> - */
>> - if (memno == 0 ||
>> - (isa_hole >= 0 && pci_addr != 0 &&
>> - hose->pci_mem_offset == isa_mb))
>> - hose->pci_mem_offset = cpu_addr - pci_addr;
>> - else if (pci_addr != 0 &&
>> - hose->pci_mem_offset != cpu_addr - pci_addr) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (offset mismatch) !\n");
>> - continue;
>> - }
>> -
>> - /* Build resource */
>> - res = &hose->mem_resources[memno++];
>> - res->flags = IORESOURCE_MEM;
>> - if (pci_space & 0x40000000)
>> - res->flags |= IORESOURCE_PREFETCH;
>> - res->start = cpu_addr;
>> - break;
>> - }
>> - if (res != NULL) {
>> - res->name = dev->full_name;
>> - res->end = res->start + size - 1;
>> - res->parent = NULL;
>> - res->sibling = NULL;
>> - res->child = NULL;
>> - }
>> - }
>> -
>> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> - * the ISA hole offset, then we need to remove the ISA hole from
>> - * the resource list for that brige
>> - */
>> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> - unsigned int next = isa_hole + 1;
>> - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
>> - if (next < memno)
>> - memmove(&hose->mem_resources[isa_hole],
>> - &hose->mem_resources[next],
>> - sizeof(struct resource) * (memno - next));
>> - hose->mem_resources[--memno].flags = 0;
>> - }
>> -}
>> -
>> /* Decide whether to display the domain number in /proc */
>> int pci_proc_domain(struct pci_bus *bus)
>> {
>> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
>> index 13e37e2..1626172 100644
>> --- a/drivers/of/of_pci.c
>> +++ b/drivers/of/of_pci.c
>> @@ -4,6 +4,10 @@
>> #include <linux/of_pci.h>
>> #include <asm/prom.h>
>>
>> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
>> +#include <asm/pci-bridge.h>
>> +#endif
>> +
>> static inline int __of_pci_pci_compare(struct device_node *node,
>> unsigned int devfn)
>> {
>> @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>> return NULL;
>> }
>> EXPORT_SYMBOL_GPL(of_pci_find_child_device);
>> +
>> +/**
>> + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> + * @hose: newly allocated pci_controller to be setup
>> + * @dev: device node of the host bridge
>> + * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> + *
>> + * This function will parse the "ranges" property of a PCI host bridge device
>> + * node and setup the resource mapping of a pci controller based on its
>> + * content.
>> + *
>> + * Life would be boring if it wasn't for a few issues that we have to deal
>> + * with here:
>> + *
>> + * - We can only cope with one IO space range and up to 3 Memory space
>> + * ranges. However, some machines (thanks Apple !) tend to split their
>> + * space into lots of small contiguous ranges. So we have to coalesce.
>> + *
>> + * - We can only cope with all memory ranges having the same offset
>> + * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> + * are setup for a large 1:1 mapping along with a small "window" which
>> + * maps PCI address 0 to some arbitrary high address of the CPU space in
>> + * order to give access to the ISA memory hole.
>> + * The way out of here that I've chosen for now is to always set the
>> + * offset based on the first resource found, then override it if we
>> + * have a different offset and the previous was set by an ISA hole.
>> + *
>> + * - Some busses have IO space not starting at 0, which causes trouble with
>> + * the way we do our IO resource renumbering. The code somewhat deals with
>> + * it for 64 bits but I would expect problems on 32 bits.
>> + *
>> + * - Some 32 bits platforms such as 4xx can have physical space larger than
>> + * 32 bits so we need to use 64 bits values for the parsing
>> + */
>> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
>> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> + struct device_node *dev, int primary)
>> +{
>> + const u32 *ranges;
>> + int rlen;
>> + int pna = of_n_addr_cells(dev);
>> + int np = pna + 5;
>> + int memno = 0, isa_hole = -1;
>> + u32 pci_space;
>> + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> + unsigned long long isa_mb = 0;
>> + struct resource *res;
>> +
>> + pr_info("PCI host bridge %s %s ranges:\n",
>> + dev->full_name, primary ? "(primary)" : "");
>> +
>> + /* Get ranges property */
>> + ranges = of_get_property(dev, "ranges", &rlen);
>> + if (ranges == NULL)
>> + return;
>> +
>> + /* Parse it */
>> + pr_debug("Parsing ranges property...\n");
>> + while ((rlen -= np * 4) >= 0) {
>> + /* Read next ranges element */
>> + pci_space = ranges[0];
>> + pci_addr = of_read_number(ranges + 1, 2);
>> + cpu_addr = of_translate_address(dev, ranges + 3);
>> + size = of_read_number(ranges + pna + 3, 2);
>> +
>> + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
>> + pci_space, pci_addr);
>> + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
>> + cpu_addr, size);
>> +
>> + ranges += np;
>> +
>> + /* If we failed translation or got a zero-sized region
>> + * (some FW try to feed us with non sensical zero sized regions
>> + * such as power3 which look like some kind of attempt
>> + * at exposing the VGA memory hole)
>> + */
>> + if (cpu_addr == OF_BAD_ADDR || size == 0)
>> + continue;
>> +
>> + /* Now consume following elements while they are contiguous */
>> + for (; rlen >= np * sizeof(u32);
>> + ranges += np, rlen -= np * 4) {
>> + if (ranges[0] != pci_space)
>> + break;
>> + pci_next = of_read_number(ranges + 1, 2);
>> + cpu_next = of_translate_address(dev, ranges + 3);
>> + if (pci_next != pci_addr + size ||
>> + cpu_next != cpu_addr + size)
>> + break;
>> + size += of_read_number(ranges + pna + 3, 2);
>> + }
>> +
>> + /* Act based on address space type */
>> + res = NULL;
>> + switch ((pci_space >> 24) & 0x3) {
>> + case 1: /* PCI IO space */
>> + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> + cpu_addr, cpu_addr + size - 1, pci_addr);
>> +
>> + /* We support only one IO range */
>> + if (hose->pci_io_size) {
>> + pr_info(" \\--> Skipped (too many) !\n");
>> + continue;
>> + }
>> +#if (!IS_ENABLED(CONFIG_64BIT))
>> + /* On 32 bits, limit I/O space to 16MB */
>> + if (size > 0x01000000)
>> + size = 0x01000000;
>> +
>> + /* 32 bits needs to map IOs here */
>> + hose->io_base_virt = ioremap(cpu_addr, size);
>> +
>> + /* Expect trouble if pci_addr is not 0 */
>> + if (primary)
>> + isa_io_base =
>> + (unsigned long)hose->io_base_virt;
>> +#endif /* !CONFIG_64BIT */
>> + /* pci_io_size and io_base_phys always represent IO
>> + * space starting at 0 so we factor in pci_addr
>> + */
>> + hose->pci_io_size = pci_addr + size;
>> + hose->io_base_phys = cpu_addr - pci_addr;
>> +
>> + /* Build resource */
>> + res = &hose->io_resource;
>> + res->flags = IORESOURCE_IO;
>> + res->start = pci_addr;
>> + break;
>> + case 2: /* PCI Memory space */
>> + case 3: /* PCI 64 bits Memory space */
>> + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> + cpu_addr, cpu_addr + size - 1, pci_addr,
>> + (pci_space & 0x40000000) ? "Prefetch" : "");
>> +
>> + /* We support only 3 memory ranges */
>> + if (memno >= 3) {
>> + pr_info(" \\--> Skipped (too many) !\n");
>> + continue;
>> + }
>> + /* Handles ISA memory hole space here */
>> + if (pci_addr == 0) {
>> + isa_mb = cpu_addr;
>> + isa_hole = memno;
>> + if (primary || isa_mem_base == 0)
>> + isa_mem_base = cpu_addr;
>> + hose->isa_mem_phys = cpu_addr;
>> + hose->isa_mem_size = size;
>> + }
>> +
>> + /* We get the PCI/Mem offset from the first range or
>> + * the, current one if the offset came from an ISA
>> + * hole. If they don't match, bugger.
>> + */
>> + if (memno == 0 ||
>> + (isa_hole >= 0 && pci_addr != 0 &&
>> + hose->pci_mem_offset == isa_mb))
>> + hose->pci_mem_offset = cpu_addr - pci_addr;
>> + else if (pci_addr != 0 &&
>> + hose->pci_mem_offset != cpu_addr - pci_addr) {
>> + pr_info(" \\--> Skipped (offset mismatch) !\n");
>> + continue;
>> + }
>> +
>> + /* Build resource */
>> + res = &hose->mem_resources[memno++];
>> + res->flags = IORESOURCE_MEM;
>> + if (pci_space & 0x40000000)
>> + res->flags |= IORESOURCE_PREFETCH;
>> + res->start = cpu_addr;
>> + break;
>> + }
>> + if (res != NULL) {
>> + res->name = dev->full_name;
>> + res->end = res->start + size - 1;
>> + res->parent = NULL;
>> + res->sibling = NULL;
>> + res->child = NULL;
>> + }
>> + }
>> +
>> + /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> + * the ISA hole offset, then we need to remove the ISA hole from
>> + * the resource list for that brige
>> + */
>> + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> + unsigned int next = isa_hole + 1;
>> + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
>> + if (next < memno)
>> + memmove(&hose->mem_resources[isa_hole],
>> + &hose->mem_resources[next],
>> + sizeof(struct resource) * (memno - next));
>> + hose->mem_resources[--memno].flags = 0;
>> + }
>> +}
>> +#endif
>> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
>> index bb115de..33e8ead 100644
>> --- a/include/linux/of_pci.h
>> +++ b/include/linux/of_pci.h
>> @@ -11,4 +11,8 @@ struct device_node;
>> struct device_node *of_pci_find_child_device(struct device_node *parent,
>> unsigned int devfn);
>>
>> +struct pci_controller;
>> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> + struct device_node *dev, int primary);
>> +
>> #endif
>
>
>
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID:
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
^ permalink raw reply related [flat|nested] 43+ messages in thread* [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-15 16:50 ` Michal Simek
0 siblings, 0 replies; 43+ messages in thread
From: Michal Simek @ 2013-04-15 16:50 UTC (permalink / raw)
To: linux-arm-kernel
Hi Thomas and Andrew,
First of all I would recommend you to add your tree to 0-day testing
system where you can easily catch up compilation failures for
microblaze and others.
Getting this compilation failure:
drivers/of/of_pci.c: In function 'pci_process_bridge_OF_ranges':
drivers/of/of_pci.c:88:22: error: storage size of 'range' isn't known
drivers/of/of_pci.c:89:29: error: storage size of 'parser' isn't known
drivers/of/of_pci.c:96:2: error: implicit declaration of function 'of_pci_range_parser' [-Werror=implicit-function-declaration]
drivers/of/of_pci.c:100:2: error: implicit declaration of function 'for_each_of_pci_range' [-Werror=implicit-function-declaration]
drivers/of/of_pci.c:100:41: error: expected ';' before '{' token
drivers/of/of_pci.c:90:6: warning: unused variable 'res_type' [-Wunused-variable]
drivers/of/of_pci.c:89:29: warning: unused variable 'parser' [-Wunused-variable]
drivers/of/of_pci.c:88:22: warning: unused variable 'range' [-Wunused-variable]
drivers/of/of_pci.c:87:19: warning: unused variable 'res' [-Wunused-variable]
drivers/of/of_pci.c:86:21: warning: unused variable 'isa_mb' [-Wunused-variable]
drivers/of/of_pci.c:85:17: warning: unused variable 'isa_hole' [-Wunused-variable]
drivers/of/of_pci.c:85:6: warning: unused variable 'memno' [-Wunused-variable]
which is caused missing linux/of_addresss.h in of_pci.c.
PowerPC probably won't have this problem because you have this header in asm/prom.h
but based on the same comment it is better to add it directly to the files.
That's why please add this header to this patch.
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 3e428a1..f30887e 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -1,6 +1,7 @@
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/of.h>
+#include <linux/of_address.h>
#include <linux/of_pci.h>
#include <asm/prom.h>
When you fix it:
Acked-by: Michal Simek <monstr@monstr.eu>
Thanks,
Michal
On 04/15/2013 02:57 PM, Thomas Petazzoni wrote:
> Michal, Ben,
>
> Would you have some time to look at this patch and give your comments
> and/or ACK ? Since it touches the PowerPC and Microblaze core code, we
> need your agreement to merge this code, and quite a bit of code pending
> for 3.10 depends on this patch.
>
> Rob, alternatively, could we imagine doing a different version of the
> 'of/pci: Provide support for parsing PCI DT ranges property' that
> introduces the new API only, leaving the PowerPC and Microblaze rework
> as follow-up efforts, so that all the PCIe drivers that depend on this
> patch can get in for 3.10 ? I'd find it pretty sad if the Marvell PCIe
> driver that has been worked on since 4+ months does not get into 3.10
> just because this patch cannot be merged.
>
> Thanks!
>
> Thomas
>
> On Thu, 11 Apr 2013 16:26:07 +0100, Andrew Murray wrote:
>> The pci_process_bridge_OF_ranges function, used to parse the "ranges"
>> property of a PCI host device, is found in both Microblaze and PowerPC
>> architectures. These implementations are nearly identical. This patch
>> moves this common code to a common place.
>>
>> Signed-off-by: Andrew Murray <Andrew.Murray@arm.com>
>> Signed-off-by: Liviu Dudau <Liviu.Dudau@arm.com>
>> Reviewed-by: Rob Herring <rob.herring@calxeda.com>
>> Tested-by: Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
>> ---
>> arch/microblaze/include/asm/pci-bridge.h | 5 +-
>> arch/microblaze/pci/pci-common.c | 192 ----------------------------
>> arch/powerpc/include/asm/pci-bridge.h | 5 +-
>> arch/powerpc/kernel/pci-common.c | 192 ----------------------------
>> drivers/of/of_pci.c | 200 ++++++++++++++++++++++++++++++
>> include/linux/of_pci.h | 4 +
>> 6 files changed, 206 insertions(+), 392 deletions(-)
>>
>> diff --git a/arch/microblaze/include/asm/pci-bridge.h b/arch/microblaze/include/asm/pci-bridge.h
>> index cb5d397..5783cd6 100644
>> --- a/arch/microblaze/include/asm/pci-bridge.h
>> +++ b/arch/microblaze/include/asm/pci-bridge.h
>> @@ -10,6 +10,7 @@
>> #include <linux/pci.h>
>> #include <linux/list.h>
>> #include <linux/ioport.h>
>> +#include <linux/of_pci.h>
>>
>> struct device_node;
>>
>> @@ -132,10 +133,6 @@ extern void setup_indirect_pci(struct pci_controller *hose,
>> extern struct pci_controller *pci_find_hose_for_OF_device(
>> struct device_node *node);
>>
>> -/* Fill up host controller resources from the OF node */
>> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary);
>> -
>> /* 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);
>> diff --git a/arch/microblaze/pci/pci-common.c b/arch/microblaze/pci/pci-common.c
>> index 9ea521e..2735ad9 100644
>> --- a/arch/microblaze/pci/pci-common.c
>> +++ b/arch/microblaze/pci/pci-common.c
>> @@ -622,198 +622,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
>> *end = rsrc->end - offset;
>> }
>>
>> -/**
>> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> - * @hose: newly allocated pci_controller to be setup
>> - * @dev: device node of the host bridge
>> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> - *
>> - * This function will parse the "ranges" property of a PCI host bridge device
>> - * node and setup the resource mapping of a pci controller based on its
>> - * content.
>> - *
>> - * Life would be boring if it wasn't for a few issues that we have to deal
>> - * with here:
>> - *
>> - * - We can only cope with one IO space range and up to 3 Memory space
>> - * ranges. However, some machines (thanks Apple !) tend to split their
>> - * space into lots of small contiguous ranges. So we have to coalesce.
>> - *
>> - * - We can only cope with all memory ranges having the same offset
>> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> - * are setup for a large 1:1 mapping along with a small "window" which
>> - * maps PCI address 0 to some arbitrary high address of the CPU space in
>> - * order to give access to the ISA memory hole.
>> - * The way out of here that I've chosen for now is to always set the
>> - * offset based on the first resource found, then override it if we
>> - * have a different offset and the previous was set by an ISA hole.
>> - *
>> - * - Some busses have IO space not starting at 0, which causes trouble with
>> - * the way we do our IO resource renumbering. The code somewhat deals with
>> - * it for 64 bits but I would expect problems on 32 bits.
>> - *
>> - * - Some 32 bits platforms such as 4xx can have physical space larger than
>> - * 32 bits so we need to use 64 bits values for the parsing
>> - */
>> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary)
>> -{
>> - const u32 *ranges;
>> - int rlen;
>> - int pna = of_n_addr_cells(dev);
>> - int np = pna + 5;
>> - int memno = 0, isa_hole = -1;
>> - u32 pci_space;
>> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> - unsigned long long isa_mb = 0;
>> - struct resource *res;
>> -
>> - pr_info("PCI host bridge %s %s ranges:\n",
>> - dev->full_name, primary ? "(primary)" : "");
>> -
>> - /* Get ranges property */
>> - ranges = of_get_property(dev, "ranges", &rlen);
>> - if (ranges == NULL)
>> - return;
>> -
>> - /* Parse it */
>> - pr_debug("Parsing ranges property...\n");
>> - while ((rlen -= np * 4) >= 0) {
>> - /* Read next ranges element */
>> - pci_space = ranges[0];
>> - pci_addr = of_read_number(ranges + 1, 2);
>> - cpu_addr = of_translate_address(dev, ranges + 3);
>> - size = of_read_number(ranges + pna + 3, 2);
>> -
>> - pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
>> - pci_space, pci_addr);
>> - pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
>> - cpu_addr, size);
>> -
>> - ranges += np;
>> -
>> - /* If we failed translation or got a zero-sized region
>> - * (some FW try to feed us with non sensical zero sized regions
>> - * such as power3 which look like some kind of attempt
>> - * at exposing the VGA memory hole)
>> - */
>> - if (cpu_addr == OF_BAD_ADDR || size == 0)
>> - continue;
>> -
>> - /* Now consume following elements while they are contiguous */
>> - for (; rlen >= np * sizeof(u32);
>> - ranges += np, rlen -= np * 4) {
>> - if (ranges[0] != pci_space)
>> - break;
>> - pci_next = of_read_number(ranges + 1, 2);
>> - cpu_next = of_translate_address(dev, ranges + 3);
>> - if (pci_next != pci_addr + size ||
>> - cpu_next != cpu_addr + size)
>> - break;
>> - size += of_read_number(ranges + pna + 3, 2);
>> - }
>> -
>> - /* Act based on address space type */
>> - res = NULL;
>> - switch ((pci_space >> 24) & 0x3) {
>> - case 1: /* PCI IO space */
>> - pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr);
>> -
>> - /* We support only one IO range */
>> - if (hose->pci_io_size) {
>> - pr_info(" \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* On 32 bits, limit I/O space to 16MB */
>> - if (size > 0x01000000)
>> - size = 0x01000000;
>> -
>> - /* 32 bits needs to map IOs here */
>> - hose->io_base_virt = ioremap(cpu_addr, size);
>> -
>> - /* Expect trouble if pci_addr is not 0 */
>> - if (primary)
>> - isa_io_base =
>> - (unsigned long)hose->io_base_virt;
>> - /* pci_io_size and io_base_phys always represent IO
>> - * space starting at 0 so we factor in pci_addr
>> - */
>> - hose->pci_io_size = pci_addr + size;
>> - hose->io_base_phys = cpu_addr - pci_addr;
>> -
>> - /* Build resource */
>> - res = &hose->io_resource;
>> - res->flags = IORESOURCE_IO;
>> - res->start = pci_addr;
>> - break;
>> - case 2: /* PCI Memory space */
>> - case 3: /* PCI 64 bits Memory space */
>> - pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr,
>> - (pci_space & 0x40000000) ? "Prefetch" : "");
>> -
>> - /* We support only 3 memory ranges */
>> - if (memno >= 3) {
>> - pr_info(" \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* Handles ISA memory hole space here */
>> - if (pci_addr == 0) {
>> - isa_mb = cpu_addr;
>> - isa_hole = memno;
>> - if (primary || isa_mem_base == 0)
>> - isa_mem_base = cpu_addr;
>> - hose->isa_mem_phys = cpu_addr;
>> - hose->isa_mem_size = size;
>> - }
>> -
>> - /* We get the PCI/Mem offset from the first range or
>> - * the, current one if the offset came from an ISA
>> - * hole. If they don't match, bugger.
>> - */
>> - if (memno == 0 ||
>> - (isa_hole >= 0 && pci_addr != 0 &&
>> - hose->pci_mem_offset == isa_mb))
>> - hose->pci_mem_offset = cpu_addr - pci_addr;
>> - else if (pci_addr != 0 &&
>> - hose->pci_mem_offset != cpu_addr - pci_addr) {
>> - pr_info(" \\--> Skipped (offset mismatch) !\n");
>> - continue;
>> - }
>> -
>> - /* Build resource */
>> - res = &hose->mem_resources[memno++];
>> - res->flags = IORESOURCE_MEM;
>> - if (pci_space & 0x40000000)
>> - res->flags |= IORESOURCE_PREFETCH;
>> - res->start = cpu_addr;
>> - break;
>> - }
>> - if (res != NULL) {
>> - res->name = dev->full_name;
>> - res->end = res->start + size - 1;
>> - res->parent = NULL;
>> - res->sibling = NULL;
>> - res->child = NULL;
>> - }
>> - }
>> -
>> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> - * the ISA hole offset, then we need to remove the ISA hole from
>> - * the resource list for that brige
>> - */
>> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> - unsigned int next = isa_hole + 1;
>> - pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
>> - if (next < memno)
>> - memmove(&hose->mem_resources[isa_hole],
>> - &hose->mem_resources[next],
>> - sizeof(struct resource) * (memno - next));
>> - hose->mem_resources[--memno].flags = 0;
>> - }
>> -}
>> -
>> /* Decide whether to display the domain number in /proc */
>> int pci_proc_domain(struct pci_bus *bus)
>> {
>> diff --git a/arch/powerpc/include/asm/pci-bridge.h b/arch/powerpc/include/asm/pci-bridge.h
>> index 025a130..205bfba 100644
>> --- a/arch/powerpc/include/asm/pci-bridge.h
>> +++ b/arch/powerpc/include/asm/pci-bridge.h
>> @@ -10,6 +10,7 @@
>> #include <linux/pci.h>
>> #include <linux/list.h>
>> #include <linux/ioport.h>
>> +#include <linux/of_pci.h>
>> #include <asm-generic/pci-bridge.h>
>>
>> struct device_node;
>> @@ -231,10 +232,6 @@ extern int pcibios_map_io_space(struct pci_bus *bus);
>> extern struct pci_controller *pci_find_hose_for_OF_device(
>> struct device_node* node);
>>
>> -/* Fill up host controller resources from the OF node */
>> -extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary);
>> -
>> /* 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);
>> diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c
>> index fa12ae4..6edf396 100644
>> --- a/arch/powerpc/kernel/pci-common.c
>> +++ b/arch/powerpc/kernel/pci-common.c
>> @@ -640,198 +640,6 @@ void pci_resource_to_user(const struct pci_dev *dev, int bar,
>> *end = rsrc->end - offset;
>> }
>>
>> -/**
>> - * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> - * @hose: newly allocated pci_controller to be setup
>> - * @dev: device node of the host bridge
>> - * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> - *
>> - * This function will parse the "ranges" property of a PCI host bridge device
>> - * node and setup the resource mapping of a pci controller based on its
>> - * content.
>> - *
>> - * Life would be boring if it wasn't for a few issues that we have to deal
>> - * with here:
>> - *
>> - * - We can only cope with one IO space range and up to 3 Memory space
>> - * ranges. However, some machines (thanks Apple !) tend to split their
>> - * space into lots of small contiguous ranges. So we have to coalesce.
>> - *
>> - * - We can only cope with all memory ranges having the same offset
>> - * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> - * are setup for a large 1:1 mapping along with a small "window" which
>> - * maps PCI address 0 to some arbitrary high address of the CPU space in
>> - * order to give access to the ISA memory hole.
>> - * The way out of here that I've chosen for now is to always set the
>> - * offset based on the first resource found, then override it if we
>> - * have a different offset and the previous was set by an ISA hole.
>> - *
>> - * - Some busses have IO space not starting at 0, which causes trouble with
>> - * the way we do our IO resource renumbering. The code somewhat deals with
>> - * it for 64 bits but I would expect problems on 32 bits.
>> - *
>> - * - Some 32 bits platforms such as 4xx can have physical space larger than
>> - * 32 bits so we need to use 64 bits values for the parsing
>> - */
>> -void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> - struct device_node *dev, int primary)
>> -{
>> - const u32 *ranges;
>> - int rlen;
>> - int pna = of_n_addr_cells(dev);
>> - int np = pna + 5;
>> - int memno = 0, isa_hole = -1;
>> - u32 pci_space;
>> - unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> - unsigned long long isa_mb = 0;
>> - struct resource *res;
>> -
>> - printk(KERN_INFO "PCI host bridge %s %s ranges:\n",
>> - dev->full_name, primary ? "(primary)" : "");
>> -
>> - /* Get ranges property */
>> - ranges = of_get_property(dev, "ranges", &rlen);
>> - if (ranges == NULL)
>> - return;
>> -
>> - /* Parse it */
>> - while ((rlen -= np * 4) >= 0) {
>> - /* Read next ranges element */
>> - pci_space = ranges[0];
>> - pci_addr = of_read_number(ranges + 1, 2);
>> - cpu_addr = of_translate_address(dev, ranges + 3);
>> - size = of_read_number(ranges + pna + 3, 2);
>> - ranges += np;
>> -
>> - /* If we failed translation or got a zero-sized region
>> - * (some FW try to feed us with non sensical zero sized regions
>> - * such as power3 which look like some kind of attempt at exposing
>> - * the VGA memory hole)
>> - */
>> - if (cpu_addr == OF_BAD_ADDR || size == 0)
>> - continue;
>> -
>> - /* Now consume following elements while they are contiguous */
>> - for (; rlen >= np * sizeof(u32);
>> - ranges += np, rlen -= np * 4) {
>> - if (ranges[0] != pci_space)
>> - break;
>> - pci_next = of_read_number(ranges + 1, 2);
>> - cpu_next = of_translate_address(dev, ranges + 3);
>> - if (pci_next != pci_addr + size ||
>> - cpu_next != cpu_addr + size)
>> - break;
>> - size += of_read_number(ranges + pna + 3, 2);
>> - }
>> -
>> - /* Act based on address space type */
>> - res = NULL;
>> - switch ((pci_space >> 24) & 0x3) {
>> - case 1: /* PCI IO space */
>> - printk(KERN_INFO
>> - " IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr);
>> -
>> - /* We support only one IO range */
>> - if (hose->pci_io_size) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> -#ifdef CONFIG_PPC32
>> - /* On 32 bits, limit I/O space to 16MB */
>> - if (size > 0x01000000)
>> - size = 0x01000000;
>> -
>> - /* 32 bits needs to map IOs here */
>> - hose->io_base_virt = ioremap(cpu_addr, size);
>> -
>> - /* Expect trouble if pci_addr is not 0 */
>> - if (primary)
>> - isa_io_base =
>> - (unsigned long)hose->io_base_virt;
>> -#endif /* CONFIG_PPC32 */
>> - /* pci_io_size and io_base_phys always represent IO
>> - * space starting at 0 so we factor in pci_addr
>> - */
>> - hose->pci_io_size = pci_addr + size;
>> - hose->io_base_phys = cpu_addr - pci_addr;
>> -
>> - /* Build resource */
>> - res = &hose->io_resource;
>> - res->flags = IORESOURCE_IO;
>> - res->start = pci_addr;
>> - break;
>> - case 2: /* PCI Memory space */
>> - case 3: /* PCI 64 bits Memory space */
>> - printk(KERN_INFO
>> - " MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> - cpu_addr, cpu_addr + size - 1, pci_addr,
>> - (pci_space & 0x40000000) ? "Prefetch" : "");
>> -
>> - /* We support only 3 memory ranges */
>> - if (memno >= 3) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (too many) !\n");
>> - continue;
>> - }
>> - /* Handles ISA memory hole space here */
>> - if (pci_addr == 0) {
>> - isa_mb = cpu_addr;
>> - isa_hole = memno;
>> - if (primary || isa_mem_base == 0)
>> - isa_mem_base = cpu_addr;
>> - hose->isa_mem_phys = cpu_addr;
>> - hose->isa_mem_size = size;
>> - }
>> -
>> - /* We get the PCI/Mem offset from the first range or
>> - * the, current one if the offset came from an ISA
>> - * hole. If they don't match, bugger.
>> - */
>> - if (memno == 0 ||
>> - (isa_hole >= 0 && pci_addr != 0 &&
>> - hose->pci_mem_offset == isa_mb))
>> - hose->pci_mem_offset = cpu_addr - pci_addr;
>> - else if (pci_addr != 0 &&
>> - hose->pci_mem_offset != cpu_addr - pci_addr) {
>> - printk(KERN_INFO
>> - " \\--> Skipped (offset mismatch) !\n");
>> - continue;
>> - }
>> -
>> - /* Build resource */
>> - res = &hose->mem_resources[memno++];
>> - res->flags = IORESOURCE_MEM;
>> - if (pci_space & 0x40000000)
>> - res->flags |= IORESOURCE_PREFETCH;
>> - res->start = cpu_addr;
>> - break;
>> - }
>> - if (res != NULL) {
>> - res->name = dev->full_name;
>> - res->end = res->start + size - 1;
>> - res->parent = NULL;
>> - res->sibling = NULL;
>> - res->child = NULL;
>> - }
>> - }
>> -
>> - /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> - * the ISA hole offset, then we need to remove the ISA hole from
>> - * the resource list for that brige
>> - */
>> - if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> - unsigned int next = isa_hole + 1;
>> - printk(KERN_INFO " Removing ISA hole at 0x%016llx\n", isa_mb);
>> - if (next < memno)
>> - memmove(&hose->mem_resources[isa_hole],
>> - &hose->mem_resources[next],
>> - sizeof(struct resource) * (memno - next));
>> - hose->mem_resources[--memno].flags = 0;
>> - }
>> -}
>> -
>> /* Decide whether to display the domain number in /proc */
>> int pci_proc_domain(struct pci_bus *bus)
>> {
>> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
>> index 13e37e2..1626172 100644
>> --- a/drivers/of/of_pci.c
>> +++ b/drivers/of/of_pci.c
>> @@ -4,6 +4,10 @@
>> #include <linux/of_pci.h>
>> #include <asm/prom.h>
>>
>> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
>> +#include <asm/pci-bridge.h>
>> +#endif
>> +
>> static inline int __of_pci_pci_compare(struct device_node *node,
>> unsigned int devfn)
>> {
>> @@ -40,3 +44,199 @@ struct device_node *of_pci_find_child_device(struct device_node *parent,
>> return NULL;
>> }
>> EXPORT_SYMBOL_GPL(of_pci_find_child_device);
>> +
>> +/**
>> + * pci_process_bridge_OF_ranges - Parse PCI bridge resources from device tree
>> + * @hose: newly allocated pci_controller to be setup
>> + * @dev: device node of the host bridge
>> + * @primary: set if primary bus (32 bits only, soon to be deprecated)
>> + *
>> + * This function will parse the "ranges" property of a PCI host bridge device
>> + * node and setup the resource mapping of a pci controller based on its
>> + * content.
>> + *
>> + * Life would be boring if it wasn't for a few issues that we have to deal
>> + * with here:
>> + *
>> + * - We can only cope with one IO space range and up to 3 Memory space
>> + * ranges. However, some machines (thanks Apple !) tend to split their
>> + * space into lots of small contiguous ranges. So we have to coalesce.
>> + *
>> + * - We can only cope with all memory ranges having the same offset
>> + * between CPU addresses and PCI addresses. Unfortunately, some bridges
>> + * are setup for a large 1:1 mapping along with a small "window" which
>> + * maps PCI address 0 to some arbitrary high address of the CPU space in
>> + * order to give access to the ISA memory hole.
>> + * The way out of here that I've chosen for now is to always set the
>> + * offset based on the first resource found, then override it if we
>> + * have a different offset and the previous was set by an ISA hole.
>> + *
>> + * - Some busses have IO space not starting at 0, which causes trouble with
>> + * the way we do our IO resource renumbering. The code somewhat deals with
>> + * it for 64 bits but I would expect problems on 32 bits.
>> + *
>> + * - Some 32 bits platforms such as 4xx can have physical space larger than
>> + * 32 bits so we need to use 64 bits values for the parsing
>> + */
>> +#if defined(CONFIG_PPC32) || defined(CONFIG_PPC64) || defined(CONFIG_MICROBLAZE)
>> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> + struct device_node *dev, int primary)
>> +{
>> + const u32 *ranges;
>> + int rlen;
>> + int pna = of_n_addr_cells(dev);
>> + int np = pna + 5;
>> + int memno = 0, isa_hole = -1;
>> + u32 pci_space;
>> + unsigned long long pci_addr, cpu_addr, pci_next, cpu_next, size;
>> + unsigned long long isa_mb = 0;
>> + struct resource *res;
>> +
>> + pr_info("PCI host bridge %s %s ranges:\n",
>> + dev->full_name, primary ? "(primary)" : "");
>> +
>> + /* Get ranges property */
>> + ranges = of_get_property(dev, "ranges", &rlen);
>> + if (ranges == NULL)
>> + return;
>> +
>> + /* Parse it */
>> + pr_debug("Parsing ranges property...\n");
>> + while ((rlen -= np * 4) >= 0) {
>> + /* Read next ranges element */
>> + pci_space = ranges[0];
>> + pci_addr = of_read_number(ranges + 1, 2);
>> + cpu_addr = of_translate_address(dev, ranges + 3);
>> + size = of_read_number(ranges + pna + 3, 2);
>> +
>> + pr_debug("pci_space: 0x%08x pci_addr:0x%016llx ",
>> + pci_space, pci_addr);
>> + pr_debug("cpu_addr:0x%016llx size:0x%016llx\n",
>> + cpu_addr, size);
>> +
>> + ranges += np;
>> +
>> + /* If we failed translation or got a zero-sized region
>> + * (some FW try to feed us with non sensical zero sized regions
>> + * such as power3 which look like some kind of attempt
>> + * at exposing the VGA memory hole)
>> + */
>> + if (cpu_addr == OF_BAD_ADDR || size == 0)
>> + continue;
>> +
>> + /* Now consume following elements while they are contiguous */
>> + for (; rlen >= np * sizeof(u32);
>> + ranges += np, rlen -= np * 4) {
>> + if (ranges[0] != pci_space)
>> + break;
>> + pci_next = of_read_number(ranges + 1, 2);
>> + cpu_next = of_translate_address(dev, ranges + 3);
>> + if (pci_next != pci_addr + size ||
>> + cpu_next != cpu_addr + size)
>> + break;
>> + size += of_read_number(ranges + pna + 3, 2);
>> + }
>> +
>> + /* Act based on address space type */
>> + res = NULL;
>> + switch ((pci_space >> 24) & 0x3) {
>> + case 1: /* PCI IO space */
>> + pr_info(" IO 0x%016llx..0x%016llx -> 0x%016llx\n",
>> + cpu_addr, cpu_addr + size - 1, pci_addr);
>> +
>> + /* We support only one IO range */
>> + if (hose->pci_io_size) {
>> + pr_info(" \\--> Skipped (too many) !\n");
>> + continue;
>> + }
>> +#if (!IS_ENABLED(CONFIG_64BIT))
>> + /* On 32 bits, limit I/O space to 16MB */
>> + if (size > 0x01000000)
>> + size = 0x01000000;
>> +
>> + /* 32 bits needs to map IOs here */
>> + hose->io_base_virt = ioremap(cpu_addr, size);
>> +
>> + /* Expect trouble if pci_addr is not 0 */
>> + if (primary)
>> + isa_io_base =
>> + (unsigned long)hose->io_base_virt;
>> +#endif /* !CONFIG_64BIT */
>> + /* pci_io_size and io_base_phys always represent IO
>> + * space starting at 0 so we factor in pci_addr
>> + */
>> + hose->pci_io_size = pci_addr + size;
>> + hose->io_base_phys = cpu_addr - pci_addr;
>> +
>> + /* Build resource */
>> + res = &hose->io_resource;
>> + res->flags = IORESOURCE_IO;
>> + res->start = pci_addr;
>> + break;
>> + case 2: /* PCI Memory space */
>> + case 3: /* PCI 64 bits Memory space */
>> + pr_info(" MEM 0x%016llx..0x%016llx -> 0x%016llx %s\n",
>> + cpu_addr, cpu_addr + size - 1, pci_addr,
>> + (pci_space & 0x40000000) ? "Prefetch" : "");
>> +
>> + /* We support only 3 memory ranges */
>> + if (memno >= 3) {
>> + pr_info(" \\--> Skipped (too many) !\n");
>> + continue;
>> + }
>> + /* Handles ISA memory hole space here */
>> + if (pci_addr == 0) {
>> + isa_mb = cpu_addr;
>> + isa_hole = memno;
>> + if (primary || isa_mem_base == 0)
>> + isa_mem_base = cpu_addr;
>> + hose->isa_mem_phys = cpu_addr;
>> + hose->isa_mem_size = size;
>> + }
>> +
>> + /* We get the PCI/Mem offset from the first range or
>> + * the, current one if the offset came from an ISA
>> + * hole. If they don't match, bugger.
>> + */
>> + if (memno == 0 ||
>> + (isa_hole >= 0 && pci_addr != 0 &&
>> + hose->pci_mem_offset == isa_mb))
>> + hose->pci_mem_offset = cpu_addr - pci_addr;
>> + else if (pci_addr != 0 &&
>> + hose->pci_mem_offset != cpu_addr - pci_addr) {
>> + pr_info(" \\--> Skipped (offset mismatch) !\n");
>> + continue;
>> + }
>> +
>> + /* Build resource */
>> + res = &hose->mem_resources[memno++];
>> + res->flags = IORESOURCE_MEM;
>> + if (pci_space & 0x40000000)
>> + res->flags |= IORESOURCE_PREFETCH;
>> + res->start = cpu_addr;
>> + break;
>> + }
>> + if (res != NULL) {
>> + res->name = dev->full_name;
>> + res->end = res->start + size - 1;
>> + res->parent = NULL;
>> + res->sibling = NULL;
>> + res->child = NULL;
>> + }
>> + }
>> +
>> + /* If there's an ISA hole and the pci_mem_offset is -not- matching
>> + * the ISA hole offset, then we need to remove the ISA hole from
>> + * the resource list for that brige
>> + */
>> + if (isa_hole >= 0 && hose->pci_mem_offset != isa_mb) {
>> + unsigned int next = isa_hole + 1;
>> + pr_info(" Removing ISA hole at 0x%016llx\n", isa_mb);
>> + if (next < memno)
>> + memmove(&hose->mem_resources[isa_hole],
>> + &hose->mem_resources[next],
>> + sizeof(struct resource) * (memno - next));
>> + hose->mem_resources[--memno].flags = 0;
>> + }
>> +}
>> +#endif
>> diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
>> index bb115de..33e8ead 100644
>> --- a/include/linux/of_pci.h
>> +++ b/include/linux/of_pci.h
>> @@ -11,4 +11,8 @@ struct device_node;
>> struct device_node *of_pci_find_child_device(struct device_node *parent,
>> unsigned int devfn);
>>
>> +struct pci_controller;
>> +void pci_process_bridge_OF_ranges(struct pci_controller *hose,
>> + struct device_node *dev, int primary);
>> +
>> #endif
>
>
>
--
Michal Simek, Ing. (M.Eng), OpenPGP -> KeyID:
w: www.monstr.eu p: +42-0-721842854
Maintainer of Linux kernel - Microblaze cpu - http://www.monstr.eu/fdt/
Maintainer of Linux kernel - Xilinx Zynq ARM architecture
Microblaze U-BOOT custodian and responsible for u-boot arm zynq platform
^ permalink raw reply related [flat|nested] 43+ messages in thread* Re: [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
2013-04-15 16:50 ` Michal Simek
@ 2013-04-16 11:49 ` Andrew Murray
-1 siblings, 0 replies; 43+ messages in thread
From: Andrew Murray @ 2013-04-16 11:49 UTC (permalink / raw)
To: Michal Simek
Cc: siva.kallam@samsung.com, benh@kernel.crashing.org,
linus.walleij@linaro.org, thierry.reding@avionic-design.de,
Liviu Dudau, grant.likely@secretlab.ca, paulus@samba.org,
linux-samsung-soc@vger.kernel.org, linux@arm.linux.org.uk,
jg1.han@samsung.com, jgunthorpe@obsidianresearch.com,
thomas.abraham@linaro.org, linux-pci@vger.kernel.org,
arnd@arndb.de, devicetree-discuss@lists.ozlabs.org,
rob.herring@calxeda.com
On Mon, Apr 15, 2013 at 05:50:55PM +0100, Michal Simek wrote:
> That's why please add this header to this patch.
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 3e428a1..f30887e 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -1,6 +1,7 @@
> #include <linux/kernel.h>
> #include <linux/export.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/of_pci.h>
> #include <asm/prom.h>
>
>
> When you fix it:
> Acked-by: Michal Simek <monstr@monstr.eu>
I've added this fix to the latest patchset (v7) and also your Ack - thanks for
your feedback (and the robot...).
Andrew Murray
^ permalink raw reply [flat|nested] 43+ messages in thread
* [PATCH v6 1/3] of/pci: Unify pci_process_bridge_OF_ranges from Microblaze and PowerPC
@ 2013-04-16 11:49 ` Andrew Murray
0 siblings, 0 replies; 43+ messages in thread
From: Andrew Murray @ 2013-04-16 11:49 UTC (permalink / raw)
To: linux-arm-kernel
On Mon, Apr 15, 2013 at 05:50:55PM +0100, Michal Simek wrote:
> That's why please add this header to this patch.
>
> diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
> index 3e428a1..f30887e 100644
> --- a/drivers/of/of_pci.c
> +++ b/drivers/of/of_pci.c
> @@ -1,6 +1,7 @@
> #include <linux/kernel.h>
> #include <linux/export.h>
> #include <linux/of.h>
> +#include <linux/of_address.h>
> #include <linux/of_pci.h>
> #include <asm/prom.h>
>
>
> When you fix it:
> Acked-by: Michal Simek <monstr@monstr.eu>
I've added this fix to the latest patchset (v7) and also your Ack - thanks for
your feedback (and the robot...).
Andrew Murray
^ permalink raw reply [flat|nested] 43+ messages in thread