diff options
| -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; } |
