[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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.