The branch main has been updated by andrew:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=839374bbfe8bdbc766156bf0129bf54958dc2d8b

commit 839374bbfe8bdbc766156bf0129bf54958dc2d8b
Author:     Andrew Turner <and...@freebsd.org>
AuthorDate: 2022-09-22 12:09:02 +0000
Commit:     Andrew Turner <and...@freebsd.org>
CommitDate: 2022-09-23 14:28:45 +0000

    Teach the GICv3 driver to translate memory ranges
    
    As with the GICv1/2 driver teach the GICv3 driver to translate memory
    ranges of children. This allows us to create a common
    bus_alloc_resource implementation for bot hACPI and FDT attachments.
    
    Sponsored by:   The FreeBSD Foundation
---
 sys/arm/arm/gic.h             |   6 ---
 sys/arm/arm/gic_common.h      |   6 +++
 sys/arm64/arm64/gic_v3.c      |  57 ++++++++++++++++++++++
 sys/arm64/arm64/gic_v3_acpi.c |  33 -------------
 sys/arm64/arm64/gic_v3_fdt.c  | 111 +++++++++++++++++++++++-------------------
 sys/arm64/arm64/gic_v3_var.h  |   3 ++
 6 files changed, 126 insertions(+), 90 deletions(-)

diff --git a/sys/arm/arm/gic.h b/sys/arm/arm/gic.h
index ce0c8a6187e1..5db11a16a4e2 100644
--- a/sys/arm/arm/gic.h
+++ b/sys/arm/arm/gic.h
@@ -39,12 +39,6 @@
 #ifndef _ARM_GIC_H_
 #define _ARM_GIC_H_
 
-struct arm_gic_range {
-       uint64_t bus;
-       uint64_t host;
-       uint64_t size;
-};
-
 struct arm_gic_softc {
        device_t                gic_dev;
        void *                  gic_intrhand;
diff --git a/sys/arm/arm/gic_common.h b/sys/arm/arm/gic_common.h
index 42ec44bb7fab..9487bcb2be8d 100644
--- a/sys/arm/arm/gic_common.h
+++ b/sys/arm/arm/gic_common.h
@@ -31,6 +31,12 @@
 #ifndef _GIC_COMMON_H_
 #define _GIC_COMMON_H_
 
+struct arm_gic_range {
+       uint64_t bus;
+       uint64_t host;
+       uint64_t size;
+};
+
 #define        GIC_IVAR_HW_REV         500
 #define        GIC_IVAR_BUS            501
 #define        GIC_IVAR_VGIC           502
diff --git a/sys/arm64/arm64/gic_v3.c b/sys/arm64/arm64/gic_v3.c
index 759d50f0941e..c26158e4035c 100644
--- a/sys/arm64/arm64/gic_v3.c
+++ b/sys/arm64/arm64/gic_v3.c
@@ -81,6 +81,7 @@ static bus_print_child_t gic_v3_print_child;
 static bus_get_domain_t gic_v3_get_domain;
 static bus_read_ivar_t gic_v3_read_ivar;
 static bus_write_ivar_t gic_v3_write_ivar;
+static bus_alloc_resource_t gic_v3_alloc_resource;
 
 static pic_disable_intr_t gic_v3_disable_intr;
 static pic_enable_intr_t gic_v3_enable_intr;
@@ -124,6 +125,8 @@ static device_method_t gic_v3_methods[] = {
        DEVMETHOD(bus_get_domain,       gic_v3_get_domain),
        DEVMETHOD(bus_read_ivar,        gic_v3_read_ivar),
        DEVMETHOD(bus_write_ivar,       gic_v3_write_ivar),
+       DEVMETHOD(bus_alloc_resource,   gic_v3_alloc_resource),
+       DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
 
        /* Interrupt controller interface */
        DEVMETHOD(pic_disable_intr,     gic_v3_disable_intr),
@@ -435,6 +438,7 @@ gic_v3_detach(device_t dev)
        for (i = 0; i <= mp_maxid; i++)
                free(sc->gic_redists.pcpu[i], M_GIC_V3);
 
+       free(sc->ranges, M_GIC_V3);
        free(sc->gic_res, M_GIC_V3);
        free(sc->gic_redists.regions, M_GIC_V3);
 
@@ -524,6 +528,59 @@ gic_v3_write_ivar(device_t dev, device_t child, int which, 
uintptr_t value)
        return (ENOENT);
 }
 
+static struct resource *
+gic_v3_alloc_resource(device_t bus, device_t child, int type, int *rid,
+    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+{
+       struct gic_v3_softc *sc;
+       struct resource_list_entry *rle;
+       struct resource_list *rl;
+       int j;
+
+       /* We only allocate memory */
+       if (type != SYS_RES_MEMORY)
+               return (NULL);
+
+       sc = device_get_softc(bus);
+
+       if (RMAN_IS_DEFAULT_RANGE(start, end)) {
+               rl = BUS_GET_RESOURCE_LIST(bus, child);
+               if (rl == NULL)
+                       return (NULL);
+
+               /* Find defaults for this rid */
+               rle = resource_list_find(rl, type, *rid);
+               if (rle == NULL)
+                       return (NULL);
+
+               start = rle->start;
+               end = rle->end;
+               count = rle->count;
+       }
+
+       /* Remap through ranges property */
+       for (j = 0; j < sc->nranges; j++) {
+               if (start >= sc->ranges[j].bus && end <
+                   sc->ranges[j].bus + sc->ranges[j].size) {
+                       start -= sc->ranges[j].bus;
+                       start += sc->ranges[j].host;
+                       end -= sc->ranges[j].bus;
+                       end += sc->ranges[j].host;
+                       break;
+               }
+       }
+       if (j == sc->nranges && sc->nranges != 0) {
+               if (bootverbose)
+                       device_printf(bus, "Could not map resource "
+                           "%#jx-%#jx\n", (uintmax_t)start, (uintmax_t)end);
+
+               return (NULL);
+       }
+
+       return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
+           count, flags));
+}
+
 int
 arm_gic_v3_intr(void *arg)
 {
diff --git a/sys/arm64/arm64/gic_v3_acpi.c b/sys/arm64/arm64/gic_v3_acpi.c
index f24662750da7..3d3cd3ba9ccd 100644
--- a/sys/arm64/arm64/gic_v3_acpi.c
+++ b/sys/arm64/arm64/gic_v3_acpi.c
@@ -59,7 +59,6 @@ struct gic_v3_acpi_devinfo {
 static device_identify_t gic_v3_acpi_identify;
 static device_probe_t gic_v3_acpi_probe;
 static device_attach_t gic_v3_acpi_attach;
-static bus_alloc_resource_t gic_v3_acpi_bus_alloc_res;
 static bus_get_resource_list_t gic_v3_acpi_get_resource_list;
 
 static void gic_v3_acpi_bus_attach(device_t);
@@ -71,8 +70,6 @@ static device_method_t gic_v3_acpi_methods[] = {
        DEVMETHOD(device_attach,                gic_v3_acpi_attach),
 
        /* Bus interface */
-       DEVMETHOD(bus_alloc_resource,           gic_v3_acpi_bus_alloc_res),
-       DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
        DEVMETHOD(bus_get_resource_list,        gic_v3_acpi_get_resource_list),
 
        /* End */
@@ -445,36 +442,6 @@ gic_v3_acpi_bus_attach(device_t dev)
        bus_generic_attach(dev);
 }
 
-static struct resource *
-gic_v3_acpi_bus_alloc_res(device_t bus, device_t child, int type, int *rid,
-    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
-{
-       struct resource_list_entry *rle;
-       struct resource_list *rl;
-
-       /* We only allocate memory */
-       if (type != SYS_RES_MEMORY)
-               return (NULL);
-
-       if (RMAN_IS_DEFAULT_RANGE(start, end)) {
-               rl = BUS_GET_RESOURCE_LIST(bus, child);
-               if (rl == NULL)
-                       return (NULL);
-
-               /* Find defaults for this rid */
-               rle = resource_list_find(rl, type, *rid);
-               if (rle == NULL)
-                       return (NULL);
-
-               start = rle->start;
-               end = rle->end;
-               count = rle->count;
-       }
-
-       return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
-           count, flags));
-}
-
 static struct resource_list *
 gic_v3_acpi_get_resource_list(device_t bus, device_t child)
 {
diff --git a/sys/arm64/arm64/gic_v3_fdt.c b/sys/arm64/arm64/gic_v3_fdt.c
index dc1445340943..2efdba68eae2 100644
--- a/sys/arm64/arm64/gic_v3_fdt.c
+++ b/sys/arm64/arm64/gic_v3_fdt.c
@@ -54,8 +54,6 @@ __FBSDID("$FreeBSD$");
 static int gic_v3_fdt_probe(device_t);
 static int gic_v3_fdt_attach(device_t);
 
-static struct resource *gic_v3_ofw_bus_alloc_res(device_t, device_t, int, int 
*,
-    rman_res_t, rman_res_t, rman_res_t, u_int);
 static const struct ofw_bus_devinfo *gic_v3_ofw_get_devinfo(device_t, 
device_t);
 static bus_get_resource_list_t gic_v3_fdt_get_resource_list;
 
@@ -65,8 +63,6 @@ static device_method_t gic_v3_fdt_methods[] = {
        DEVMETHOD(device_attach,        gic_v3_fdt_attach),
 
        /* Bus interface */
-       DEVMETHOD(bus_alloc_resource,           gic_v3_ofw_bus_alloc_res),
-       DEVMETHOD(bus_activate_resource,        bus_generic_activate_resource),
        DEVMETHOD(bus_get_resource_list,        gic_v3_fdt_get_resource_list),
 
        /* ofw_bus interface */
@@ -219,51 +215,64 @@ gic_v3_ofw_get_devinfo(device_t bus __unused, device_t 
child)
        return (&di->di_dinfo);
 }
 
-static struct resource *
-gic_v3_ofw_bus_alloc_res(device_t bus, device_t child, int type, int *rid,
-    rman_res_t start, rman_res_t end, rman_res_t count, u_int flags)
+/* Helper functions */
+static int
+gic_v3_ofw_fill_ranges(phandle_t parent, struct gic_v3_softc *sc,
+    pcell_t *addr_cellsp, pcell_t *size_cellsp)
 {
-       struct resource_list_entry *rle;
-       struct resource_list *rl;
-       int ranges_len;
-
-       /* We only allocate memory */
-       if (type != SYS_RES_MEMORY)
-               return (NULL);
-
-       if (RMAN_IS_DEFAULT_RANGE(start, end)) {
-               rl = BUS_GET_RESOURCE_LIST(bus, child);
-               if (rl == NULL)
-                       return (NULL);
-
-               /* Find defaults for this rid */
-               rle = resource_list_find(rl, type, *rid);
-               if (rle == NULL)
-                       return (NULL);
-
-               start = rle->start;
-               end = rle->end;
-               count = rle->count;
-       }
-       /*
-        * XXX: No ranges remap!
-        *      Absolute address is expected.
-        */
-       if (ofw_bus_has_prop(bus, "ranges")) {
-               ranges_len = OF_getproplen(ofw_bus_get_node(bus), "ranges");
-               if (ranges_len != 0) {
-                       if (bootverbose) {
-                               device_printf(child,
-                                   "Ranges remap not supported\n");
-                       }
-                       return (NULL);
+       pcell_t addr_cells, host_cells, size_cells;
+       cell_t *base_ranges;
+       ssize_t nbase_ranges;
+       int i, j, k;
+
+       host_cells = 1;
+       OF_getencprop(OF_parent(parent), "#address-cells", &host_cells,
+           sizeof(host_cells));
+       addr_cells = 2;
+       OF_getencprop(parent, "#address-cells", &addr_cells,
+           sizeof(addr_cells));
+       size_cells = 2;
+       OF_getencprop(parent, "#size-cells", &size_cells,
+           sizeof(size_cells));
+
+       *addr_cellsp = addr_cells;
+       *size_cellsp = size_cells;
+
+       nbase_ranges = OF_getproplen(parent, "ranges");
+       if (nbase_ranges < 0)
+               return (EINVAL);
+
+       sc->nranges = nbase_ranges / sizeof(cell_t) /
+           (addr_cells + host_cells + size_cells);
+       if (sc->nranges == 0)
+               return (0);
+
+       sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), M_GIC_V3,
+           M_WAITOK);
+       base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK);
+       OF_getencprop(parent, "ranges", base_ranges, nbase_ranges);
+
+       for (i = 0, j = 0; i < sc->nranges; i++) {
+               sc->ranges[i].bus = 0;
+               for (k = 0; k < addr_cells; k++) {
+                       sc->ranges[i].bus <<= 32;
+                       sc->ranges[i].bus |= base_ranges[j++];
+               }
+               sc->ranges[i].host = 0;
+               for (k = 0; k < host_cells; k++) {
+                       sc->ranges[i].host <<= 32;
+                       sc->ranges[i].host |= base_ranges[j++];
+               }
+               sc->ranges[i].size = 0;
+               for (k = 0; k < size_cells; k++) {
+                       sc->ranges[i].size <<= 32;
+                       sc->ranges[i].size |= base_ranges[j++];
                }
        }
-       return (bus_generic_alloc_resource(bus, child, type, rid, start, end,
-           count, flags));
-}
 
-/* Helper functions */
+       free(base_ranges, M_DEVBUF);
+       return (0);
+}
 
 /*
  * Bus capability support for GICv3.
@@ -278,16 +287,16 @@ gic_v3_ofw_bus_attach(device_t dev)
        device_t child;
        phandle_t parent, node;
        pcell_t addr_cells, size_cells;
+       int rv;
 
        sc = device_get_softc(dev);
        parent = ofw_bus_get_node(dev);
        if (parent > 0) {
-               addr_cells = 2;
-               OF_getencprop(parent, "#address-cells", &addr_cells,
-                   sizeof(addr_cells));
-               size_cells = 2;
-               OF_getencprop(parent, "#size-cells", &size_cells,
-                   sizeof(size_cells));
+               rv = gic_v3_ofw_fill_ranges(parent, sc, &addr_cells,
+                   &size_cells);
+               if (rv != 0)
+                       return (rv);
+
                /* Iterate through all GIC subordinates */
                for (node = OF_child(parent); node > 0; node = OF_peer(node)) {
                        /*
diff --git a/sys/arm64/arm64/gic_v3_var.h b/sys/arm64/arm64/gic_v3_var.h
index b66fe6c57bb2..61c3ff0b61ae 100644
--- a/sys/arm64/arm64/gic_v3_var.h
+++ b/sys/arm64/arm64/gic_v3_var.h
@@ -84,6 +84,9 @@ struct gic_v3_softc {
        device_t                *gic_children;
        struct intr_pic         *gic_pic;
        struct gic_v3_irqsrc    *gic_irqs;
+
+       int                     nranges;
+       struct arm_gic_range *  ranges;
 };
 
 struct gic_v3_devinfo {

Reply via email to