git: 839374bbfe8b - main - Teach the GICv3 driver to translate memory ranges
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 23 Sep 2022 14:47:11 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=839374bbfe8bdbc766156bf0129bf54958dc2d8b commit 839374bbfe8bdbc766156bf0129bf54958dc2d8b Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2022-09-22 12:09:02 +0000 Commit: Andrew Turner <andrew@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 {