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

Benjamin Herrenschmidt benh at kernel.crashing.org
Thu Jun 10 16:43:32 EST 2010


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.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);




More information about the Linuxppc-dev mailing list