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 <mon...@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.mur...@arm.com>
>> Signed-off-by: Liviu Dudau <liviu.du...@arm.com>
>> Reviewed-by: Rob Herring <rob.herr...@calxeda.com>
>> Tested-by: Thomas Petazzoni <thomas.petazz...@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

_______________________________________________
devicetree-discuss mailing list
devicetree-discuss@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/devicetree-discuss

Reply via email to