Message ID | 20201023224739.3837478-1-atish.patra@wdc.com |
---|---|
State | Accepted |
Headers | show |
Series | [v3] lib: utils: Implement "ranges" property parsing | expand |
> -----Original Message----- > From: Atish Patra <atish.patra@wdc.com> > Sent: 24 October 2020 04:18 > To: opensbi@lists.infradead.org > Cc: Atish Patra <Atish.Patra@wdc.com>; Anup Patel <Anup.Patel@wdc.com> > Subject: [PATCH v3] lib: utils: Implement "ranges" property parsing > > The "reg" property in a device node may not be the correct address always. > If a parent node defines a "ranges" property, the child address need to be > translated with respect to parents address. If the ranges property is not > present, it will just use 1:1 translation. > > Signed-off-by: Atish Patra <atish.patra@wdc.com> > Reviewed-by: Anup Patel <anup.patel@wdc.com> > --- > lib/utils/fdt/fdt_helper.c | 50 > ++++++++++++++++++++++++++++++++++++-- > 1 file changed, 48 insertions(+), 2 deletions(-) > > diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index > aec73a0598d7..bf19ff92d5bd 100644 > --- a/lib/utils/fdt/fdt_helper.c > +++ b/lib/utils/fdt/fdt_helper.c > @@ -71,10 +71,48 @@ int fdt_find_match(void *fdt, int startoff, > return SBI_ENODEV; > } > > +static int fdt_translate_address(void *fdt, uint64_t reg, int parent, > + unsigned long *addr) > +{ > + int i, rlen; > + int cell_addr, cell_size; > + const fdt32_t *ranges; > + uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0; > + > + cell_addr = fdt_address_cells(fdt, parent); > + if (cell_addr < 1) > + return SBI_ENODEV; > + > + cell_size = fdt_size_cells(fdt, parent); > + if (cell_size < 0) > + return SBI_ENODEV; > + > + ranges = fdt_getprop(fdt, parent, "ranges", &rlen); > + if (ranges && rlen > 0) { > + for (i = 0; i < cell_addr; i++) > + caddr = (caddr << 32) | fdt32_to_cpu(*ranges++); > + for (i = 0; i < cell_addr; i++) > + paddr = (paddr << 32) | fdt32_to_cpu(*ranges++); > + for (i = 0; i < cell_size; i++) > + rsize = (rsize << 32) | fdt32_to_cpu(*ranges++); > + if (reg < caddr || caddr >= (reg + rsize )) { > + sbi_printf("invalid address translation\n"); > + return SBI_ENODEV; > + } > + offset = reg - caddr; > + *addr = paddr + offset; > + } else { > + /* No translation required */ > + *addr = reg; > + } > + > + return 0; > +} > + > int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr, > unsigned long *size) > { > - int parent, len, i; > + int parent, len, i, rc; > int cell_addr, cell_size; > const fdt32_t *prop_addr, *prop_size; > uint64_t temp = 0; > @@ -98,7 +136,15 @@ int fdt_get_node_addr_size(void *fdt, int node, > unsigned long *addr, > if (addr) { > for (i = 0; i < cell_addr; i++) > temp = (temp << 32) | fdt32_to_cpu(*prop_addr++); > - *addr = temp; > + do { > + if (parent < 0) > + break; > + rc = fdt_translate_address(fdt, temp, parent, addr); > + if (rc) > + break; > + parent = fdt_parent_offset(fdt, parent); > + temp = *addr; > + } while (1); > } > temp = 0; > > -- > 2.25.1 Applied this patch to the riscv/opensbi repo. Thanks, Anup
diff --git a/lib/utils/fdt/fdt_helper.c b/lib/utils/fdt/fdt_helper.c index aec73a0598d7..bf19ff92d5bd 100644 --- a/lib/utils/fdt/fdt_helper.c +++ b/lib/utils/fdt/fdt_helper.c @@ -71,10 +71,48 @@ int fdt_find_match(void *fdt, int startoff, return SBI_ENODEV; } +static int fdt_translate_address(void *fdt, uint64_t reg, int parent, + unsigned long *addr) +{ + int i, rlen; + int cell_addr, cell_size; + const fdt32_t *ranges; + uint64_t offset = 0, caddr = 0, paddr = 0, rsize = 0; + + cell_addr = fdt_address_cells(fdt, parent); + if (cell_addr < 1) + return SBI_ENODEV; + + cell_size = fdt_size_cells(fdt, parent); + if (cell_size < 0) + return SBI_ENODEV; + + ranges = fdt_getprop(fdt, parent, "ranges", &rlen); + if (ranges && rlen > 0) { + for (i = 0; i < cell_addr; i++) + caddr = (caddr << 32) | fdt32_to_cpu(*ranges++); + for (i = 0; i < cell_addr; i++) + paddr = (paddr << 32) | fdt32_to_cpu(*ranges++); + for (i = 0; i < cell_size; i++) + rsize = (rsize << 32) | fdt32_to_cpu(*ranges++); + if (reg < caddr || caddr >= (reg + rsize )) { + sbi_printf("invalid address translation\n"); + return SBI_ENODEV; + } + offset = reg - caddr; + *addr = paddr + offset; + } else { + /* No translation required */ + *addr = reg; + } + + return 0; +} + int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr, unsigned long *size) { - int parent, len, i; + int parent, len, i, rc; int cell_addr, cell_size; const fdt32_t *prop_addr, *prop_size; uint64_t temp = 0; @@ -98,7 +136,15 @@ int fdt_get_node_addr_size(void *fdt, int node, unsigned long *addr, if (addr) { for (i = 0; i < cell_addr; i++) temp = (temp << 32) | fdt32_to_cpu(*prop_addr++); - *addr = temp; + do { + if (parent < 0) + break; + rc = fdt_translate_address(fdt, temp, parent, addr); + if (rc) + break; + parent = fdt_parent_offset(fdt, parent); + temp = *addr; + } while (1); } temp = 0;