On Tue, 2010-06-08 at 08:10 -0600, Grant Likely wrote:
> Microblaze and PowerPC share a large chunk of code for translating
> OF device tree data into usable addresses.  There aren't many differences
                                                           ^^^^
Care to comment on these differences ?

> between the two, so merge the codebase wholesale rather than trying to
> work out the independent bits.

Well, I don't see ifdef's in the resulting code (but I'm a bit blind),
so what did you do with the differences ?

This is complex and fragile code, so any change to it must be very
carefully scrutinized.

Cheers,
Ben.

> Signed-off-by: Grant Likely <grant.lik...@secretlab.ca>
> CC: Michal Simek <mon...@monstr.eu>
> CC: Wolfram Sang <w.s...@pengutronix.de>
> CC: Stephen Rothwell <s...@canb.auug.org.au>
> CC: Benjamin Herrenschmidt <b...@kernel.crashing.org>
> CC: microblaze-ucli...@itee.uq.edu.au
> CC: linuxppc-...@ozlabs.org
> ---
>  arch/microblaze/include/asm/prom.h  |    4 
>  arch/microblaze/kernel/prom_parse.c |  489 ---------------------------------
>  arch/powerpc/include/asm/prom.h     |    4 
>  arch/powerpc/kernel/prom_parse.c    |  515 
> -----------------------------------
>  drivers/of/address.c                |  517 
> +++++++++++++++++++++++++++++++++++
>  include/linux/of_address.h          |    4 
>  6 files changed, 515 insertions(+), 1018 deletions(-)
> 
> diff --git a/arch/microblaze/include/asm/prom.h 
> b/arch/microblaze/include/asm/prom.h
> index 644fa32..35cb3de 100644
> --- a/arch/microblaze/include/asm/prom.h
> +++ b/arch/microblaze/include/asm/prom.h
> @@ -52,10 +52,6 @@ extern void pci_create_OF_bus_map(void);
>   * OF address retreival & translation
>   */
>  
> -/* Translate an OF address block into a CPU physical address
> - */
> -extern u64 of_translate_address(struct device_node *np, const u32 *addr);
> -
>  /* Extract an address from a device, returns the region size and
>   * the address space flags too. The PCI version uses a BAR number
>   * instead of an absolute index
> diff --git a/arch/microblaze/kernel/prom_parse.c 
> b/arch/microblaze/kernel/prom_parse.c
> index 7cb5a98..1d610e6 100644
> --- a/arch/microblaze/kernel/prom_parse.c
> +++ b/arch/microblaze/kernel/prom_parse.c
> @@ -10,213 +10,7 @@
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
>  
> -#define PRu64        "%llx"
> -
> -/* Max address size we deal with */
> -#define OF_MAX_ADDR_CELLS    4
> -#define OF_CHECK_COUNTS(na, ns)      ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS 
> && \
> -                     (ns) > 0)
> -
> -static struct of_bus *of_match_bus(struct device_node *np);
> -
> -/* Debug utility */
> -#ifdef DEBUG
> -static void of_dump_addr(const char *s, const u32 *addr, int na)
> -{
> -     printk(KERN_INFO "%s", s);
> -     while (na--)
> -             printk(KERN_INFO " %08x", *(addr++));
> -     printk(KERN_INFO "\n");
> -}
> -#else
> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
> -#endif
> -
> -/* Callbacks for bus specific translators */
> -struct of_bus {
> -     const char      *name;
> -     const char      *addresses;
> -     int             (*match)(struct device_node *parent);
> -     void            (*count_cells)(struct device_node *child,
> -                                     int *addrc, int *sizec);
> -     u64             (*map)(u32 *addr, const u32 *range,
> -                             int na, int ns, int pna);
> -     int             (*translate)(u32 *addr, u64 offset, int na);
> -     unsigned int    (*get_flags)(const u32 *addr);
> -};
> -
> -/*
> - * Default translator (generic bus)
> - */
> -
> -static void of_bus_default_count_cells(struct device_node *dev,
> -                                     int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = of_n_addr_cells(dev);
> -     if (sizec)
> -             *sizec = of_n_size_cells(dev);
> -}
> -
> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
> -             int na, int ns, int pna)
> -{
> -     u64 cp, s, da;
> -
> -     cp = of_read_number(range, na);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr, na);
> -
> -     pr_debug("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
> -             cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> -{
> -     u64 a = of_read_number(addr, na);
> -     memset(addr, 0, na * 4);
> -     a += offset;
> -     if (na > 1)
> -             addr[na - 2] = a >> 32;
> -     addr[na - 1] = a & 0xffffffffu;
> -
> -     return 0;
> -}
> -
> -static unsigned int of_bus_default_get_flags(const u32 *addr)
> -{
> -     return IORESOURCE_MEM;
> -}
> -
>  #ifdef CONFIG_PCI
> -/*
> - * PCI bus specific translator
> - */
> -
> -static int of_bus_pci_match(struct device_node *np)
> -{
> -     /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> -     return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> -}
> -
> -static void of_bus_pci_count_cells(struct device_node *np,
> -                             int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = 3;
> -     if (sizec)
> -             *sizec = 2;
> -}
> -
> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> -{
> -     u64 cp, s, da;
> -
> -     /* Check address type match */
> -     if ((addr[0] ^ range[0]) & 0x03000000)
> -             return OF_BAD_ADDR;
> -
> -     /* Read address values, skipping high cell */
> -     cp = of_read_number(range + 1, na - 1);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr + 1, na - 1);
> -
> -     pr_debug("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> -{
> -     return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
> -{
> -     unsigned int flags = 0;
> -     u32 w = addr[0];
> -
> -     switch ((w >> 24) & 0x03) {
> -     case 0x01:
> -             flags |= IORESOURCE_IO;
> -             break;
> -     case 0x02: /* 32 bits */
> -     case 0x03: /* 64 bits */
> -             flags |= IORESOURCE_MEM;
> -             break;
> -     }
> -     if (w & 0x40000000)
> -             flags |= IORESOURCE_PREFETCH;
> -     return flags;
> -}
> -
> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
> -                     unsigned int *flags)
> -{
> -     const u32 *prop;
> -     unsigned int psize;
> -     struct device_node *parent;
> -     struct of_bus *bus;
> -     int onesize, i, na, ns;
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             return NULL;
> -     bus = of_match_bus(parent);
> -     if (strcmp(bus->name, "pci")) {
> -             of_node_put(parent);
> -             return NULL;
> -     }
> -     bus->count_cells(dev, &na, &ns);
> -     of_node_put(parent);
> -     if (!OF_CHECK_COUNTS(na, ns))
> -             return NULL;
> -
> -     /* Get "reg" or "assigned-addresses" property */
> -     prop = of_get_property(dev, bus->addresses, &psize);
> -     if (prop == NULL)
> -             return NULL;
> -     psize /= 4;
> -
> -     onesize = na + ns;
> -     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -             if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> -                     if (size)
> -                             *size = of_read_number(prop + na, ns);
> -                     if (flags)
> -                             *flags = bus->get_flags(prop);
> -                     return prop;
> -             }
> -     return NULL;
> -}
> -EXPORT_SYMBOL(of_get_pci_address);
> -
> -int of_pci_address_to_resource(struct device_node *dev, int bar,
> -                             struct resource *r)
> -{
> -     const u32       *addrp;
> -     u64             size;
> -     unsigned int    flags;
> -
> -     addrp = of_get_pci_address(dev, bar, &size, &flags);
> -     if (addrp == NULL)
> -             return -EINVAL;
> -     return __of_address_to_resource(dev, addrp, size, flags, r);
> -}
> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
> -
> -static u8 of_irq_pci_swizzle(u8 slot, u8 pin)
> -{
> -     return (((pin - 1) + slot) % 4) + 1;
> -}
> -
>  int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  {
>       struct device_node *dn, *ppnode;
> @@ -291,289 +85,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq 
> *out_irq)
>  EXPORT_SYMBOL_GPL(of_irq_map_pci);
>  #endif /* CONFIG_PCI */
>  
> -/*
> - * ISA bus specific translator
> - */
> -
> -static int of_bus_isa_match(struct device_node *np)
> -{
> -     return !strcmp(np->name, "isa");
> -}
> -
> -static void of_bus_isa_count_cells(struct device_node *child,
> -                             int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = 2;
> -     if (sizec)
> -             *sizec = 1;
> -}
> -
> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> -{
> -     u64 cp, s, da;
> -
> -     /* Check address type match */
> -     if ((addr[0] ^ range[0]) & 0x00000001)
> -             return OF_BAD_ADDR;
> -
> -     /* Read address values, skipping high cell */
> -     cp = of_read_number(range + 1, na - 1);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr + 1, na - 1);
> -
> -     pr_debug("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> -{
> -     return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
> -{
> -     unsigned int flags = 0;
> -     u32 w = addr[0];
> -
> -     if (w & 1)
> -             flags |= IORESOURCE_IO;
> -     else
> -             flags |= IORESOURCE_MEM;
> -     return flags;
> -}
> -
> -/*
> - * Array of bus specific translators
> - */
> -
> -static struct of_bus of_busses[] = {
> -#ifdef CONFIG_PCI
> -     /* PCI */
> -     {
> -             .name = "pci",
> -             .addresses = "assigned-addresses",
> -             .match = of_bus_pci_match,
> -             .count_cells = of_bus_pci_count_cells,
> -             .map = of_bus_pci_map,
> -             .translate = of_bus_pci_translate,
> -             .get_flags = of_bus_pci_get_flags,
> -     },
> -#endif /* CONFIG_PCI */
> -     /* ISA */
> -     {
> -             .name = "isa",
> -             .addresses = "reg",
> -             .match = of_bus_isa_match,
> -             .count_cells = of_bus_isa_count_cells,
> -             .map = of_bus_isa_map,
> -             .translate = of_bus_isa_translate,
> -             .get_flags = of_bus_isa_get_flags,
> -     },
> -     /* Default */
> -     {
> -             .name = "default",
> -             .addresses = "reg",
> -             .match = NULL,
> -             .count_cells = of_bus_default_count_cells,
> -             .map = of_bus_default_map,
> -             .translate = of_bus_default_translate,
> -             .get_flags = of_bus_default_get_flags,
> -     },
> -};
> -
> -static struct of_bus *of_match_bus(struct device_node *np)
> -{
> -     int i;
> -
> -     for (i = 0; i < ARRAY_SIZE(of_busses); i++)
> -             if (!of_busses[i].match || of_busses[i].match(np))
> -                     return &of_busses[i];
> -     BUG();
> -     return NULL;
> -}
> -
> -static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> -                     struct of_bus *pbus, u32 *addr,
> -                     int na, int ns, int pna)
> -{
> -     const u32 *ranges;
> -     unsigned int rlen;
> -     int rone;
> -     u64 offset = OF_BAD_ADDR;
> -
> -     /* Normally, an absence of a "ranges" property means we are
> -      * crossing a non-translatable boundary, and thus the addresses
> -      * below the current not cannot be converted to CPU physical ones.
> -      * Unfortunately, while this is very clear in the spec, it's not
> -      * what Apple understood, and they do have things like /uni-n or
> -      * /ht nodes with no "ranges" property and a lot of perfectly
> -      * useable mapped devices below them. Thus we treat the absence of
> -      * "ranges" as equivalent to an empty "ranges" property which means
> -      * a 1:1 translation at that level. It's up to the caller not to try
> -      * to translate addresses that aren't supposed to be translated in
> -      * the first place. --BenH.
> -      */
> -     ranges = of_get_property(parent, "ranges", (int *) &rlen);
> -     if (ranges == NULL || rlen == 0) {
> -             offset = of_read_number(addr, na);
> -             memset(addr, 0, pna * 4);
> -             pr_debug("OF: no ranges, 1:1 translation\n");
> -             goto finish;
> -     }
> -
> -     pr_debug("OF: walking ranges...\n");
> -
> -     /* Now walk through the ranges */
> -     rlen /= 4;
> -     rone = na + pna + ns;
> -     for (; rlen >= rone; rlen -= rone, ranges += rone) {
> -             offset = bus->map(addr, ranges, na, ns, pna);
> -             if (offset != OF_BAD_ADDR)
> -                     break;
> -     }
> -     if (offset == OF_BAD_ADDR) {
> -             pr_debug("OF: not found !\n");
> -             return 1;
> -     }
> -     memcpy(addr, ranges + na, 4 * pna);
> -
> - finish:
> -     of_dump_addr("OF: parent translation for:", addr, pna);
> -     pr_debug("OF: with offset: "PRu64"\n", offset);
> -
> -     /* Translate it into parent bus space */
> -     return pbus->translate(addr, offset, pna);
> -}
> -
> -/*
> - * Translate an address from the device-tree into a CPU physical address,
> - * this walks up the tree and applies the various bus mappings on the
> - * way.
> - *
> - * Note: We consider that crossing any level with #size-cells == 0 to mean
> - * that translation is impossible (that is we are not dealing with a value
> - * that can be mapped to a cpu physical address). This is not really 
> specified
> - * that way, but this is traditionally the way IBM at least do things
> - */
> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
> -{
> -     struct device_node *parent = NULL;
> -     struct of_bus *bus, *pbus;
> -     u32 addr[OF_MAX_ADDR_CELLS];
> -     int na, ns, pna, pns;
> -     u64 result = OF_BAD_ADDR;
> -
> -     pr_debug("OF: ** translation for device %s **\n", dev->full_name);
> -
> -     /* Increase refcount at current level */
> -     of_node_get(dev);
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             goto bail;
> -     bus = of_match_bus(parent);
> -
> -     /* Cound address cells & copy address locally */
> -     bus->count_cells(dev, &na, &ns);
> -     if (!OF_CHECK_COUNTS(na, ns)) {
> -             printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -                     dev->full_name);
> -             goto bail;
> -     }
> -     memcpy(addr, in_addr, na * 4);
> -
> -     pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
> -             bus->name, na, ns, parent->full_name);
> -     of_dump_addr("OF: translating address:", addr, na);
> -
> -     /* Translate */
> -     for (;;) {
> -             /* Switch to parent bus */
> -             of_node_put(dev);
> -             dev = parent;
> -             parent = of_get_parent(dev);
> -
> -             /* If root, we have finished */
> -             if (parent == NULL) {
> -                     pr_debug("OF: reached root node\n");
> -                     result = of_read_number(addr, na);
> -                     break;
> -             }
> -
> -             /* Get new parent bus and counts */
> -             pbus = of_match_bus(parent);
> -             pbus->count_cells(dev, &pna, &pns);
> -             if (!OF_CHECK_COUNTS(pna, pns)) {
> -                     printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -                             dev->full_name);
> -                     break;
> -             }
> -
> -             pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> -                     pbus->name, pna, pns, parent->full_name);
> -
> -             /* Apply bus translation */
> -             if (of_translate_one(dev, bus, pbus, addr, na, ns, pna))
> -                     break;
> -
> -             /* Complete the move up one level */
> -             na = pna;
> -             ns = pns;
> -             bus = pbus;
> -
> -             of_dump_addr("OF: one level translation:", addr, na);
> -     }
> - bail:
> -     of_node_put(parent);
> -     of_node_put(dev);
> -
> -     return result;
> -}
> -EXPORT_SYMBOL(of_translate_address);
> -
> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
> -                     unsigned int *flags)
> -{
> -     const u32 *prop;
> -     unsigned int psize;
> -     struct device_node *parent;
> -     struct of_bus *bus;
> -     int onesize, i, na, ns;
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             return NULL;
> -     bus = of_match_bus(parent);
> -     bus->count_cells(dev, &na, &ns);
> -     of_node_put(parent);
> -     if (!OF_CHECK_COUNTS(na, ns))
> -             return NULL;
> -
> -     /* Get "reg" or "assigned-addresses" property */
> -     prop = of_get_property(dev, bus->addresses, (int *) &psize);
> -     if (prop == NULL)
> -             return NULL;
> -     psize /= 4;
> -
> -     onesize = na + ns;
> -     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -             if (i == index) {
> -                     if (size)
> -                             *size = of_read_number(prop + na, ns);
> -                     if (flags)
> -                             *flags = bus->get_flags(prop);
> -                     return prop;
> -             }
> -     return NULL;
> -}
> -EXPORT_SYMBOL(of_get_address);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>               unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> diff --git a/arch/powerpc/include/asm/prom.h b/arch/powerpc/include/asm/prom.h
> index e1c1bdd..8e1d0fe 100644
> --- a/arch/powerpc/include/asm/prom.h
> +++ b/arch/powerpc/include/asm/prom.h
> @@ -45,10 +45,6 @@ extern void pci_create_OF_bus_map(void);
>   * OF address retreival & translation
>   */
>  
> -/* Translate an OF address block into a CPU physical address
> - */
> -extern u64 of_translate_address(struct device_node *np, const u32 *addr);
> -
>  /* Translate a DMA address from device space to CPU space */
>  extern u64 of_translate_dma_address(struct device_node *dev,
>                                   const u32 *in_addr);
> diff --git a/arch/powerpc/kernel/prom_parse.c 
> b/arch/powerpc/kernel/prom_parse.c
> index a2ef129..64f2606 100644
> --- a/arch/powerpc/kernel/prom_parse.c
> +++ b/arch/powerpc/kernel/prom_parse.c
> @@ -10,225 +10,7 @@
>  #include <asm/prom.h>
>  #include <asm/pci-bridge.h>
>  
> -#ifdef DEBUG
> -#define DBG(fmt...) do { printk(fmt); } while(0)
> -#else
> -#define DBG(fmt...) do { } while(0)
> -#endif
> -
> -#ifdef CONFIG_PPC64
> -#define PRu64        "%lx"
> -#else
> -#define PRu64        "%llx"
> -#endif
> -
> -/* Max address size we deal with */
> -#define OF_MAX_ADDR_CELLS    4
> -#define OF_CHECK_COUNTS(na, ns)      ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS 
> && \
> -                     (ns) > 0)
> -
> -static struct of_bus *of_match_bus(struct device_node *np);
> -
> -/* Debug utility */
> -#ifdef DEBUG
> -static void of_dump_addr(const char *s, const u32 *addr, int na)
> -{
> -     printk("%s", s);
> -     while(na--)
> -             printk(" %08x", *(addr++));
> -     printk("\n");
> -}
> -#else
> -static void of_dump_addr(const char *s, const u32 *addr, int na) { }
> -#endif
> -
> -
> -/* Callbacks for bus specific translators */
> -struct of_bus {
> -     const char      *name;
> -     const char      *addresses;
> -     int             (*match)(struct device_node *parent);
> -     void            (*count_cells)(struct device_node *child,
> -                                    int *addrc, int *sizec);
> -     u64             (*map)(u32 *addr, const u32 *range,
> -                             int na, int ns, int pna);
> -     int             (*translate)(u32 *addr, u64 offset, int na);
> -     unsigned int    (*get_flags)(const u32 *addr);
> -};
> -
> -
> -/*
> - * Default translator (generic bus)
> - */
> -
> -static void of_bus_default_count_cells(struct device_node *dev,
> -                                    int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = of_n_addr_cells(dev);
> -     if (sizec)
> -             *sizec = of_n_size_cells(dev);
> -}
> -
> -static u64 of_bus_default_map(u32 *addr, const u32 *range,
> -             int na, int ns, int pna)
> -{
> -     u64 cp, s, da;
> -
> -     cp = of_read_number(range, na);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr, na);
> -
> -     DBG("OF: default map, cp="PRu64", s="PRu64", da="PRu64"\n",
> -         cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> -{
> -     u64 a = of_read_number(addr, na);
> -     memset(addr, 0, na * 4);
> -     a += offset;
> -     if (na > 1)
> -             addr[na - 2] = a >> 32;
> -     addr[na - 1] = a & 0xffffffffu;
> -
> -     return 0;
> -}
> -
> -static unsigned int of_bus_default_get_flags(const u32 *addr)
> -{
> -     return IORESOURCE_MEM;
> -}
> -
> -
>  #ifdef CONFIG_PCI
> -/*
> - * PCI bus specific translator
> - */
> -
> -static int of_bus_pci_match(struct device_node *np)
> -{
> -     /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> -     return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> -}
> -
> -static void of_bus_pci_count_cells(struct device_node *np,
> -                                int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = 3;
> -     if (sizec)
> -             *sizec = 2;
> -}
> -
> -static unsigned int of_bus_pci_get_flags(const u32 *addr)
> -{
> -     unsigned int flags = 0;
> -     u32 w = addr[0];
> -
> -     switch((w >> 24) & 0x03) {
> -     case 0x01:
> -             flags |= IORESOURCE_IO;
> -             break;
> -     case 0x02: /* 32 bits */
> -     case 0x03: /* 64 bits */
> -             flags |= IORESOURCE_MEM;
> -             break;
> -     }
> -     if (w & 0x40000000)
> -             flags |= IORESOURCE_PREFETCH;
> -     return flags;
> -}
> -
> -static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> -{
> -     u64 cp, s, da;
> -     unsigned int af, rf;
> -
> -     af = of_bus_pci_get_flags(addr);
> -     rf = of_bus_pci_get_flags(range);
> -
> -     /* Check address type match */
> -     if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
> -             return OF_BAD_ADDR;
> -
> -     /* Read address values, skipping high cell */
> -     cp = of_read_number(range + 1, na - 1);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr + 1, na - 1);
> -
> -     DBG("OF: PCI map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> -{
> -     return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
> -                     unsigned int *flags)
> -{
> -     const u32 *prop;
> -     unsigned int psize;
> -     struct device_node *parent;
> -     struct of_bus *bus;
> -     int onesize, i, na, ns;
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             return NULL;
> -     bus = of_match_bus(parent);
> -     if (strcmp(bus->name, "pci")) {
> -             of_node_put(parent);
> -             return NULL;
> -     }
> -     bus->count_cells(dev, &na, &ns);
> -     of_node_put(parent);
> -     if (!OF_CHECK_COUNTS(na, ns))
> -             return NULL;
> -
> -     /* Get "reg" or "assigned-addresses" property */
> -     prop = of_get_property(dev, bus->addresses, &psize);
> -     if (prop == NULL)
> -             return NULL;
> -     psize /= 4;
> -
> -     onesize = na + ns;
> -     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -             if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> -                     if (size)
> -                             *size = of_read_number(prop + na, ns);
> -                     if (flags)
> -                             *flags = bus->get_flags(prop);
> -                     return prop;
> -             }
> -     return NULL;
> -}
> -EXPORT_SYMBOL(of_get_pci_address);
> -
> -int of_pci_address_to_resource(struct device_node *dev, int bar,
> -                            struct resource *r)
> -{
> -     const u32       *addrp;
> -     u64             size;
> -     unsigned int    flags;
> -
> -     addrp = of_get_pci_address(dev, bar, &size, &flags);
> -     if (addrp == NULL)
> -             return -EINVAL;
> -     return __of_address_to_resource(dev, addrp, size, flags, r);
> -}
> -EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
> -
>  int of_irq_map_pci(struct pci_dev *pdev, struct of_irq *out_irq)
>  {
>       struct device_node *dn, *ppnode;
> @@ -310,303 +92,6 @@ int of_irq_map_pci(struct pci_dev *pdev, struct of_irq 
> *out_irq)
>  EXPORT_SYMBOL_GPL(of_irq_map_pci);
>  #endif /* CONFIG_PCI */
>  
> -/*
> - * ISA bus specific translator
> - */
> -
> -static int of_bus_isa_match(struct device_node *np)
> -{
> -     return !strcmp(np->name, "isa");
> -}
> -
> -static void of_bus_isa_count_cells(struct device_node *child,
> -                                int *addrc, int *sizec)
> -{
> -     if (addrc)
> -             *addrc = 2;
> -     if (sizec)
> -             *sizec = 1;
> -}
> -
> -static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> -{
> -     u64 cp, s, da;
> -
> -     /* Check address type match */
> -     if ((addr[0] ^ range[0]) & 0x00000001)
> -             return OF_BAD_ADDR;
> -
> -     /* Read address values, skipping high cell */
> -     cp = of_read_number(range + 1, na - 1);
> -     s  = of_read_number(range + na + pna, ns);
> -     da = of_read_number(addr + 1, na - 1);
> -
> -     DBG("OF: ISA map, cp="PRu64", s="PRu64", da="PRu64"\n", cp, s, da);
> -
> -     if (da < cp || da >= (cp + s))
> -             return OF_BAD_ADDR;
> -     return da - cp;
> -}
> -
> -static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> -{
> -     return of_bus_default_translate(addr + 1, offset, na - 1);
> -}
> -
> -static unsigned int of_bus_isa_get_flags(const u32 *addr)
> -{
> -     unsigned int flags = 0;
> -     u32 w = addr[0];
> -
> -     if (w & 1)
> -             flags |= IORESOURCE_IO;
> -     else
> -             flags |= IORESOURCE_MEM;
> -     return flags;
> -}
> -
> -
> -/*
> - * Array of bus specific translators
> - */
> -
> -static struct of_bus of_busses[] = {
> -#ifdef CONFIG_PCI
> -     /* PCI */
> -     {
> -             .name = "pci",
> -             .addresses = "assigned-addresses",
> -             .match = of_bus_pci_match,
> -             .count_cells = of_bus_pci_count_cells,
> -             .map = of_bus_pci_map,
> -             .translate = of_bus_pci_translate,
> -             .get_flags = of_bus_pci_get_flags,
> -     },
> -#endif /* CONFIG_PCI */
> -     /* ISA */
> -     {
> -             .name = "isa",
> -             .addresses = "reg",
> -             .match = of_bus_isa_match,
> -             .count_cells = of_bus_isa_count_cells,
> -             .map = of_bus_isa_map,
> -             .translate = of_bus_isa_translate,
> -             .get_flags = of_bus_isa_get_flags,
> -     },
> -     /* Default */
> -     {
> -             .name = "default",
> -             .addresses = "reg",
> -             .match = NULL,
> -             .count_cells = of_bus_default_count_cells,
> -             .map = of_bus_default_map,
> -             .translate = of_bus_default_translate,
> -             .get_flags = of_bus_default_get_flags,
> -     },
> -};
> -
> -static struct of_bus *of_match_bus(struct device_node *np)
> -{
> -     int i;
> -
> -     for (i = 0; i < ARRAY_SIZE(of_busses); i ++)
> -             if (!of_busses[i].match || of_busses[i].match(np))
> -                     return &of_busses[i];
> -     BUG();
> -     return NULL;
> -}
> -
> -static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> -                         struct of_bus *pbus, u32 *addr,
> -                         int na, int ns, int pna, const char *rprop)
> -{
> -     const u32 *ranges;
> -     unsigned int rlen;
> -     int rone;
> -     u64 offset = OF_BAD_ADDR;
> -
> -     /* Normally, an absence of a "ranges" property means we are
> -      * crossing a non-translatable boundary, and thus the addresses
> -      * below the current not cannot be converted to CPU physical ones.
> -      * Unfortunately, while this is very clear in the spec, it's not
> -      * what Apple understood, and they do have things like /uni-n or
> -      * /ht nodes with no "ranges" property and a lot of perfectly
> -      * useable mapped devices below them. Thus we treat the absence of
> -      * "ranges" as equivalent to an empty "ranges" property which means
> -      * a 1:1 translation at that level. It's up to the caller not to try
> -      * to translate addresses that aren't supposed to be translated in
> -      * the first place. --BenH.
> -      */
> -     ranges = of_get_property(parent, rprop, &rlen);
> -     if (ranges == NULL || rlen == 0) {
> -             offset = of_read_number(addr, na);
> -             memset(addr, 0, pna * 4);
> -             DBG("OF: no ranges, 1:1 translation\n");
> -             goto finish;
> -     }
> -
> -     DBG("OF: walking ranges...\n");
> -
> -     /* Now walk through the ranges */
> -     rlen /= 4;
> -     rone = na + pna + ns;
> -     for (; rlen >= rone; rlen -= rone, ranges += rone) {
> -             offset = bus->map(addr, ranges, na, ns, pna);
> -             if (offset != OF_BAD_ADDR)
> -                     break;
> -     }
> -     if (offset == OF_BAD_ADDR) {
> -             DBG("OF: not found !\n");
> -             return 1;
> -     }
> -     memcpy(addr, ranges + na, 4 * pna);
> -
> - finish:
> -     of_dump_addr("OF: parent translation for:", addr, pna);
> -     DBG("OF: with offset: "PRu64"\n", offset);
> -
> -     /* Translate it into parent bus space */
> -     return pbus->translate(addr, offset, pna);
> -}
> -
> -
> -/*
> - * Translate an address from the device-tree into a CPU physical address,
> - * this walks up the tree and applies the various bus mappings on the
> - * way.
> - *
> - * Note: We consider that crossing any level with #size-cells == 0 to mean
> - * that translation is impossible (that is we are not dealing with a value
> - * that can be mapped to a cpu physical address). This is not really 
> specified
> - * that way, but this is traditionally the way IBM at least do things
> - */
> -u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
> -                        const char *rprop)
> -{
> -     struct device_node *parent = NULL;
> -     struct of_bus *bus, *pbus;
> -     u32 addr[OF_MAX_ADDR_CELLS];
> -     int na, ns, pna, pns;
> -     u64 result = OF_BAD_ADDR;
> -
> -     DBG("OF: ** translation for device %s **\n", dev->full_name);
> -
> -     /* Increase refcount at current level */
> -     of_node_get(dev);
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             goto bail;
> -     bus = of_match_bus(parent);
> -
> -     /* Cound address cells & copy address locally */
> -     bus->count_cells(dev, &na, &ns);
> -     if (!OF_CHECK_COUNTS(na, ns)) {
> -             printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -                    dev->full_name);
> -             goto bail;
> -     }
> -     memcpy(addr, in_addr, na * 4);
> -
> -     DBG("OF: bus is %s (na=%d, ns=%d) on %s\n",
> -         bus->name, na, ns, parent->full_name);
> -     of_dump_addr("OF: translating address:", addr, na);
> -
> -     /* Translate */
> -     for (;;) {
> -             /* Switch to parent bus */
> -             of_node_put(dev);
> -             dev = parent;
> -             parent = of_get_parent(dev);
> -
> -             /* If root, we have finished */
> -             if (parent == NULL) {
> -                     DBG("OF: reached root node\n");
> -                     result = of_read_number(addr, na);
> -                     break;
> -             }
> -
> -             /* Get new parent bus and counts */
> -             pbus = of_match_bus(parent);
> -             pbus->count_cells(dev, &pna, &pns);
> -             if (!OF_CHECK_COUNTS(pna, pns)) {
> -                     printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> -                            dev->full_name);
> -                     break;
> -             }
> -
> -             DBG("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> -                 pbus->name, pna, pns, parent->full_name);
> -
> -             /* Apply bus translation */
> -             if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
> -                     break;
> -
> -             /* Complete the move up one level */
> -             na = pna;
> -             ns = pns;
> -             bus = pbus;
> -
> -             of_dump_addr("OF: one level translation:", addr, na);
> -     }
> - bail:
> -     of_node_put(parent);
> -     of_node_put(dev);
> -
> -     return result;
> -}
> -
> -u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
> -{
> -     return __of_translate_address(dev, in_addr, "ranges");
> -}
> -EXPORT_SYMBOL(of_translate_address);
> -
> -u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
> -{
> -     return __of_translate_address(dev, in_addr, "dma-ranges");
> -}
> -EXPORT_SYMBOL(of_translate_dma_address);
> -
> -const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
> -                 unsigned int *flags)
> -{
> -     const u32 *prop;
> -     unsigned int psize;
> -     struct device_node *parent;
> -     struct of_bus *bus;
> -     int onesize, i, na, ns;
> -
> -     /* Get parent & match bus type */
> -     parent = of_get_parent(dev);
> -     if (parent == NULL)
> -             return NULL;
> -     bus = of_match_bus(parent);
> -     bus->count_cells(dev, &na, &ns);
> -     of_node_put(parent);
> -     if (!OF_CHECK_COUNTS(na, ns))
> -             return NULL;
> -
> -     /* Get "reg" or "assigned-addresses" property */
> -     prop = of_get_property(dev, bus->addresses, &psize);
> -     if (prop == NULL)
> -             return NULL;
> -     psize /= 4;
> -
> -     onesize = na + ns;
> -     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> -             if (i == index) {
> -                     if (size)
> -                             *size = of_read_number(prop + na, ns);
> -                     if (flags)
> -                             *flags = bus->get_flags(prop);
> -                     return prop;
> -             }
> -     return NULL;
> -}
> -EXPORT_SYMBOL(of_get_address);
> -
>  void of_parse_dma_window(struct device_node *dn, const void *dma_window_prop,
>               unsigned long *busno, unsigned long *phys, unsigned long *size)
>  {
> diff --git a/drivers/of/address.c b/drivers/of/address.c
> index c381955..2a905d5 100644
> --- a/drivers/of/address.c
> +++ b/drivers/of/address.c
> @@ -1,11 +1,522 @@
>  
>  #include <linux/io.h>
>  #include <linux/ioport.h>
> +#include <linux/module.h>
>  #include <linux/of_address.h>
> +#include <linux/pci_regs.h>
> +#include <linux/string.h>
>  
> -int __of_address_to_resource(struct device_node *dev, const u32 *addrp,
> -                          u64 size, unsigned int flags,
> -                          struct resource *r)
> +/* Max address size we deal with */
> +#define OF_MAX_ADDR_CELLS    4
> +#define OF_CHECK_COUNTS(na, ns)      ((na) > 0 && (na) <= OF_MAX_ADDR_CELLS 
> && \
> +                     (ns) > 0)
> +
> +static struct of_bus *of_match_bus(struct device_node *np);
> +static int __of_address_to_resource(struct device_node *dev, const u32 
> *addrp,
> +                                 u64 size, unsigned int flags,
> +                                 struct resource *r);
> +
> +/* Debug utility */
> +#ifdef DEBUG
> +static void of_dump_addr(const char *s, const u32 *addr, int na)
> +{
> +     printk(KERN_DEBUG "%s", s);
> +     while (na--)
> +             printk(" %08x", *(addr++));
> +     printk("\n");
> +}
> +#else
> +static void of_dump_addr(const char *s, const u32 *addr, int na) { }
> +#endif
> +
> +/* Callbacks for bus specific translators */
> +struct of_bus {
> +     const char      *name;
> +     const char      *addresses;
> +     int             (*match)(struct device_node *parent);
> +     void            (*count_cells)(struct device_node *child,
> +                                    int *addrc, int *sizec);
> +     u64             (*map)(u32 *addr, const u32 *range,
> +                             int na, int ns, int pna);
> +     int             (*translate)(u32 *addr, u64 offset, int na);
> +     unsigned int    (*get_flags)(const u32 *addr);
> +};
> +
> +/*
> + * Default translator (generic bus)
> + */
> +
> +static void of_bus_default_count_cells(struct device_node *dev,
> +                                    int *addrc, int *sizec)
> +{
> +     if (addrc)
> +             *addrc = of_n_addr_cells(dev);
> +     if (sizec)
> +             *sizec = of_n_size_cells(dev);
> +}
> +
> +static u64 of_bus_default_map(u32 *addr, const u32 *range,
> +             int na, int ns, int pna)
> +{
> +     u64 cp, s, da;
> +
> +     cp = of_read_number(range, na);
> +     s  = of_read_number(range + na + pna, ns);
> +     da = of_read_number(addr, na);
> +
> +     pr_debug("OF: default map, cp=%llx, s=%llx, da=%llx\n",
> +              (unsigned long long)cp, (unsigned long long)s,
> +              (unsigned long long)da);
> +
> +     if (da < cp || da >= (cp + s))
> +             return OF_BAD_ADDR;
> +     return da - cp;
> +}
> +
> +static int of_bus_default_translate(u32 *addr, u64 offset, int na)
> +{
> +     u64 a = of_read_number(addr, na);
> +     memset(addr, 0, na * 4);
> +     a += offset;
> +     if (na > 1)
> +             addr[na - 2] = a >> 32;
> +     addr[na - 1] = a & 0xffffffffu;
> +
> +     return 0;
> +}
> +
> +static unsigned int of_bus_default_get_flags(const u32 *addr)
> +{
> +     return IORESOURCE_MEM;
> +}
> +
> +#ifdef CONFIG_PCI
> +/*
> + * PCI bus specific translator
> + */
> +
> +static int of_bus_pci_match(struct device_node *np)
> +{
> +     /* "vci" is for the /chaos bridge on 1st-gen PCI powermacs */
> +     return !strcmp(np->type, "pci") || !strcmp(np->type, "vci");
> +}
> +
> +static void of_bus_pci_count_cells(struct device_node *np,
> +                                int *addrc, int *sizec)
> +{
> +     if (addrc)
> +             *addrc = 3;
> +     if (sizec)
> +             *sizec = 2;
> +}
> +
> +static unsigned int of_bus_pci_get_flags(const u32 *addr)
> +{
> +     unsigned int flags = 0;
> +     u32 w = addr[0];
> +
> +     switch((w >> 24) & 0x03) {
> +     case 0x01:
> +             flags |= IORESOURCE_IO;
> +             break;
> +     case 0x02: /* 32 bits */
> +     case 0x03: /* 64 bits */
> +             flags |= IORESOURCE_MEM;
> +             break;
> +     }
> +     if (w & 0x40000000)
> +             flags |= IORESOURCE_PREFETCH;
> +     return flags;
> +}
> +
> +static u64 of_bus_pci_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> +{
> +     u64 cp, s, da;
> +     unsigned int af, rf;
> +
> +     af = of_bus_pci_get_flags(addr);
> +     rf = of_bus_pci_get_flags(range);
> +
> +     /* Check address type match */
> +     if ((af ^ rf) & (IORESOURCE_MEM | IORESOURCE_IO))
> +             return OF_BAD_ADDR;
> +
> +     /* Read address values, skipping high cell */
> +     cp = of_read_number(range + 1, na - 1);
> +     s  = of_read_number(range + na + pna, ns);
> +     da = of_read_number(addr + 1, na - 1);
> +
> +     pr_debug("OF: PCI map, cp=%llx, s=%llx, da=%llx\n",
> +              (unsigned long long)cp, (unsigned long long)s,
> +              (unsigned long long)da);
> +
> +     if (da < cp || da >= (cp + s))
> +             return OF_BAD_ADDR;
> +     return da - cp;
> +}
> +
> +static int of_bus_pci_translate(u32 *addr, u64 offset, int na)
> +{
> +     return of_bus_default_translate(addr + 1, offset, na - 1);
> +}
> +
> +const u32 *of_get_pci_address(struct device_node *dev, int bar_no, u64 *size,
> +                     unsigned int *flags)
> +{
> +     const u32 *prop;
> +     unsigned int psize;
> +     struct device_node *parent;
> +     struct of_bus *bus;
> +     int onesize, i, na, ns;
> +
> +     /* Get parent & match bus type */
> +     parent = of_get_parent(dev);
> +     if (parent == NULL)
> +             return NULL;
> +     bus = of_match_bus(parent);
> +     if (strcmp(bus->name, "pci")) {
> +             of_node_put(parent);
> +             return NULL;
> +     }
> +     bus->count_cells(dev, &na, &ns);
> +     of_node_put(parent);
> +     if (!OF_CHECK_COUNTS(na, ns))
> +             return NULL;
> +
> +     /* Get "reg" or "assigned-addresses" property */
> +     prop = of_get_property(dev, bus->addresses, &psize);
> +     if (prop == NULL)
> +             return NULL;
> +     psize /= 4;
> +
> +     onesize = na + ns;
> +     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> +             if ((prop[0] & 0xff) == ((bar_no * 4) + PCI_BASE_ADDRESS_0)) {
> +                     if (size)
> +                             *size = of_read_number(prop + na, ns);
> +                     if (flags)
> +                             *flags = bus->get_flags(prop);
> +                     return prop;
> +             }
> +     return NULL;
> +}
> +EXPORT_SYMBOL(of_get_pci_address);
> +
> +int of_pci_address_to_resource(struct device_node *dev, int bar,
> +                            struct resource *r)
> +{
> +     const u32       *addrp;
> +     u64             size;
> +     unsigned int    flags;
> +
> +     addrp = of_get_pci_address(dev, bar, &size, &flags);
> +     if (addrp == NULL)
> +             return -EINVAL;
> +     return __of_address_to_resource(dev, addrp, size, flags, r);
> +}
> +EXPORT_SYMBOL_GPL(of_pci_address_to_resource);
> +#endif /* CONFIG_PCI */
> +
> +/*
> + * ISA bus specific translator
> + */
> +
> +static int of_bus_isa_match(struct device_node *np)
> +{
> +     return !strcmp(np->name, "isa");
> +}
> +
> +static void of_bus_isa_count_cells(struct device_node *child,
> +                                int *addrc, int *sizec)
> +{
> +     if (addrc)
> +             *addrc = 2;
> +     if (sizec)
> +             *sizec = 1;
> +}
> +
> +static u64 of_bus_isa_map(u32 *addr, const u32 *range, int na, int ns, int 
> pna)
> +{
> +     u64 cp, s, da;
> +
> +     /* Check address type match */
> +     if ((addr[0] ^ range[0]) & 0x00000001)
> +             return OF_BAD_ADDR;
> +
> +     /* Read address values, skipping high cell */
> +     cp = of_read_number(range + 1, na - 1);
> +     s  = of_read_number(range + na + pna, ns);
> +     da = of_read_number(addr + 1, na - 1);
> +
> +     pr_debug("OF: ISA map, cp=%llx, s=%llx, da=%llx\n",
> +              (unsigned long long)cp, (unsigned long long)s,
> +              (unsigned long long)da);
> +
> +     if (da < cp || da >= (cp + s))
> +             return OF_BAD_ADDR;
> +     return da - cp;
> +}
> +
> +static int of_bus_isa_translate(u32 *addr, u64 offset, int na)
> +{
> +     return of_bus_default_translate(addr + 1, offset, na - 1);
> +}
> +
> +static unsigned int of_bus_isa_get_flags(const u32 *addr)
> +{
> +     unsigned int flags = 0;
> +     u32 w = addr[0];
> +
> +     if (w & 1)
> +             flags |= IORESOURCE_IO;
> +     else
> +             flags |= IORESOURCE_MEM;
> +     return flags;
> +}
> +
> +/*
> + * Array of bus specific translators
> + */
> +
> +static struct of_bus of_busses[] = {
> +#ifdef CONFIG_PCI
> +     /* PCI */
> +     {
> +             .name = "pci",
> +             .addresses = "assigned-addresses",
> +             .match = of_bus_pci_match,
> +             .count_cells = of_bus_pci_count_cells,
> +             .map = of_bus_pci_map,
> +             .translate = of_bus_pci_translate,
> +             .get_flags = of_bus_pci_get_flags,
> +     },
> +#endif /* CONFIG_PCI */
> +     /* ISA */
> +     {
> +             .name = "isa",
> +             .addresses = "reg",
> +             .match = of_bus_isa_match,
> +             .count_cells = of_bus_isa_count_cells,
> +             .map = of_bus_isa_map,
> +             .translate = of_bus_isa_translate,
> +             .get_flags = of_bus_isa_get_flags,
> +     },
> +     /* Default */
> +     {
> +             .name = "default",
> +             .addresses = "reg",
> +             .match = NULL,
> +             .count_cells = of_bus_default_count_cells,
> +             .map = of_bus_default_map,
> +             .translate = of_bus_default_translate,
> +             .get_flags = of_bus_default_get_flags,
> +     },
> +};
> +
> +static struct of_bus *of_match_bus(struct device_node *np)
> +{
> +     int i;
> +
> +     for (i = 0; i < ARRAY_SIZE(of_busses); i++)
> +             if (!of_busses[i].match || of_busses[i].match(np))
> +                     return &of_busses[i];
> +     BUG();
> +     return NULL;
> +}
> +
> +static int of_translate_one(struct device_node *parent, struct of_bus *bus,
> +                         struct of_bus *pbus, u32 *addr,
> +                         int na, int ns, int pna, const char *rprop)
> +{
> +     const u32 *ranges;
> +     unsigned int rlen;
> +     int rone;
> +     u64 offset = OF_BAD_ADDR;
> +
> +     /* Normally, an absence of a "ranges" property means we are
> +      * crossing a non-translatable boundary, and thus the addresses
> +      * below the current not cannot be converted to CPU physical ones.
> +      * Unfortunately, while this is very clear in the spec, it's not
> +      * what Apple understood, and they do have things like /uni-n or
> +      * /ht nodes with no "ranges" property and a lot of perfectly
> +      * useable mapped devices below them. Thus we treat the absence of
> +      * "ranges" as equivalent to an empty "ranges" property which means
> +      * a 1:1 translation at that level. It's up to the caller not to try
> +      * to translate addresses that aren't supposed to be translated in
> +      * the first place. --BenH.
> +      */
> +     ranges = of_get_property(parent, rprop, &rlen);
> +     if (ranges == NULL || rlen == 0) {
> +             offset = of_read_number(addr, na);
> +             memset(addr, 0, pna * 4);
> +             pr_debug("OF: no ranges, 1:1 translation\n");
> +             goto finish;
> +     }
> +
> +     pr_debug("OF: walking ranges...\n");
> +
> +     /* Now walk through the ranges */
> +     rlen /= 4;
> +     rone = na + pna + ns;
> +     for (; rlen >= rone; rlen -= rone, ranges += rone) {
> +             offset = bus->map(addr, ranges, na, ns, pna);
> +             if (offset != OF_BAD_ADDR)
> +                     break;
> +     }
> +     if (offset == OF_BAD_ADDR) {
> +             pr_debug("OF: not found !\n");
> +             return 1;
> +     }
> +     memcpy(addr, ranges + na, 4 * pna);
> +
> + finish:
> +     of_dump_addr("OF: parent translation for:", addr, pna);
> +     pr_debug("OF: with offset: %llx\n", (unsigned long long)offset);
> +
> +     /* Translate it into parent bus space */
> +     return pbus->translate(addr, offset, pna);
> +}
> +
> +/*
> + * Translate an address from the device-tree into a CPU physical address,
> + * this walks up the tree and applies the various bus mappings on the
> + * way.
> + *
> + * Note: We consider that crossing any level with #size-cells == 0 to mean
> + * that translation is impossible (that is we are not dealing with a value
> + * that can be mapped to a cpu physical address). This is not really 
> specified
> + * that way, but this is traditionally the way IBM at least do things
> + */
> +u64 __of_translate_address(struct device_node *dev, const u32 *in_addr,
> +                        const char *rprop)
> +{
> +     struct device_node *parent = NULL;
> +     struct of_bus *bus, *pbus;
> +     u32 addr[OF_MAX_ADDR_CELLS];
> +     int na, ns, pna, pns;
> +     u64 result = OF_BAD_ADDR;
> +
> +     pr_debug("OF: ** translation for device %s **\n", dev->full_name);
> +
> +     /* Increase refcount at current level */
> +     of_node_get(dev);
> +
> +     /* Get parent & match bus type */
> +     parent = of_get_parent(dev);
> +     if (parent == NULL)
> +             goto bail;
> +     bus = of_match_bus(parent);
> +
> +     /* Cound address cells & copy address locally */
> +     bus->count_cells(dev, &na, &ns);
> +     if (!OF_CHECK_COUNTS(na, ns)) {
> +             printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> +                    dev->full_name);
> +             goto bail;
> +     }
> +     memcpy(addr, in_addr, na * 4);
> +
> +     pr_debug("OF: bus is %s (na=%d, ns=%d) on %s\n",
> +         bus->name, na, ns, parent->full_name);
> +     of_dump_addr("OF: translating address:", addr, na);
> +
> +     /* Translate */
> +     for (;;) {
> +             /* Switch to parent bus */
> +             of_node_put(dev);
> +             dev = parent;
> +             parent = of_get_parent(dev);
> +
> +             /* If root, we have finished */
> +             if (parent == NULL) {
> +                     pr_debug("OF: reached root node\n");
> +                     result = of_read_number(addr, na);
> +                     break;
> +             }
> +
> +             /* Get new parent bus and counts */
> +             pbus = of_match_bus(parent);
> +             pbus->count_cells(dev, &pna, &pns);
> +             if (!OF_CHECK_COUNTS(pna, pns)) {
> +                     printk(KERN_ERR "prom_parse: Bad cell count for %s\n",
> +                            dev->full_name);
> +                     break;
> +             }
> +
> +             pr_debug("OF: parent bus is %s (na=%d, ns=%d) on %s\n",
> +                 pbus->name, pna, pns, parent->full_name);
> +
> +             /* Apply bus translation */
> +             if (of_translate_one(dev, bus, pbus, addr, na, ns, pna, rprop))
> +                     break;
> +
> +             /* Complete the move up one level */
> +             na = pna;
> +             ns = pns;
> +             bus = pbus;
> +
> +             of_dump_addr("OF: one level translation:", addr, na);
> +     }
> + bail:
> +     of_node_put(parent);
> +     of_node_put(dev);
> +
> +     return result;
> +}
> +
> +u64 of_translate_address(struct device_node *dev, const u32 *in_addr)
> +{
> +     return __of_translate_address(dev, in_addr, "ranges");
> +}
> +EXPORT_SYMBOL(of_translate_address);
> +
> +u64 of_translate_dma_address(struct device_node *dev, const u32 *in_addr)
> +{
> +     return __of_translate_address(dev, in_addr, "dma-ranges");
> +}
> +EXPORT_SYMBOL(of_translate_dma_address);
> +
> +const u32 *of_get_address(struct device_node *dev, int index, u64 *size,
> +                 unsigned int *flags)
> +{
> +     const u32 *prop;
> +     unsigned int psize;
> +     struct device_node *parent;
> +     struct of_bus *bus;
> +     int onesize, i, na, ns;
> +
> +     /* Get parent & match bus type */
> +     parent = of_get_parent(dev);
> +     if (parent == NULL)
> +             return NULL;
> +     bus = of_match_bus(parent);
> +     bus->count_cells(dev, &na, &ns);
> +     of_node_put(parent);
> +     if (!OF_CHECK_COUNTS(na, ns))
> +             return NULL;
> +
> +     /* Get "reg" or "assigned-addresses" property */
> +     prop = of_get_property(dev, bus->addresses, &psize);
> +     if (prop == NULL)
> +             return NULL;
> +     psize /= 4;
> +
> +     onesize = na + ns;
> +     for (i = 0; psize >= onesize; psize -= onesize, prop += onesize, i++)
> +             if (i == index) {
> +                     if (size)
> +                             *size = of_read_number(prop + na, ns);
> +                     if (flags)
> +                             *flags = bus->get_flags(prop);
> +                     return prop;
> +             }
> +     return NULL;
> +}
> +EXPORT_SYMBOL(of_get_address);
> +
> +static int __of_address_to_resource(struct device_node *dev, const u32 
> *addrp,
> +                                 u64 size, unsigned int flags,
> +                                 struct resource *r)
>  {
>       u64 taddr;
>  
> diff --git a/include/linux/of_address.h b/include/linux/of_address.h
> index 474b794..cc567df 100644
> --- a/include/linux/of_address.h
> +++ b/include/linux/of_address.h
> @@ -3,9 +3,7 @@
>  #include <linux/ioport.h>
>  #include <linux/of.h>
>  
> -extern int __of_address_to_resource(struct device_node *dev, const u32 
> *addrp,
> -                                 u64 size, unsigned int flags,
> -                                 struct resource *r);
> +extern u64 of_translate_address(struct device_node *np, const u32 *addr);
>  extern int of_address_to_resource(struct device_node *dev, int index,
>                                 struct resource *r);
>  extern void __iomem *of_iomap(struct device_node *device, int index);


_______________________________________________
Linuxppc-dev mailing list
Linuxppc-dev@lists.ozlabs.org
https://lists.ozlabs.org/listinfo/linuxppc-dev

Reply via email to