From: fangyu.yu@linux.alibaba.com
To: tjeznach@rivosinc.com, joro@8bytes.org, will@kernel.org,
robin.murphy@arm.com, pjw@kernel.org, palmer@dabbelt.com,
aou@eecs.berkeley.edu, alex@ghiti.fr,
andrew.jones@oss.qualcomm.com
Cc: guoren@kernel.org, iommu@lists.linux.dev,
linux-kernel@vger.kernel.org, linux-riscv@lists.infradead.org,
Fangyu Yu <fangyu.yu@linux.alibaba.com>
Subject: [PATCH 2/2] iommu/riscv: Add non-leaf invalidation support
Date: Sun, 8 Feb 2026 22:42:13 +0800 [thread overview]
Message-ID: <20260208144213.94856-3-fangyu.yu@linux.alibaba.com> (raw)
In-Reply-To: <20260208144213.94856-1-fangyu.yu@linux.alibaba.com>
From: Fangyu Yu <fangyu.yu@linux.alibaba.com>
The RISC-V IOMMU v1.0.1 spec adds the Non-leaf PTE Invalidation extension
(capabilities.NL) which allows IOTINVAL.VMA to invalidate cached non-leaf
PTE information when performing address-specific invalidations.
Add the NL capability bit definition and the IOTINVAL.VMA NL operand bit,
and provide a helper to set NL in an invalidation command.
Extend the internal IOTLB invalidation helpers to optionally request non-
leaf invalidation and, when mapping replaces non-leaf page-table entries
(freelist is not empty), invalidate the affected IOVA range with non-leaf
semantics instead of falling back to invalidate-all.
This reduces the scope of invalidations while keeping compatibility with
implementations that do not support the NL extension.
Signed-off-by: Fangyu Yu <fangyu.yu@linux.alibaba.com>
---
drivers/iommu/riscv/iommu-bits.h | 7 +++++++
drivers/iommu/riscv/iommu.c | 29 +++++++++++++++++++++++------
2 files changed, 30 insertions(+), 6 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 0d1f8813ae31..35bb9eaa5214 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -62,6 +62,7 @@
#define RISCV_IOMMU_CAPABILITIES_PD8 BIT_ULL(38)
#define RISCV_IOMMU_CAPABILITIES_PD17 BIT_ULL(39)
#define RISCV_IOMMU_CAPABILITIES_PD20 BIT_ULL(40)
+#define RISCV_IOMMU_CAPABILITIES_NL BIT_ULL(42)
#define RISCV_IOMMU_CAPABILITIES_S BIT_ULL(43)
/**
@@ -473,6 +474,7 @@ struct riscv_iommu_command {
#define RISCV_IOMMU_CMD_IOTINVAL_PSCV BIT_ULL(32)
#define RISCV_IOMMU_CMD_IOTINVAL_GV BIT_ULL(33)
#define RISCV_IOMMU_CMD_IOTINVAL_GSCID GENMASK_ULL(59, 44)
+#define RISCV_IOMMU_CMD_IOTINVAL_NL BIT_ULL(34)
#define RISCV_IOMMU_CMD_IOTINVAL_S BIT_ULL(9)
/* dword1[61:10] is the 4K-aligned page address */
#define RISCV_IOMMU_CMD_IOTINVAL_ADDR GENMASK_ULL(61, 10)
@@ -732,6 +734,11 @@ static inline void riscv_iommu_cmd_inval_set_addr(struct riscv_iommu_command *cm
cmd->dword0 |= RISCV_IOMMU_CMD_IOTINVAL_AV;
}
+static inline void riscv_iommu_cmd_inval_set_nonleaf(struct riscv_iommu_command *cmd)
+{
+ cmd->dword0 |= RISCV_IOMMU_CMD_IOTINVAL_NL;
+}
+
static inline void riscv_iommu_cmd_inval_set_pscid(struct riscv_iommu_command *cmd,
int pscid)
{
diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c
index ae48409a052a..acc82c8626ce 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -933,7 +933,8 @@ static unsigned long range_encode(unsigned long start, unsigned long size)
}
static void riscv_iommu_iotlb_inval_range(struct riscv_iommu_domain *domain,
struct riscv_iommu_device *iommu,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end,
+ bool non_leaf)
{
struct riscv_iommu_command cmd;
unsigned long len = end - start + 1;
@@ -962,6 +963,16 @@ static void riscv_iommu_iotlb_inval_range(struct riscv_iommu_domain *domain,
limit = PAGE_ALIGN(end + 1);
cur = page_start;
+ if (non_leaf) {
+ if (!!(iommu->caps & RISCV_IOMMU_CAPABILITIES_NL)) {
+ riscv_iommu_cmd_inval_set_nonleaf(&cmd);
+ } else {
+ /* Falls back to whole address space invalidation */
+ riscv_iommu_cmd_send(iommu, &cmd);
+ return;
+ }
+ }
+
while (cur < limit) {
max_range = 0;
@@ -1004,7 +1015,8 @@ static void riscv_iommu_iotlb_inval_range(struct riscv_iommu_domain *domain,
#define RISCV_IOMMU_IOTLB_INVAL_LIMIT (2 << 20)
static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
- unsigned long start, unsigned long end)
+ unsigned long start, unsigned long end,
+ bool non_leaf)
{
struct riscv_iommu_bond *bond;
struct riscv_iommu_device *iommu, *prev;
@@ -1052,8 +1064,11 @@ static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain,
continue;
if (!!(iommu->caps & RISCV_IOMMU_CAPABILITIES_S)) {
- riscv_iommu_iotlb_inval_range(domain, iommu, start, end);
+ riscv_iommu_iotlb_inval_range(domain, iommu, start, end, non_leaf);
continue;
+ } else if (non_leaf) {
+ /* Falls back to whole address space invalidation */
+ len = ULONG_MAX;
}
riscv_iommu_cmd_inval_vma(&cmd);
@@ -1155,7 +1170,7 @@ static void riscv_iommu_iotlb_flush_all(struct iommu_domain *iommu_domain)
{
struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain);
- riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX);
+ riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX, false);
}
static void riscv_iommu_iotlb_sync(struct iommu_domain *iommu_domain,
@@ -1163,7 +1178,7 @@ static void riscv_iommu_iotlb_sync(struct iommu_domain *iommu_domain,
{
struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain);
- riscv_iommu_iotlb_inval(domain, gather->start, gather->end);
+ riscv_iommu_iotlb_inval(domain, gather->start, gather->end, false);
}
#define PT_SHIFT (PAGE_SHIFT - ilog2(sizeof(pte_t)))
@@ -1284,6 +1299,7 @@ static int riscv_iommu_map_pages(struct iommu_domain *iommu_domain,
unsigned long pte, old, pte_prot;
int rc = 0;
struct iommu_pages_list freelist = IOMMU_PAGES_LIST_INIT(freelist);
+ unsigned long inval_start = iova;
if (!(prot & IOMMU_WRITE))
pte_prot = _PAGE_BASE | _PAGE_READ;
@@ -1322,7 +1338,8 @@ static int riscv_iommu_map_pages(struct iommu_domain *iommu_domain,
* This will be updated with hardware support for
* capability.NL (non-leaf) IOTINVAL command.
*/
- riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX);
+ riscv_iommu_iotlb_inval(domain, inval_start,
+ inval_start + size - 1, true);
iommu_put_pages_list(&freelist);
}
--
2.50.1
_______________________________________________
linux-riscv mailing list
linux-riscv@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-riscv
next prev parent reply other threads:[~2026-02-08 14:43 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-08 14:42 [PATCH 0/2] iommu/riscv: support range and non-leaf IOTLB invalidation fangyu.yu
2026-02-08 14:42 ` [PATCH 1/2] iommu/riscv: Add NAPOT range invalidation support for IOTINVAL fangyu.yu
2026-02-08 14:42 ` fangyu.yu [this message]
2026-02-10 13:02 ` [PATCH 0/2] iommu/riscv: support range and non-leaf IOTLB invalidation Jason Gunthorpe
2026-02-11 12:07 ` fangyu.yu
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=20260208144213.94856-3-fangyu.yu@linux.alibaba.com \
--to=fangyu.yu@linux.alibaba.com \
--cc=alex@ghiti.fr \
--cc=andrew.jones@oss.qualcomm.com \
--cc=aou@eecs.berkeley.edu \
--cc=guoren@kernel.org \
--cc=iommu@lists.linux.dev \
--cc=joro@8bytes.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-riscv@lists.infradead.org \
--cc=palmer@dabbelt.com \
--cc=pjw@kernel.org \
--cc=robin.murphy@arm.com \
--cc=tjeznach@rivosinc.com \
--cc=will@kernel.org \
/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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox