[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Minios-devel] [UNIKRAFT PATCHv5 4/8] plat/common: Add fdt address translation support
The ranges property provides a means of defining a mapping or translation between the address space of the bus (the child address space) and the address space of the bus node's parent (the parent address space). Currently only 1:1 mapping between parent and child address is supported. Reviewed-by: Sharan Santhanam <sharan.santhanam@xxxxxxxxx> Signed-off-by: Jia He <justin.he@xxxxxxx> --- v4->v5: remove the _size_ check in fdt_reg_read_number to avoid return a exceptional address plat/drivers/include/ofw/fdt.h | 2 + plat/drivers/ofw/fdt.c | 137 +++++++++++++++++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/plat/drivers/include/ofw/fdt.h b/plat/drivers/include/ofw/fdt.h index 7d40fba..9ef3c8e 100644 --- a/plat/drivers/include/ofw/fdt.h +++ b/plat/drivers/include/ofw/fdt.h @@ -35,6 +35,8 @@ #ifndef _PLAT_DRIVER_OFW_FDT_H #define _PLAT_DRIVER_OFW_FDT_H +#define FDT_BAD_ADDR (uint64_t)(-1) + /** * fdt_getprop_u32_by_offset - retrieve u32 of a given property * @fdt: pointer to the device tree blob diff --git a/plat/drivers/ofw/fdt.c b/plat/drivers/ofw/fdt.c index a596df3..d891ab3 100644 --- a/plat/drivers/ofw/fdt.c +++ b/plat/drivers/ofw/fdt.c @@ -35,9 +35,14 @@ #include <libfdt_env.h> #include <fdt.h> #include <libfdt.h> +#include <ofw/fdt.h> #include <uk/print.h> +#define FDT_MAX_ADDR_CELLS FDT_MAX_NCELLS +#define FDT_CHECK_COUNTS(na, ns) ((na) > 0 && (na) <= FDT_MAX_ADDR_CELLS && \ + (ns) > 0) + int fdt_getprop_u32_by_offset(const void *fdt, int offset, const char *name, uint32_t *out) { @@ -100,3 +105,135 @@ int fdt_interrupt_cells(const void *fdt, int offset) return val; } + +/* + * read and combine the big number of reg, caller needs to make sure size + * is correct + */ +static uint64_t fdt_reg_read_number(const fdt32_t *regs, uint32_t size) +{ + uint64_t number = 0; + + for (uint32_t i = 0; i < size; i++) { + number <<= 32; + number |= fdt32_to_cpu(*regs); + regs++; + } + + return number; +} + +/* Default translator (generic bus) */ +static void fdt_default_count_cells(const void *fdt, int parentoffset, + int *addrc, int *sizec) +{ + if (addrc) + *addrc = fdt_address_cells(fdt, parentoffset); + + if (sizec) + *sizec = fdt_size_cells(fdt, parentoffset); +} + +static int fdt_default_translate(fdt32_t *addr, uint64_t offset, int na) +{ + uint64_t a = fdt_reg_read_number(addr, na); + + memset(addr, 0, na * sizeof(fdt32_t)); + a += offset; + if (na > 1) + addr[na - 2] = cpu_to_fdt32(a >> 32); + addr[na - 1] = cpu_to_fdt32(a & 0xffffffffu); + + return 0; +} + +static int fdt_translate_one(const void *fdt, int parent, fdt32_t *addr, + int na, int pna, const char *rprop) +{ + const fdt32_t *ranges; + int rlen; + uint64_t offset = FDT_BAD_ADDR; + + ranges = fdt_getprop(fdt, parent, rprop, &rlen); + if (!ranges) + return 1; + if (rlen == 0) { + offset = fdt_reg_read_number(addr, na); + memset(addr, 0, pna * 4); + uk_pr_debug("empty ranges, 1:1 translation\n"); + goto finish; + } + + uk_pr_err("Error, only 1:1 translation is supported...\n"); + return 1; + finish: + uk_pr_debug("with offset: 0x%lx\n", offset); + + /* Translate it into parent bus space */ + return fdt_default_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. + */ +static uint64_t fdt_translate_address_by_ranges(const void *fdt, + int node_offset, const fdt32_t *regs) +{ + int parent; + fdt32_t addr[FDT_MAX_ADDR_CELLS]; + int na, ns, pna, pns; + uint64_t result = FDT_BAD_ADDR; + + /* Get parent */ + parent = fdt_parent_offset(fdt, node_offset); + if (parent < 0) + goto bail; + + /* Count address cells & copy address locally */ + fdt_default_count_cells(fdt, parent, &na, &ns); + if (!FDT_CHECK_COUNTS(na, ns)) { + uk_pr_err("Bad cell count for %s\n", + fdt_get_name(fdt, node_offset, NULL)); + goto bail; + } + memcpy(addr, regs, na * 4); + + /* Translate */ + for (;;) { + /* Switch to parent bus */ + node_offset = parent; + parent = fdt_parent_offset(fdt, node_offset); + + /* If root, we have finished */ + if (parent < 0) { + uk_pr_debug("reached root node\n"); + result = fdt_reg_read_number(addr, na); + break; + } + + /* Get new parent bus and counts */ + fdt_default_count_cells(fdt, parent, &pna, &pns); + if (!FDT_CHECK_COUNTS(pna, pns)) { + uk_pr_err("Bad cell count for %s\n", + fdt_get_name(fdt, node_offset, NULL)); + break; + } + + uk_pr_debug("parent bus (na=%d, ns=%d) on %s\n", + pna, pns, fdt_get_name(fdt, parent, NULL)); + + /* Apply bus translation */ + if (fdt_translate_one(fdt, node_offset, + addr, na, pna, "ranges")) + break; + + /* Complete the move up one level */ + na = pna; + ns = pns; + } +bail: + return result; +} + -- 2.17.1 _______________________________________________ Minios-devel mailing list Minios-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/minios-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |