From: Jason Gunthorpe <jgg@nvidia.com>
To: Naresh Kamboju <naresh.kamboju@linaro.org>
Cc: open list <linux-kernel@vger.kernel.org>,
iommu@lists.linux.dev, lkft-triage@lists.linaro.org,
Linux Regressions <regressions@lists.linux.dev>,
Nicolin Chen <nicolinc@nvidia.com>,
Jean-Philippe Brucker <jean-philippe@linaro.org>,
Anders Roxell <anders.roxell@linaro.org>,
Ben Copeland <benjamin.copeland@linaro.org>,
Arnd Bergmann <arnd@arndb.de>,
Dan Carpenter <dan.carpenter@linaro.org>
Subject: Re: next-20250702 WARNING iommu io-pgtable-arm.c at arm_lpae_map_pages qcom_iommu_map
Date: Wed, 9 Jul 2025 13:26:09 -0300 [thread overview]
Message-ID: <20250709162609.GD1599700@nvidia.com> (raw)
In-Reply-To: <CA+G9fYtOZLYe7yN7EdaEHLyJgVypgKFO2R6POoiEZv7PcLw+3A@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 1316 bytes --]
On Wed, Jul 09, 2025 at 04:14:26PM +0530, Naresh Kamboju wrote:
> I have tested this patch on top of Linux next-20250702 tag,
> and found kernel warning,
Oh, yeah, I guess that hacky fix is not going to work.
Then this is probably good enough (against linux-next):
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -335,7 +335,7 @@ static struct iommu_domain *qcom_iommu_domain_alloc_paging(struct device *dev)
mutex_init(&qcom_domain->init_mutex);
spin_lock_init(&qcom_domain->pgtbl_lock);
- qcom_domain->domain.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M;
+ qcom_domain->domain.pgsize_bitmap = SZ_4K | SZ_2M;
return &qcom_domain->domain;
}
I believe the original text was a copy and pasto from an ARMv7s driver
(ie the 32 bit ARM page table) which uses that unique combination of
sizes. It is not a sane bitmap for HW with 64 bit page table support,
there is never a 1M option for instance.
So this removes 64k page support, which maybe didn't even work?
I also prepared a proper rework that puts the pgtable allocation into
the qcom_iommu_domain_alloc_paging(). I've attached it, but it is
involved enough it probably breaks something else. However if you
want to test it maybe we can progress it too.
Thanks,
Jason
[-- Attachment #2: 0001-iommu-qcom-Allocate-the-iopgtbl-inside-qcom_iommu_do.patch --]
[-- Type: text/x-diff, Size: 8837 bytes --]
From a86762cd05296949a8fc20bcb7558aa57b137cd2 Mon Sep 17 00:00:00 2001
From: Jason Gunthorpe <jgg@nvidia.com>
Date: Wed, 9 Jul 2025 13:24:40 -0300
Subject: [PATCH] iommu/qcom: Allocate the iopgtbl inside
qcom_iommu_domain_alloc_paging()
Structure the driver the way the current driver API expects.
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
---
drivers/iommu/arm/arm-smmu/qcom_iommu.c | 159 ++++++++++--------------
1 file changed, 65 insertions(+), 94 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu/qcom_iommu.c b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
index 5891ad5de0d5e2..f65c8b50903319 100644
--- a/drivers/iommu/arm/arm-smmu/qcom_iommu.c
+++ b/drivers/iommu/arm/arm-smmu/qcom_iommu.c
@@ -66,7 +66,6 @@ struct qcom_iommu_ctx {
struct qcom_iommu_domain {
struct io_pgtable_ops *pgtbl_ops;
spinlock_t pgtbl_lock;
- struct mutex init_mutex; /* Protects iommu pointer */
struct iommu_domain domain;
struct qcom_iommu_dev *iommu;
struct iommu_fwspec *fwspec;
@@ -213,42 +212,16 @@ static irqreturn_t qcom_iommu_fault(int irq, void *dev)
return IRQ_HANDLED;
}
-static int qcom_iommu_init_domain(struct iommu_domain *domain,
- struct qcom_iommu_dev *qcom_iommu,
- struct device *dev)
+static int qcom_iommu_attach_domain(struct qcom_iommu_domain *qcom_domain,
+ struct device *dev)
{
- struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
- struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
- struct io_pgtable_ops *pgtbl_ops;
- struct io_pgtable_cfg pgtbl_cfg;
+ struct qcom_iommu_dev *qcom_iommu = qcom_domain->iommu;
+ struct iommu_fwspec *fwspec = qcom_domain->fwspec;
+ struct io_pgtable_cfg *pgtbl_cfg =
+ &io_pgtable_ops_to_pgtable(qcom_domain->pgtbl_ops)->cfg;
int i, ret = 0;
u32 reg;
- mutex_lock(&qcom_domain->init_mutex);
- if (qcom_domain->iommu)
- goto out_unlock;
-
- pgtbl_cfg = (struct io_pgtable_cfg) {
- .pgsize_bitmap = domain->pgsize_bitmap,
- .ias = 32,
- .oas = 40,
- .tlb = &qcom_flush_ops,
- .iommu_dev = qcom_iommu->dev,
- };
-
- qcom_domain->iommu = qcom_iommu;
- qcom_domain->fwspec = fwspec;
-
- pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, qcom_domain);
- if (!pgtbl_ops) {
- dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
- ret = -ENOMEM;
- goto out_clear_iommu;
- }
-
- domain->geometry.aperture_end = (1ULL << pgtbl_cfg.ias) - 1;
- domain->geometry.force_aperture = true;
-
for (i = 0; i < fwspec->num_ids; i++) {
struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
@@ -256,14 +229,14 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
ret = qcom_scm_restore_sec_cfg(qcom_iommu->sec_id, ctx->asid);
if (ret) {
dev_err(qcom_iommu->dev, "secure init failed: %d\n", ret);
- goto out_clear_iommu;
+ return ret;
}
ctx->secure_init = true;
}
/* Secured QSMMU-500/QSMMU-v2 contexts cannot be programmed */
if (ctx->secured_ctx) {
- ctx->domain = domain;
+ ctx->domain = &qcom_domain->domain;
continue;
}
@@ -276,21 +249,21 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
/* TTBRs */
iommu_writeq(ctx, ARM_SMMU_CB_TTBR0,
- pgtbl_cfg.arm_lpae_s1_cfg.ttbr |
+ pgtbl_cfg->arm_lpae_s1_cfg.ttbr |
FIELD_PREP(ARM_SMMU_TTBRn_ASID, ctx->asid));
iommu_writeq(ctx, ARM_SMMU_CB_TTBR1, 0);
/* TCR */
iommu_writel(ctx, ARM_SMMU_CB_TCR2,
- arm_smmu_lpae_tcr2(&pgtbl_cfg));
+ arm_smmu_lpae_tcr2(pgtbl_cfg));
iommu_writel(ctx, ARM_SMMU_CB_TCR,
- arm_smmu_lpae_tcr(&pgtbl_cfg) | ARM_SMMU_TCR_EAE);
+ arm_smmu_lpae_tcr(pgtbl_cfg) | ARM_SMMU_TCR_EAE);
/* MAIRs (stage-1 only) */
iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR0,
- pgtbl_cfg.arm_lpae_s1_cfg.mair);
+ pgtbl_cfg->arm_lpae_s1_cfg.mair);
iommu_writel(ctx, ARM_SMMU_CB_S1_MAIR1,
- pgtbl_cfg.arm_lpae_s1_cfg.mair >> 32);
+ pgtbl_cfg->arm_lpae_s1_cfg.mair >> 32);
/* SCTLR */
reg = ARM_SMMU_SCTLR_CFIE | ARM_SMMU_SCTLR_CFRE |
@@ -303,58 +276,74 @@ static int qcom_iommu_init_domain(struct iommu_domain *domain,
iommu_writel(ctx, ARM_SMMU_CB_SCTLR, reg);
- ctx->domain = domain;
+ ctx->domain = &qcom_domain->domain;
}
-
- mutex_unlock(&qcom_domain->init_mutex);
-
- /* Publish page table ops for map/unmap */
- qcom_domain->pgtbl_ops = pgtbl_ops;
-
return 0;
-
-out_clear_iommu:
- qcom_domain->iommu = NULL;
-out_unlock:
- mutex_unlock(&qcom_domain->init_mutex);
- return ret;
}
static struct iommu_domain *qcom_iommu_domain_alloc_paging(struct device *dev)
{
+ struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
struct qcom_iommu_domain *qcom_domain;
+ struct io_pgtable_ops *pgtbl_ops;
+ struct io_pgtable_cfg pgtbl_cfg;
+ int ret;
- /*
- * Allocate the domain and initialise some of its data structures.
- * We can't really do anything meaningful until we've added a
- * master.
- */
qcom_domain = kzalloc(sizeof(*qcom_domain), GFP_KERNEL);
if (!qcom_domain)
return NULL;
- mutex_init(&qcom_domain->init_mutex);
spin_lock_init(&qcom_domain->pgtbl_lock);
- qcom_domain->domain.pgsize_bitmap = SZ_4K | SZ_64K | SZ_1M | SZ_16M;
+
+ pgtbl_cfg = (struct io_pgtable_cfg) {
+ .pgsize_bitmap = SZ_4K | SZ_64K | SZ_2M,
+ .ias = 32,
+ .oas = 40,
+ .tlb = &qcom_flush_ops,
+ .iommu_dev = qcom_iommu->dev,
+ };
+
+ qcom_domain->iommu = qcom_iommu;
+
+ /*
+ * This driver doesn't keep track of devices attached to a domain,
+ * so each domain is single device. The single fwspec is used
+ * to push the invalidations.
+ */
+ qcom_domain->fwspec = dev_iommu_fwspec_get(dev);
+
+ pgtbl_ops = alloc_io_pgtable_ops(ARM_32_LPAE_S1, &pgtbl_cfg, qcom_domain);
+ if (!pgtbl_ops) {
+ dev_err(qcom_iommu->dev, "failed to allocate pagetable ops\n");
+ ret = -ENOMEM;
+ goto err_free;
+ }
+
+ qcom_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
+ qcom_domain->domain.geometry.aperture_end = (1ULL << pgtbl_cfg.ias) - 1;
+ qcom_domain->domain.geometry.force_aperture = true;
+ qcom_domain->pgtbl_ops = pgtbl_ops;
return &qcom_domain->domain;
+
+err_free:
+ kfree(qcom_domain);
+ return ERR_PTR(ret);
}
static void qcom_iommu_domain_free(struct iommu_domain *domain)
{
struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
- if (qcom_domain->iommu) {
- /*
- * NOTE: unmap can be called after client device is powered
- * off, for example, with GPUs or anything involving dma-buf.
- * So we cannot rely on the device_link. Make sure the IOMMU
- * is on to avoid unclocked accesses in the TLB inv path:
- */
- pm_runtime_get_sync(qcom_domain->iommu->dev);
- free_io_pgtable_ops(qcom_domain->pgtbl_ops);
- pm_runtime_put_sync(qcom_domain->iommu->dev);
- }
+ /*
+ * NOTE: unmap can be called after client device is powered
+ * off, for example, with GPUs or anything involving dma-buf.
+ * So we cannot rely on the device_link. Make sure the IOMMU
+ * is on to avoid unclocked accesses in the TLB inv path:
+ */
+ pm_runtime_get_sync(qcom_domain->iommu->dev);
+ free_io_pgtable_ops(qcom_domain->pgtbl_ops);
+ pm_runtime_put_sync(qcom_domain->iommu->dev);
kfree(qcom_domain);
}
@@ -365,47 +354,29 @@ static int qcom_iommu_attach_dev(struct iommu_domain *domain, struct device *dev
struct qcom_iommu_domain *qcom_domain = to_qcom_iommu_domain(domain);
int ret;
- if (!qcom_iommu) {
- dev_err(dev, "cannot attach to IOMMU, is it on the same bus?\n");
- return -ENXIO;
- }
+ if (qcom_domain->iommu != qcom_iommu ||
+ qcom_domain->fwspec != dev_iommu_fwspec_get(dev))
+ return -EINVAL;
/* Ensure that the domain is finalized */
pm_runtime_get_sync(qcom_iommu->dev);
- ret = qcom_iommu_init_domain(domain, qcom_iommu, dev);
+ ret = qcom_iommu_attach_domain(qcom_domain, dev);
pm_runtime_put_sync(qcom_iommu->dev);
if (ret < 0)
return ret;
-
- /*
- * Sanity check the domain. We don't support domains across
- * different IOMMUs.
- */
- if (qcom_domain->iommu != qcom_iommu)
- return -EINVAL;
-
return 0;
}
static int qcom_iommu_identity_attach(struct iommu_domain *identity_domain,
struct device *dev)
{
- struct iommu_domain *domain = iommu_get_domain_for_dev(dev);
- struct qcom_iommu_domain *qcom_domain;
struct iommu_fwspec *fwspec = dev_iommu_fwspec_get(dev);
struct qcom_iommu_dev *qcom_iommu = dev_iommu_priv_get(dev);
unsigned int i;
- if (domain == identity_domain || !domain)
- return 0;
-
- qcom_domain = to_qcom_iommu_domain(domain);
- if (WARN_ON(!qcom_domain->iommu))
- return -EINVAL;
-
pm_runtime_get_sync(qcom_iommu->dev);
for (i = 0; i < fwspec->num_ids; i++) {
- struct qcom_iommu_ctx *ctx = to_ctx(qcom_domain, fwspec->ids[i]);
+ struct qcom_iommu_ctx *ctx = qcom_iommu->ctxs[fwspec->ids[i]];
/* Disable the context bank: */
iommu_writel(ctx, ARM_SMMU_CB_SCTLR, 0);
--
2.43.0
next prev parent reply other threads:[~2025-07-09 16:26 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-08 20:56 next-20250702 WARNING iommu io-pgtable-arm.c at arm_lpae_map_pages qcom_iommu_map Naresh Kamboju
2025-07-09 0:25 ` Jason Gunthorpe
2025-07-09 10:44 ` Naresh Kamboju
2025-07-09 16:26 ` Jason Gunthorpe [this message]
2025-07-09 16:50 ` Arnd Bergmann
2025-07-09 17:22 ` Jason Gunthorpe
2025-07-10 10:38 ` Naresh Kamboju
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250709162609.GD1599700@nvidia.com \
--to=jgg@nvidia.com \
--cc=anders.roxell@linaro.org \
--cc=arnd@arndb.de \
--cc=benjamin.copeland@linaro.org \
--cc=dan.carpenter@linaro.org \
--cc=iommu@lists.linux.dev \
--cc=jean-philippe@linaro.org \
--cc=linux-kernel@vger.kernel.org \
--cc=lkft-triage@lists.linaro.org \
--cc=naresh.kamboju@linaro.org \
--cc=nicolinc@nvidia.com \
--cc=regressions@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.