From nobody Wed May 18 13:18:11 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id D50381AE2EC5; Wed, 18 May 2022 13:18:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4L3D7l5c4Kz4Zbh; Wed, 18 May 2022 13:18:11 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652879891; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Mwl+wmw7W8rYYG8Sqmo91KpcDLE+NPcP8LIBuJY/M8k=; b=HhVGx+FD0DDOg+Wnz7U2LEE8Vu1lsOQDAINMPVyjLMDhX3/c3RKR8/m0MJhoBT3+CHsj8U bcNg4MkXYHc43Mex2RrGEM57IbPOgDZ5GqWWiLZoQH+RTO06XwESBDIFEwALtCGWQHHVIB gvSERKzkm+SpHdU2tLrweF3ArA/o82ThDhSmvgiM+fuAdGmNEtLWSlVVWRUrhOtYAatVMO LCBxNlvZ9Fp4wpjVPzumn1YY9IzDz2okGsjEyzqBTJaZ3K16AJU0XXWb7UXBactjd3a5uX WOzt6Uy+G253CMGlnM8sJeA5cCm7rEZWJIIQ3L5tIhNtyS4O0hQfYhTVhA+A+A== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id A0FFC1AA1; Wed, 18 May 2022 13:18:11 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 24IDIBZX016523; Wed, 18 May 2022 13:18:11 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 24IDIB4S016522; Wed, 18 May 2022 13:18:11 GMT (envelope-from git) Date: Wed, 18 May 2022 13:18:11 GMT Message-Id: <202205181318.24IDIB4S016522@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Ruslan Bukin Subject: git: 41ce5498f8e6 - main - Add OFW support to arm64's IOMMU framework. This is needed to support non-PCI devices like memory-mapped display controllers. Split-out some initialization code from iommu_ctx_alloc() into iommu_ctx_init() method so we could pass controller's MD-data obtained from DTS to the driver prior to a CTX initialization. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: br X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 41ce5498f8e69e6820962e813eb3b40c465079d0 Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1652879891; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Mwl+wmw7W8rYYG8Sqmo91KpcDLE+NPcP8LIBuJY/M8k=; b=sMkMxZ6P9IqD/gF81FJU+Rl/mfYyMwWBfCZi7dxJ8ZWmZeuepzKJ+RHEZW0+NI6gsx6p/D w1IC2nrsEdwYBLoHWqC3u1D+I7DQZsgkEqMjWIsA8Ozdc0xfiIuvFDxLpasXfQYo9/lMeY 3cJlgBnfjebsnG02l8y/Q4+YlNCsvCFlBEsVxmE1xHJDd7GIlf6ocj8m6ANYYPRKhndLhr TuChW8QaZAPUXs8JLz2uZxn8wvnL+Ei1tO9t9bbZqUtfo/Vq7yJMqw+lat0JPGSpFRNu80 P/x1CRAIw2d9u4wajtbgNEdROX4cKitg6HHDV9mKmtHwmKNSS4M+6XMeJEWxSw== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1652879891; a=rsa-sha256; cv=none; b=RAhsf/J7NbTkLUplSeBftWRJQuKz2KKPORxdNP9DDOMdGIq1jVwMh36aurF1mZAJ2ERLzU CRqXEUSe0L4lKiJCU7JPBzSsTGrh2AIrxGcrJrTzHUejSAyfl3L+XxgEeqNKXuU7IfXSlt Y0YWS8CMPFaEtNXgQaopsb9qhHFOEuv8ty6sOyDHc4Fmvmz+aikCdzlL47Wpg42n2kThvY Sqp/LSRo+MDkXa8RpMulXjvFvhEganAx75s3AAPBKR6mkKTMMq+apB2jIEd9pbHDJGM70u qSj2eBxAGD1xC24mdQdsmmN4RyuIz4v8Io5DtHfKl4NMonKs9r5QU684y4KjVA== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch main has been updated by br: URL: https://cgit.FreeBSD.org/src/commit/?id=41ce5498f8e69e6820962e813eb3b40c465079d0 commit 41ce5498f8e69e6820962e813eb3b40c465079d0 Author: Ruslan Bukin AuthorDate: 2022-05-18 13:11:23 +0000 Commit: Ruslan Bukin CommitDate: 2022-05-18 13:11:23 +0000 Add OFW support to arm64's IOMMU framework. This is needed to support non-PCI devices like memory-mapped display controllers. Split-out some initialization code from iommu_ctx_alloc() into iommu_ctx_init() method so we could pass controller's MD-data obtained from DTS to the driver prior to a CTX initialization. Tested on Morello SoC. Sponsored by: UKRI --- sys/arm64/iommu/iommu.c | 163 ++++++++++++++++++++++++++++++++++++++++----- sys/arm64/iommu/iommu.h | 1 + sys/arm64/iommu/iommu_if.m | 24 +++++++ sys/arm64/iommu/smmu.c | 92 +++++++++++++++++-------- sys/arm64/iommu/smmu_fdt.c | 2 + 5 files changed, 239 insertions(+), 43 deletions(-) diff --git a/sys/arm64/iommu/iommu.c b/sys/arm64/iommu/iommu.c index 447f3e141610..aa48dcf5ab5e 100644 --- a/sys/arm64/iommu/iommu.c +++ b/sys/arm64/iommu/iommu.c @@ -57,6 +57,12 @@ __FBSDID("$FreeBSD$"); #include #include +#ifdef FDT +#include +#include +#include +#endif + #include "iommu.h" #include "iommu_if.h" @@ -180,23 +186,149 @@ iommu_tag_init(struct bus_dma_tag_iommu *t) } static struct iommu_ctx * -iommu_ctx_alloc(device_t dev, struct iommu_domain *iodom, bool disabled) +iommu_ctx_alloc(device_t requester, struct iommu_domain *iodom, bool disabled) { struct iommu_unit *iommu; struct iommu_ctx *ioctx; iommu = iodom->iommu; - ioctx = IOMMU_CTX_ALLOC(iommu->dev, iodom, dev, disabled); + ioctx = IOMMU_CTX_ALLOC(iommu->dev, iodom, requester, disabled); if (ioctx == NULL) return (NULL); + ioctx->domain = iodom; + + return (ioctx); +} + +static int +iommu_ctx_init(device_t requester, struct iommu_ctx *ioctx) +{ + struct bus_dma_tag_iommu *tag; + struct iommu_domain *iodom; + struct iommu_unit *iommu; + int error; + + iodom = ioctx->domain; + iommu = iodom->iommu; + + error = IOMMU_CTX_INIT(iommu->dev, ioctx); + if (error) + return (error); + + tag = ioctx->tag = malloc(sizeof(struct bus_dma_tag_iommu), + M_IOMMU, M_WAITOK | M_ZERO); + tag->owner = requester; + tag->ctx = ioctx; + tag->ctx->domain = iodom; + + iommu_tag_init(tag); + + return (error); +} + +static struct iommu_unit * +iommu_lookup(device_t dev) +{ + struct iommu_entry *entry; + struct iommu_unit *iommu; + + IOMMU_LIST_LOCK(); + LIST_FOREACH(entry, &iommu_list, next) { + iommu = entry->iommu; + if (iommu->dev == dev) { + IOMMU_LIST_UNLOCK(); + return (iommu); + } + } + IOMMU_LIST_UNLOCK(); + + return (NULL); +} + +struct iommu_ctx * +iommu_get_ctx_ofw(device_t dev, int channel) +{ + struct iommu_domain *iodom; + struct iommu_unit *iommu; + struct iommu_ctx *ioctx; + phandle_t node, parent; + device_t iommu_dev; + pcell_t *cells; + int niommus; + int ncells; + int error; + + node = ofw_bus_get_node(dev); + if (node <= 0) { + device_printf(dev, + "%s called on not ofw based device.\n", __func__); + return (NULL); + } + + error = ofw_bus_parse_xref_list_get_length(node, + "iommus", "#iommu-cells", &niommus); + if (error) { + device_printf(dev, "%s can't get iommu list.\n", __func__); + return (NULL); + } + + if (niommus == 0) { + device_printf(dev, "%s iommu list is empty.\n", __func__); + return (NULL); + } + + error = ofw_bus_parse_xref_list_alloc(node, "iommus", "#iommu-cells", + channel, &parent, &ncells, &cells); + if (error != 0) { + device_printf(dev, "%s can't get iommu device xref.\n", + __func__); + return (NULL); + } + + iommu_dev = OF_device_from_xref(parent); + if (iommu_dev == NULL) { + device_printf(dev, "%s can't get iommu device.\n", __func__); + return (NULL); + } + + iommu = iommu_lookup(iommu_dev); + if (iommu == NULL) { + device_printf(dev, "%s can't lookup iommu.\n", __func__); + return (NULL); + } + /* - * iommu can also be used for non-PCI based devices. - * This should be reimplemented as new newbus method with - * pci_get_rid() as a default for PCI device class. + * In our current configuration we have a domain per each ctx, + * so allocate a domain first. */ - ioctx->rid = pci_get_rid(dev); + iodom = iommu_domain_alloc(iommu); + if (iodom == NULL) { + device_printf(dev, "%s can't allocate domain.\n", __func__); + return (NULL); + } + + ioctx = iommu_ctx_alloc(dev, iodom, false); + if (ioctx == NULL) { + iommu_domain_free(iodom); + return (NULL); + } + + ioctx->domain = iodom; + + error = IOMMU_OFW_MD_DATA(iommu->dev, ioctx, cells, ncells); + if (error) { + device_printf(dev, "%s can't set MD data\n", __func__); + return (NULL); + } + + error = iommu_ctx_init(dev, ioctx); + if (error) { + IOMMU_CTX_FREE(iommu->dev, ioctx); + iommu_domain_free(iodom); + return (NULL); + } return (ioctx); } @@ -205,9 +337,9 @@ struct iommu_ctx * iommu_get_ctx(struct iommu_unit *iommu, device_t requester, uint16_t rid, bool disabled, bool rmrr) { - struct iommu_ctx *ioctx; struct iommu_domain *iodom; - struct bus_dma_tag_iommu *tag; + struct iommu_ctx *ioctx; + int error; IOMMU_LOCK(iommu); ioctx = IOMMU_CTX_LOOKUP(iommu->dev, requester); @@ -231,15 +363,12 @@ iommu_get_ctx(struct iommu_unit *iommu, device_t requester, return (NULL); } - tag = ioctx->tag = malloc(sizeof(struct bus_dma_tag_iommu), - M_IOMMU, M_WAITOK | M_ZERO); - tag->owner = requester; - tag->ctx = ioctx; - tag->ctx->domain = iodom; - - iommu_tag_init(tag); - - ioctx->domain = iodom; + error = iommu_ctx_init(requester, ioctx); + if (error) { + IOMMU_CTX_FREE(iommu->dev, ioctx); + iommu_domain_free(iodom); + return (NULL); + } return (ioctx); } diff --git a/sys/arm64/iommu/iommu.h b/sys/arm64/iommu/iommu.h index 2071173070df..c221f619b5db 100644 --- a/sys/arm64/iommu/iommu.h +++ b/sys/arm64/iommu/iommu.h @@ -40,5 +40,6 @@ int iommu_unregister(struct iommu_unit *unit); int iommu_register(struct iommu_unit *unit); +struct iommu_ctx * iommu_get_ctx_ofw(device_t dev, int channel); #endif /* _ARM64_IOMMU_IOMMU_H_ */ diff --git a/sys/arm64/iommu/iommu_if.m b/sys/arm64/iommu/iommu_if.m index ef8c3e7b57b8..6d4f963c5ff1 100644 --- a/sys/arm64/iommu/iommu_if.m +++ b/sys/arm64/iommu/iommu_if.m @@ -42,6 +42,12 @@ #include #include +#ifdef FDT +#include +#include +#include +#endif + INTERFACE iommu; # @@ -116,6 +122,14 @@ METHOD struct iommu_ctx * ctx_alloc { bool disabled; }; +# +# Initialize the new iommu context. +# +METHOD int ctx_init { + device_t dev; + struct iommu_ctx *ioctx; +}; + # # Free the iommu context. # @@ -123,3 +137,13 @@ METHOD void ctx_free { device_t dev; struct iommu_ctx *ioctx; }; + +# +# Notify controller we have machine-dependent data. +# +METHOD int ofw_md_data { + device_t dev; + struct iommu_ctx *ioctx; + pcell_t *cells; + int ncells; +}; diff --git a/sys/arm64/iommu/smmu.c b/sys/arm64/iommu/smmu.c index 5d4401c5cee9..57f6826faa5e 100644 --- a/sys/arm64/iommu/smmu.c +++ b/sys/arm64/iommu/smmu.c @@ -1844,42 +1844,63 @@ smmu_ctx_alloc(device_t dev, struct iommu_domain *iodom, device_t child, bool disabled) { struct smmu_domain *domain; + struct smmu_ctx *ctx; + + domain = (struct smmu_domain *)iodom; + + ctx = malloc(sizeof(struct smmu_ctx), M_SMMU, M_WAITOK | M_ZERO); + ctx->dev = child; + ctx->domain = domain; + if (disabled) + ctx->bypass = true; + + IOMMU_DOMAIN_LOCK(iodom); + LIST_INSERT_HEAD(&domain->ctx_list, ctx, next); + IOMMU_DOMAIN_UNLOCK(iodom); + + return (&ctx->ioctx); +} + +static int +smmu_ctx_init(device_t dev, struct iommu_ctx *ioctx) +{ + struct smmu_domain *domain; + struct iommu_domain *iodom; struct smmu_softc *sc; struct smmu_ctx *ctx; devclass_t pci_class; u_int sid; int err; + ctx = (struct smmu_ctx *)ioctx; + sc = device_get_softc(dev); - domain = (struct smmu_domain *)iodom; - pci_class = devclass_find("pci"); - if (device_get_devclass(device_get_parent(child)) != pci_class) - return (NULL); + domain = ctx->domain; + iodom = (struct iommu_domain *)domain; + pci_class = devclass_find("pci"); + if (device_get_devclass(device_get_parent(ctx->dev)) == pci_class) { #ifdef DEV_ACPI - err = smmu_pci_get_sid_acpi(child, NULL, &sid); + err = smmu_pci_get_sid_acpi(ctx->dev, NULL, &sid); #else - err = smmu_pci_get_sid_fdt(child, NULL, &sid); + err = smmu_pci_get_sid_fdt(ctx->dev, NULL, &sid); #endif - if (err) - return (NULL); + if (err) + return (err); + + ioctx->rid = pci_get_rid(dev); + ctx->sid = sid; + ctx->vendor = pci_get_vendor(ctx->dev); + ctx->device = pci_get_device(ctx->dev); + } if (sc->features & SMMU_FEATURE_2_LVL_STREAM_TABLE) { - err = smmu_init_l1_entry(sc, sid); + err = smmu_init_l1_entry(sc, ctx->sid); if (err) - return (NULL); + return (err); } - ctx = malloc(sizeof(struct smmu_ctx), M_SMMU, M_WAITOK | M_ZERO); - ctx->vendor = pci_get_vendor(child); - ctx->device = pci_get_device(child); - ctx->dev = child; - ctx->sid = sid; - ctx->domain = domain; - if (disabled) - ctx->bypass = true; - /* * Neoverse N1 SDP: * 0x800 xhci @@ -1889,14 +1910,11 @@ smmu_ctx_alloc(device_t dev, struct iommu_domain *iodom, device_t child, smmu_init_ste(sc, domain->cd, ctx->sid, ctx->bypass); - if (iommu_is_buswide_ctx(iodom->iommu, pci_get_bus(ctx->dev))) - smmu_set_buswide(dev, domain, ctx); + if (device_get_devclass(device_get_parent(ctx->dev)) == pci_class) + if (iommu_is_buswide_ctx(iodom->iommu, pci_get_bus(ctx->dev))) + smmu_set_buswide(dev, domain, ctx); - IOMMU_DOMAIN_LOCK(iodom); - LIST_INSERT_HEAD(&domain->ctx_list, ctx, next); - IOMMU_DOMAIN_UNLOCK(iodom); - - return (&ctx->ioctx); + return (0); } static void @@ -1993,6 +2011,24 @@ smmu_find(device_t dev, device_t child) return (0); } +#ifdef FDT +static int +smmu_ofw_md_data(device_t dev, struct iommu_ctx *ioctx, pcell_t *cells, + int ncells) +{ + struct smmu_ctx *ctx; + + ctx = (struct smmu_ctx *)ioctx; + + if (ncells != 1) + return (-1); + + ctx->sid = cells[0]; + + return (0); +} +#endif + static device_method_t smmu_methods[] = { /* Device interface */ DEVMETHOD(device_detach, smmu_detach), @@ -2004,8 +2040,12 @@ static device_method_t smmu_methods[] = { DEVMETHOD(iommu_domain_alloc, smmu_domain_alloc), DEVMETHOD(iommu_domain_free, smmu_domain_free), DEVMETHOD(iommu_ctx_alloc, smmu_ctx_alloc), + DEVMETHOD(iommu_ctx_init, smmu_ctx_init), DEVMETHOD(iommu_ctx_free, smmu_ctx_free), DEVMETHOD(iommu_ctx_lookup, smmu_ctx_lookup), +#ifdef FDT + DEVMETHOD(iommu_ofw_md_data, smmu_ofw_md_data), +#endif /* Bus interface */ DEVMETHOD(bus_read_ivar, smmu_read_ivar), diff --git a/sys/arm64/iommu/smmu_fdt.c b/sys/arm64/iommu/smmu_fdt.c index f2d441fe8340..e5541b50058f 100644 --- a/sys/arm64/iommu/smmu_fdt.c +++ b/sys/arm64/iommu/smmu_fdt.c @@ -176,6 +176,8 @@ smmu_fdt_attach(device_t dev) return (ENXIO); } + OF_device_register_xref(OF_xref_from_node(node), dev); + return (0); error: