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: