diff options
| author | Jason Gunthorpe <jgg@nvidia.com> | 2026-05-08 11:53:05 -0300 |
|---|---|---|
| committer | Joerg Roedel <joerg.roedel@amd.com> | 2026-05-19 10:48:09 +0200 |
| commit | e4084c6bbb42b0ef2dbfceca70513cc1f49aff61 (patch) | |
| tree | a58045f7ee39afed70ad6130062bcc901fbb5e50 /drivers | |
| parent | bb62adcf451336301f75763d3a4851febf1dd9ba (diff) | |
iommu/riscv: Add RISCV_IOMMU_CAPABILITIES_NL
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.
Reviewed-by: Tomasz Jeznach <tjeznach@rivosinc.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
Tested-by: Andrew Jones <andrew.jones@oss.qualcomm.com>
Signed-off-by: Joerg Roedel <joerg.roedel@amd.com>
Diffstat (limited to 'drivers')
| -rw-r--r-- | drivers/iommu/riscv/iommu-bits.h | 7 | ||||
| -rw-r--r-- | 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 29a0040b1c32..f01b49ac8155 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 719d3b475d61..165ced993756 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; } |
