#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
#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)
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)
{
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;
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;
}