[PATCH 6/7] iommu/riscv: Add RISCV_IOMMU_CAPABILITIES_NL
Jason Gunthorpe
jgg at nvidia.com
Fri Apr 10 08:57:07 PDT 2026
Non-leaf invalidation allows the single invalidate command to also
clear the walk cache. If NL is available, set the NL bit if the
gather indicates tables have been changed. The stride is already
calculated properly.
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/iommu/riscv/iommu-bits.h | 7 +++++++
drivers/iommu/riscv/iommu.c | 12 +++++++-----
2 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/drivers/iommu/riscv/iommu-bits.h b/drivers/iommu/riscv/iommu-bits.h
index 29a0040b1c32ea..f01b49ac815586 100644
--- a/drivers/iommu/riscv/iommu-bits.h
+++ b/drivers/iommu/riscv/iommu-bits.h
@@ -63,6 +63,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)
/**
* enum riscv_iommu_igs_settings - Interrupt Generation Support Settings
@@ -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)
/* dword1[61:10] is the 4K-aligned page address */
#define RISCV_IOMMU_CMD_IOTINVAL_ADDR GENMASK_ULL(61, 10)
@@ -724,6 +726,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_nl(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 fd9c5294dbc082..ea14630430451a 100644
--- a/drivers/iommu/riscv/iommu.c
+++ b/drivers/iommu/riscv/iommu.c
@@ -966,6 +966,8 @@ static void riscv_iommu_iotlb_inval_iommu(struct riscv_iommu_device *iommu,
int pscid,
struct riscv_iommu_tlbi *tlbi)
{
+ bool use_nl = tlbi->non_leaf &&
+ (iommu->caps & RISCV_IOMMU_CAPABILITIES_NL);
struct riscv_iommu_command cmd;
unsigned long iova;
unsigned int i;
@@ -974,17 +976,17 @@ static void riscv_iommu_iotlb_inval_iommu(struct riscv_iommu_device *iommu,
riscv_iommu_cmd_inval_set_pscid(&cmd, pscid);
/*
- * When non-leaf page table entries were changed, the base spec
- * requires a full PSCID invalidation (AV=0) since there is no
- * way to do targeted non-leaf invalidation without the NL
- * extension. Force global invalidation to preserve correctness.
+ * If non-leaf entries were changed and the IOMMU doesn't
+ * support NL, we must fall back to global invalidation (AV=0).
*/
- if (tlbi->single.use_global || tlbi->non_leaf)
+ if (tlbi->single.use_global || (tlbi->non_leaf && !use_nl))
goto global;
iova = tlbi->start;
for (i = 0; i < tlbi->single.num; i++) {
riscv_iommu_cmd_inval_set_addr(&cmd, iova);
+ if (use_nl)
+ riscv_iommu_cmd_inval_set_nl(&cmd);
riscv_iommu_cmd_send(iommu, &cmd);
iova += 1ULL << tlbi->single.stride_lg2;
}
--
2.43.0
More information about the linux-riscv
mailing list