git: a5ec261a7c57 - main - Add FDT attachment driver for ARM System MMU v3.2 controller.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 07 May 2022 10:20:31 UTC
The branch main has been updated by br: URL: https://cgit.FreeBSD.org/src/commit/?id=a5ec261a7c57758e9b77c1c3af0bdbb5165b3e3c commit a5ec261a7c57758e9b77c1c3af0bdbb5165b3e3c Author: Ruslan Bukin <br@FreeBSD.org> AuthorDate: 2022-05-07 10:13:46 +0000 Commit: Ruslan Bukin <br@FreeBSD.org> CommitDate: 2022-05-07 10:18:35 +0000 Add FDT attachment driver for ARM System MMU v3.2 controller. Tested on ARM Morello Board. Sponsored by: UKRI --- sys/arm64/iommu/smmu.c | 63 ++++++++++++++++---- sys/arm64/iommu/smmu_acpi.c | 4 +- sys/arm64/iommu/smmu_fdt.c | 138 ++++++++++++++++++++++++++++++++++++++++++++ sys/arm64/iommu/smmuvar.h | 2 +- sys/conf/files.arm64 | 3 +- 5 files changed, 195 insertions(+), 15 deletions(-) diff --git a/sys/arm64/iommu/smmu.c b/sys/arm64/iommu/smmu.c index 1f2d7283be72..74b68ce1d07a 100644 --- a/sys/arm64/iommu/smmu.c +++ b/sys/arm64/iommu/smmu.c @@ -98,13 +98,15 @@ __FBSDID("$FreeBSD$"); #include <sys/bus.h> #include <sys/kernel.h> #include <sys/malloc.h> +#include <sys/mutex.h> #include <sys/rman.h> #include <sys/lock.h> +#include <sys/sysctl.h> #include <sys/tree.h> #include <sys/taskqueue.h> #include <vm/vm.h> #include <vm/vm_page.h> -#if DEV_ACPI +#ifdef DEV_ACPI #include <contrib/dev/acpica/include/acpi.h> #include <dev/acpica/acpivar.h> #endif @@ -113,6 +115,14 @@ __FBSDID("$FreeBSD$"); #include <dev/iommu/iommu.h> #include <arm64/iommu/iommu_pmap.h> +#include <machine/bus.h> + +#ifdef FDT +#include <dev/fdt/fdt_common.h> +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> +#endif + #include "iommu.h" #include "iommu_if.h" @@ -144,6 +154,7 @@ static struct resource_spec smmu_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, { SYS_RES_IRQ, 1, RF_ACTIVE }, { SYS_RES_IRQ, 2, RF_ACTIVE }, + { SYS_RES_IRQ, 3, RF_ACTIVE }, RESOURCE_SPEC_END }; @@ -1129,7 +1140,7 @@ smmu_enable_interrupts(struct smmu_softc *sc) return (0); } -#if DEV_ACPI +#ifdef DEV_ACPI static void smmu_configure_intr(struct smmu_softc *sc, struct resource *res) { @@ -1155,14 +1166,15 @@ smmu_setup_interrupts(struct smmu_softc *sc) dev = sc->dev; -#if DEV_ACPI +#ifdef DEV_ACPI /* * Configure SMMU interrupts as EDGE triggered manually * as ACPI tables carries no information for that. */ smmu_configure_intr(sc, sc->res[1]); - smmu_configure_intr(sc, sc->res[2]); + /* PRIQ is not in use. */ smmu_configure_intr(sc, sc->res[3]); + smmu_configure_intr(sc, sc->res[4]); #endif error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC, @@ -1172,7 +1184,7 @@ smmu_setup_interrupts(struct smmu_softc *sc) return (ENXIO); } - error = bus_setup_intr(dev, sc->res[3], INTR_TYPE_MISC, + error = bus_setup_intr(dev, sc->res[4], INTR_TYPE_MISC, smmu_gerr_intr, NULL, sc, &sc->intr_cookie[2]); if (error) { device_printf(dev, "Couldn't setup Gerr interrupt handler\n"); @@ -1761,18 +1773,28 @@ smmu_ctx_alloc(device_t dev, struct iommu_domain *iodom, device_t child, struct smmu_domain *domain; struct smmu_softc *sc; struct smmu_ctx *ctx; +#ifdef DEV_ACPI uint16_t rid; - u_int xref, sid; + u_int xref; int seg; +#else + struct pci_id_ofw_iommu pi; +#endif + u_int sid; int err; sc = device_get_softc(dev); domain = (struct smmu_domain *)iodom; +#ifdef DEV_ACPI seg = pci_get_domain(child); rid = pci_get_rid(child); err = acpi_iort_map_pci_smmuv3(seg, rid, &xref, &sid); - if (err) +#else + err = pci_get_id(child, PCI_ID_OFW_IOMMU, (uintptr_t *)&pi); + sid = pi.id; +#endif + if (err != 0) return (NULL); if (sc->features & SMMU_FEATURE_2_LVL_STREAM_TABLE) { @@ -1852,7 +1874,7 @@ smmu_ctx_lookup_by_sid(device_t dev, u_int sid) static struct iommu_ctx * smmu_ctx_lookup(device_t dev, device_t child) { - struct iommu_unit *iommu; + struct iommu_unit *iommu __unused; struct smmu_softc *sc; struct smmu_domain *domain; struct smmu_unit *unit; @@ -1883,15 +1905,24 @@ static int smmu_find(device_t dev, device_t child) { struct smmu_softc *sc; - u_int xref, sid; - uint16_t rid; + u_int xref; int error; +#ifdef DEV_ACPI + uint16_t rid; int seg; + u_int sid; +#else + phandle_t node; + uint64_t base, size; + struct pci_id_ofw_iommu pi; +#endif sc = device_get_softc(dev); +#ifdef DEV_ACPI rid = pci_get_rid(child); seg = pci_get_domain(child); +#endif /* * Find an xref of an IOMMU controller that serves traffic for dev. @@ -1903,8 +1934,16 @@ smmu_find(device_t dev, device_t child) return (ENOENT); } #else - /* TODO: add FDT support. */ - return (ENXIO); + error = pci_get_id(child, PCI_ID_OFW_IOMMU, (uintptr_t *)&pi); + if (error) { + /* Could not find reference to an SMMU device. */ + return (ENOENT); + } + + /* Our xref is memory base address. */ + node = OF_node_from_xref(pi.xref); + fdt_regsize(node, &base, &size); + xref = base; #endif /* Check if xref is ours. */ diff --git a/sys/arm64/iommu/smmu_acpi.c b/sys/arm64/iommu/smmu_acpi.c index d7a2c0444fdf..6ddbb0138c87 100644 --- a/sys/arm64/iommu/smmu_acpi.c +++ b/sys/arm64/iommu/smmu_acpi.c @@ -146,8 +146,10 @@ smmu_acpi_identify(driver_t *driver, device_t parent) BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 0, iort_data.smmu[i]->EventGsiv, 1); BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 1, - iort_data.smmu[i]->SyncGsiv, 1); + iort_data.smmu[i]->PriGsiv, 1); BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 2, + iort_data.smmu[i]->SyncGsiv, 1); + BUS_SET_RESOURCE(parent, dev, SYS_RES_IRQ, 3, iort_data.smmu[i]->GerrGsiv, 1); BUS_SET_RESOURCE(parent, dev, SYS_RES_MEMORY, 0, iort_data.smmu[i]->BaseAddress, MEMORY_RESOURCE_SIZE); diff --git a/sys/arm64/iommu/smmu_fdt.c b/sys/arm64/iommu/smmu_fdt.c new file mode 100644 index 000000000000..86cf0f9fd0cf --- /dev/null +++ b/sys/arm64/iommu/smmu_fdt.c @@ -0,0 +1,138 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2022 Ruslan Bukin <br@bsdpad.com> + * + * This work was supported by Innovate UK project 105694, "Digital Security + * by Design (DSbD) Technology Platform Prototype". + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> +#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/bitstring.h> +#include <sys/kernel.h> +#include <sys/rman.h> +#include <sys/sysctl.h> +#include <sys/tree.h> +#include <sys/taskqueue.h> +#include <sys/malloc.h> +#include <sys/module.h> +#include <vm/vm.h> +#include <vm/pmap.h> +#include <dev/pci/pcireg.h> +#include <dev/pci/pcivar.h> +#include <dev/iommu/iommu.h> + +#include <dev/ofw/ofw_bus.h> +#include <dev/ofw/ofw_bus_subr.h> + +#include <dev/iommu/iommu.h> + +#include <arm64/iommu/iommu.h> + +#include "smmuvar.h" + +static struct ofw_compat_data compat_data[] = { + { "arm,smmu-v3", 1 }, + { NULL, 0 } +}; + +static int +smmu_fdt_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "ARM System MMU (SMMU) v3"); + + return (BUS_PROBE_DEFAULT); +} + +static int +smmu_fdt_attach(device_t dev) +{ + struct smmu_softc *sc; + struct smmu_unit *unit; + struct iommu_unit *iommu; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + err = smmu_attach(dev); + if (err != 0) + goto error; + + unit = &sc->unit; + unit->dev = dev; + + iommu = &unit->iommu; + iommu->dev = dev; + + LIST_INIT(&unit->domain_list); + + /* Use memory start address as an xref. */ + sc->xref = bus_get_resource_start(dev, SYS_RES_MEMORY, 0); + + err = iommu_register(iommu); + if (err) { + device_printf(dev, "Failed to register SMMU.\n"); + return (ENXIO); + } + + return (0); + +error: + if (bootverbose) { + device_printf(dev, + "Failed to attach. Error %d\n", err); + } + + /* Failure so free resources. */ + smmu_detach(dev); + + return (err); +} + +static device_method_t smmu_fdt_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, smmu_fdt_probe), + DEVMETHOD(device_attach, smmu_fdt_attach), + DEVMETHOD_END +}; + +DEFINE_CLASS_1(smmu, smmu_fdt_driver, smmu_fdt_methods, + sizeof(struct smmu_softc), smmu_driver); + +static devclass_t smmu_fdt_devclass; + +EARLY_DRIVER_MODULE(smmu, simplebus, smmu_fdt_driver, smmu_fdt_devclass, + 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); diff --git a/sys/arm64/iommu/smmuvar.h b/sys/arm64/iommu/smmuvar.h index 3a1e5a269c01..76d4f238002d 100644 --- a/sys/arm64/iommu/smmuvar.h +++ b/sys/arm64/iommu/smmuvar.h @@ -136,7 +136,7 @@ struct smmu_strtab { struct smmu_softc { device_t dev; - struct resource *res[4]; + struct resource *res[5]; void *intr_cookie[3]; uint32_t ias; /* Intermediate Physical Address */ uint32_t oas; /* Physical Address */ diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64 index 5ee973a7b514..30358a5d67d1 100644 --- a/sys/conf/files.arm64 +++ b/sys/conf/files.arm64 @@ -106,7 +106,8 @@ arm64/iommu/iommu.c optional iommu arm64/iommu/iommu_if.m optional iommu arm64/iommu/iommu_pmap.c optional iommu arm64/iommu/smmu.c optional iommu -arm64/iommu/smmu_acpi.c optional acpi iommu +arm64/iommu/smmu_acpi.c optional iommu acpi +arm64/iommu/smmu_fdt.c optional iommu fdt arm64/iommu/smmu_quirks.c optional iommu dev/iommu/busdma_iommu.c optional iommu dev/iommu/iommu_gas.c optional iommu