[PATCH 3/5] of/address: Merge all of the bus translation code

Grant Likely grant.likely at secretlab.ca
Fri Jun 11 00:26:32 EST 2010


On Thu, Jun 10, 2010 at 12:43 AM, Benjamin Herrenschmidt
<benh at kernel.crashing.org> wrote:
> 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 ?

Purely cosmetic IIRC, but I will go back and double check.  Things
like printk vs. pr_info and some style differences.  I looked at them
side-by-side and fixed each difference individually until they were
identical.

>> 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.likely at secretlab.ca>
>> CC: Michal Simek <monstr at monstr.eu>
>> CC: Wolfram Sang <w.sang at pengutronix.de>
>> CC: Stephen Rothwell <sfr at canb.auug.org.au>
>> CC: Benjamin Herrenschmidt <benh at kernel.crashing.org>
>> CC: microblaze-uclinux at itee.uq.edu.au
>> CC: linuxppc-dev at 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);
>
>
>



-- 
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.


More information about the Linuxppc-dev mailing list