From: Scott Wood <scottwood-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
To: Rob Herring <robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
Cc: devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org,
Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>,
Grant Likely
<grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>,
Kim Phillips
<kim.phillips-KZfg59tc24xl57MIdRCFDg@public.gmane.org>,
Kumar Gala
<galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>,
Benjamin Herrenschmidt
<benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
Subject: Re: [PATCH] libfdt: add address translation support
Date: Tue, 1 Apr 2014 18:02:38 -0500 [thread overview]
Message-ID: <1396393358.32034.40.camel@snotra.buserror.net> (raw)
In-Reply-To: <1396371463-7516-1-git-send-email-robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
On Tue, 2014-04-01 at 11:57 -0500, Rob Herring wrote:
> From: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
>
> Add FDT based address translation. Currently, only simple bus
> translations are supported, but the framework allows adding other
> buses like PCI. Adding this to libfdt allows the address
> translation code to be shared amongst u-boot, Linux kernel and other
> projects.
>
> This code is based on GPL only licensed code. It must first be
> re-licensed for dual GPL/BSD to add to libfdt which requires approval
> from the copyright holders.
>
> This code is copied from u-boot common/fdt_support.c. The portion used
> here was originally added to u-boot by Kumar Gala in 2010 and Freescale
> is the copyright holder. Later changes have also only been done by
> Freescale authors. The u-boot code appears to have been copied from the
> Linux kernel's address translation code in drivers/of/address.c which
> has no copyright. This code was moved by Grant Likely in 2010 and
> originated from arch/powerpc/kernel/prom_parse.c which was written by
> Ben Herrenschmidt. Who is the copyright holder on a file in the kernel
> with no copyright? Does this default to the author or Linus or nobody?
ACK for the Freescale contribution (on copyright issues, not technical -- see below).
FWIW, if you have trouble tracking everyone down for this code, there's
address translation code in arch/powerpc/boot/devtree.c that has a
cleaner history (I wrote it from scratch, and there's been only minor
modifications since then, by Mark Greer).
> Signed-off-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: Grant Likely <grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org>
> Cc: Scott Wood <scottwood-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> Cc: Kim Phillips <kim.phillips-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
> Cc: Kumar Gala <galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
> Cc: Benjamin Herrenschmidt <benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org>
> ---
> libfdt/fdt_ro.c | 203 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
> libfdt/libfdt.h | 4 ++
> 2 files changed, 207 insertions(+)
>
> diff --git a/libfdt/fdt_ro.c b/libfdt/fdt_ro.c
> index 50007f6..3c1bde1 100644
> --- a/libfdt/fdt_ro.c
> +++ b/libfdt/fdt_ro.c
> @@ -571,3 +571,206 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
>
> return offset; /* error from fdt_next_node() */
> }
> +
> +/* 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)
> +
> +/* Helper to read a big number; size is in cells (not bytes) */
> +static uint64_t fdt_read_number(const fdt32_t *cell, int size)
> +{
> + uint64_t r = 0;
> + while (size--)
> + r = (r << 32) | fdt32_to_cpu(*(cell++));
> + return r;
> +}
> +
> +/* Callbacks for bus specific translators */
> +struct of_bus {
> + void (*count_cells)(void *blob, int parentoffset,
> + int *addrc, int *sizec);
> + uint64_t (*map)(fdt32_t *addr, const fdt32_t *range,
> + int na, int ns, int pna);
> + int (*translate)(fdt32_t *addr, uint64_t offset, int na);
> +};
> +
> +/* Default translator (generic bus) */
> +static void fdt_bus_default_count_cells(void *blob, int parentoffset,
> + int *addrc, int *sizec)
> +{
> + const fdt32_t *prop;
> +
> + if (addrc) {
> + prop = fdt_getprop(blob, parentoffset, "#address-cells", NULL);
> + if (prop)
> + *addrc = fdt32_to_cpu(*prop);
> + else
> + *addrc = 2;
> + }
> +
> + if (sizec) {
> + prop = fdt_getprop(blob, parentoffset, "#size-cells", NULL);
> + if (prop)
> + *sizec = fdt32_to_cpu(*prop);
> + else
> + *sizec = 2;
> + }
> +}
#size-cells should default to 1 as per IEEE1275 (ePAPR agrees, though
it calls a missing #size-cells non-compliant). This is also what
kernel code currently seems to do (see OF_ROOT_NODE_SIZE_CELLS_DEFAULT).
> +static uint64_t fdt_bus_default_map(fdt32_t *addr, const fdt32_t *range,
> + int na, int ns, int pna)
> +{
> + uint64_t cp, s, da;
> +
> + cp = fdt_read_number(range, na);
> + s = fdt_read_number(range + na + pna, ns);
> + da = fdt_read_number(addr, na);
> +
> + if (da < cp || da >= (cp + s))
> + return FDT_BAD_ADDR;
> + return da - cp;
> +}
> +
> +static int fdt_bus_default_translate(fdt32_t *addr, uint64_t offset, int na)
> +{
> + uint64_t a = fdt_read_number(addr, na);
> + memset(addr, 0, na * 4);
> + a += offset;
> + if (na > 1)
> + addr[na - 2] = cpu_to_fdt32(a >> 32);
> + addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu);
> +
> + return 0;
> +}
> +
> +/* Array of bus specific translators */
> +static const struct of_bus of_busses[] = {
> + /* Default */
> + {
> + .count_cells = fdt_bus_default_count_cells,
> + .map = fdt_bus_default_map,
> + .translate = fdt_bus_default_translate,
> + },
> +};
> +
> +static int fdt_translate_one(void * blob, int parent,
> + const struct of_bus *bus,
> + const struct of_bus *pbus, fdt32_t *addr,
> + int na, int ns, int pna, const char *rprop)
> +{
> + const fdt32_t *ranges;
> + int rlen;
> + int rone;
> + uint64_t offset = FDT_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.
> + */
I don't think libfdt should be copying a non-compliant hack that was
meant to deal with broken Apple firmware that doesn't use flat trees.
-Scott
> + ranges = fdt_getprop(blob, parent, rprop, &rlen);
> + if (ranges == NULL || rlen == 0) {
> + offset = fdt_read_number(addr, na);
> + memset(addr, 0, pna * 4);
> + goto finish;
> + }
> +
> + /* 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 != FDT_BAD_ADDR)
> + break;
> + }
> + if (offset == FDT_BAD_ADDR)
> + return -FDT_ERR_NOTFOUND;
> +
> + memcpy(addr, ranges + na, 4 * pna);
> +
> + finish:
> + /* Translate it into parent bus space */
> + return pbus->translate(addr, offset, pna);
> +}
> +
> +static uint64_t __fdt_translate_address(void *blob, int node_offset,
> + const char *rprop)
> +{
> + int parent, len;
> + const struct of_bus *bus, *pbus;
> + const fdt32_t *reg;
> + fdt32_t addr[OF_MAX_ADDR_CELLS];
> + int na, ns, pna, pns;
> + uint64_t result = FDT_BAD_ADDR;
> +
> + reg = fdt_getprop(blob, node_offset, "reg", &len);
> + if (!reg)
> + goto bail;
> +
> + /* Get parent & match bus type */
> + parent = fdt_parent_offset(blob, node_offset);
> + if (parent < 0)
> + goto bail;
> + bus = &of_busses[0];
> +
> + /* Cound address cells & copy address locally */
> + bus->count_cells(blob, parent, &na, &ns);
> + if (!OF_CHECK_COUNTS(na, ns))
> + goto bail;
> +
> + memcpy(addr, reg, na * 4);
> +
> + /* Translate */
> + for (;;) {
> + /* Switch to parent bus */
> + node_offset = parent;
> + parent = fdt_parent_offset(blob, node_offset);
> +
> + /* If root, we have finished */
> + if (parent < 0) {
> + result = fdt_read_number(addr, na);
> + break;
> + }
> +
> + /* Get new parent bus and counts */
> + pbus = &of_busses[0];
> + pbus->count_cells(blob, parent, &pna, &pns);
> + if (!OF_CHECK_COUNTS(pna, pns))
> + break;
> +
> + /* Apply bus translation */
> + if (fdt_translate_one(blob, node_offset, bus, pbus,
> + addr, na, ns, pna, "ranges"))
> + break;
> +
> + /* Complete the move up one level */
> + na = pna;
> + ns = pns;
> + bus = pbus;
> + }
> + bail:
> + return result;
> +}
> +
> +/*
> + * 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
> + */
> +uint64_t fdt_translate_address(void *fdt, int node_offset)
> +{
> + return __fdt_translate_address(fdt, node_offset, "ranges");
> +}
> diff --git a/libfdt/libfdt.h b/libfdt/libfdt.h
> index c4d5a91..afbea65 100644
> --- a/libfdt/libfdt.h
> +++ b/libfdt/libfdt.h
> @@ -118,6 +118,8 @@
>
> #define FDT_ERR_MAX 13
>
> +#define FDT_BAD_ADDR ((uint64_t)-1)
> +
> /**********************************************************************/
> /* Low-level functions (you probably don't need these) */
> /**********************************************************************/
> @@ -852,6 +854,8 @@ int fdt_node_offset_by_compatible(const void *fdt, int startoffset,
> */
> int fdt_stringlist_contains(const char *strlist, int listlen, const char *str);
>
> +uint64_t fdt_translate_address(void *blob, int node_offset);
> +
> /**********************************************************************/
> /* Write-in-place functions */
> /**********************************************************************/
--
To unsubscribe from this list: send the line "unsubscribe devicetree-compiler" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
next prev parent reply other threads:[~2014-04-01 23:02 UTC|newest]
Thread overview: 22+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-04-01 16:57 [PATCH] libfdt: add address translation support Rob Herring
[not found] ` <1396371463-7516-1-git-send-email-robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org>
2014-04-01 18:59 ` Warner Losh
[not found] ` <4073722A-7162-4041-B1A2-8A992871FEC0-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2014-04-02 5:43 ` David Gibson
[not found] ` <20140402054325.GC3496-1s0os16eZneny3qCrzbmXA@public.gmane.org>
2014-04-02 14:53 ` Warner Losh
[not found] ` <AB306DF0-D50C-476A-8314-CFCE5C57BB2E-uzTCJ5RojNnQT0dZR+AlfA@public.gmane.org>
2014-04-02 23:37 ` David Gibson
2014-04-01 23:02 ` Scott Wood [this message]
[not found] ` <1396393358.32034.40.camel-88ow+0ZRuxG2UiBs7uKeOtHuzzzSOjJt@public.gmane.org>
2014-04-02 19:24 ` Kim Phillips
[not found] ` <20140402142403.9d3316f14520252a4a3474e0-KZfg59tc24xl57MIdRCFDg@public.gmane.org>
2014-04-02 21:01 ` Rob Herring
2014-04-15 14:03 ` Rob Herring
[not found] ` <CAL_JsqKMUHiPeU7iQDHZ=E6GzMxvXBB4L8Arg+m0JrfQsRkhtg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-28 18:12 ` Rob Herring
2014-04-15 21:57 ` Grant Likely
[not found] ` <CACxGe6uPerPT_cT+p1zvL20ERwuguDJWDHasxz5gAUe5kPQHNg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-04-15 22:55 ` Rob Herring
2014-05-12 6:00 ` David Gibson
2014-05-12 6:10 ` Benjamin Herrenschmidt
2014-05-12 6:14 ` Benjamin Herrenschmidt
2014-05-14 4:19 ` David Gibson
2014-05-12 19:27 ` Rob Herring
[not found] ` <CAL_Jsq+zi72PAjQ+RGvUddLtHocgphPQQ9x2X0S0dYGOKz+Hgg-JsoAwUIsXosN+BqQ9rBEUg@public.gmane.org>
2014-05-12 22:01 ` Benjamin Herrenschmidt
2014-05-14 4:20 ` David Gibson
2014-05-14 4:18 ` David Gibson
2014-05-14 5:23 ` Benjamin Herrenschmidt
2014-05-14 6:51 ` David Gibson
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1396393358.32034.40.camel@snotra.buserror.net \
--to=scottwood-kzfg59tc24xl57midrcfdg@public.gmane.org \
--cc=benh-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org \
--cc=devicetree-compiler-u79uwXL29TY76Z2rM5mHXA@public.gmane.org \
--cc=galak-XVmvHMARGAS8U2dJNN8I7kB+6BGkLq7r@public.gmane.org \
--cc=grant.likely-QSEj5FYQhm4dnm+yROfE0A@public.gmane.org \
--cc=kim.phillips-KZfg59tc24xl57MIdRCFDg@public.gmane.org \
--cc=robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org \
--cc=robherring2-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).