[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [UNIKRAFT PATCH RFCv4 14/35] plat/ofw: Support completed ranges mapping
Previously, we only support 1:1 mapping for ranges property. This is not enough for pci ecam on arm64. e.g. pcie@10000000 { interrupt-map-mask = < 0x1800 0x00 0x00 0x07 >; interrupt-map = < ... >; #interrupt-cells = < 0x01 >; ranges = < 0x1000000 0x00 0x00 0x00 0x3eff0000 0x00 0x10000 0x2000000 0x00 0x10000000 0x00 0x10000000 0x00 0x2eff0000 0x3000000 0x80 0x00 0x80 0x00 0x80 0x00 >; reg = < 0x40 0x10000000 0x00 0x10000000 >; msi-parent = < 0x8002 >; dma-coherent; bus-range = < 0x00 0xff >; linux,pci-domain = < 0x00 >; #size-cells = < 0x02 >; #address-cells = < 0x03 >; device_type = "pci"; compatible = "pci-host-ecam-generic"; }; Signed-off-by: Jia He <justin.he@xxxxxxx> --- plat/drivers/ofw/fdt.c | 46 +++++++++++++++++++++++++++++++++++------- 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/plat/drivers/ofw/fdt.c b/plat/drivers/ofw/fdt.c index 30ac270..780b8dd 100644 --- a/plat/drivers/ofw/fdt.c +++ b/plat/drivers/ofw/fdt.c @@ -97,6 +97,24 @@ static void fdt_default_count_cells(const void *fdt, int parentoffset, *sizec = fdt_size_cells(fdt, parentoffset); } +static __u64 fdt_default_map(fdt32_t *addr, const fdt32_t *range, + int na, int ns, int pna) +{ + __u64 cp, s, da; + + cp = fdt_reg_read_number(range, na); + s = fdt_reg_read_number(range + na + pna, ns); + da = fdt_reg_read_number(addr, na); + + uk_pr_debug("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 FDT_BAD_ADDR; + return da - cp; +} + static int fdt_default_translate(fdt32_t *addr, uint64_t offset, int na) { uint64_t a = fdt_reg_read_number(addr, na); @@ -111,10 +129,11 @@ static int fdt_default_translate(fdt32_t *addr, uint64_t offset, int na) } static int fdt_translate_one(const void *fdt, int parent, fdt32_t *addr, - int na, int pna, const char *rprop) + int na, int ns, int pna, const char *rprop) { const fdt32_t *ranges; int rlen; + int rone; uint64_t offset = FDT_BAD_ADDR; ranges = fdt_getprop(fdt, parent, rprop, &rlen); @@ -126,10 +145,23 @@ static int fdt_translate_one(const void *fdt, int parent, fdt32_t *addr, 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); + uk_pr_debug("walking ranges...\n"); + /* Now walk through the ranges */ + rlen /= 4; + rone = na + pna + ns; + for (; rlen >= rone; rlen -= rone, ranges += rone) { + offset = fdt_default_map(addr, ranges, na, ns, pna); + if (offset != FDT_BAD_ADDR) + break; + } + if (offset == FDT_BAD_ADDR) { + uk_pr_debug("not found !\n"); + return 1; + } + memcpy(addr, ranges + na, 4 * pna); + +finish: + uk_pr_info("parent translation for:%p %x", addr, pna); /* Translate it into parent bus space */ return fdt_default_translate(addr, offset, pna); @@ -140,7 +172,7 @@ static int fdt_translate_one(const void *fdt, int parent, fdt32_t *addr, * 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, +uint64_t fdt_translate_address_by_ranges(const void *fdt, int node_offset, const fdt32_t *regs) { int parent; @@ -188,7 +220,7 @@ static uint64_t fdt_translate_address_by_ranges(const void *fdt, /* Apply bus translation */ if (fdt_translate_one(fdt, node_offset, - addr, na, pna, "ranges")) + addr, na, ns, pna, "ranges")) break; /* Complete the move up one level */ -- 2.17.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |