[PATCH 6/7] iommu/riscv: Add RISCV_IOMMU_CAPABILITIES_NL

Tomasz Jeznach tjeznach at rivosinc.com
Tue May 5 09:35:04 PDT 2026


On Fri, Apr 10, 2026 at 8:57 AM Jason Gunthorpe <jgg at nvidia.com> wrote:
>
> 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
>

Reviewed-by: Tomasz Jeznach <tjeznach at rivosinc.com>

Thank you,
- Tomasz



More information about the linux-riscv mailing list