diff options
| author | Jason Gunthorpe <jgg@nvidia.com> | 2026-05-08 11:53:03 -0300 |
|---|---|---|
| committer | Joerg Roedel <joerg.roedel@amd.com> | 2026-05-19 10:48:08 +0200 |
| commit | db1aad42ca8b37437846078dfc405abda7868261 (patch) | |
| tree | 631e6f4444faedb166b6b8ca685f0cc39f33ac09 | |
| parent | 89792629d4b260104555f9719ac84c1afc9a2012 (diff) | |
| download | linux-db1aad42ca8b37437846078dfc405abda7868261.tar.gz linux-db1aad42ca8b37437846078dfc405abda7868261.zip | |
iommu/riscv: Enable PT_FEAT_DETAILED_GATHER and pass gather to iotlb_inval
RISC-V can use the information from PT_FEAT_DETAILED_GATHER to
compute the best stride to generate the single TLB invalidations.
Pass the gather down to the lower functions and create a full-range
gather for the flush-all callback.
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>
| -rw-r--r-- | drivers/iommu/generic_pt/fmt/iommu_riscv64.c | 4 | ||||
| -rw-r--r-- | drivers/iommu/riscv/iommu.c | 44 |
2 files changed, 31 insertions, 17 deletions
diff --git a/drivers/iommu/generic_pt/fmt/iommu_riscv64.c b/drivers/iommu/generic_pt/fmt/iommu_riscv64.c index cbf60fffa9bf..b18fc4d109f5 100644 --- a/drivers/iommu/generic_pt/fmt/iommu_riscv64.c +++ b/drivers/iommu/generic_pt/fmt/iommu_riscv64.c @@ -6,6 +6,8 @@ #define PT_FMT_VARIANT 64 #define PT_SUPPORTED_FEATURES \ (BIT(PT_FEAT_SIGN_EXTEND) | BIT(PT_FEAT_FLUSH_RANGE) | \ - BIT(PT_FEAT_RISCV_SVNAPOT_64K)) + BIT(PT_FEAT_RISCV_SVNAPOT_64K) | \ + BIT(PT_FEAT_DETAILED_GATHER)) +#define PT_FORCE_ENABLED_FEATURES BIT(PT_FEAT_DETAILED_GATHER) #include "iommu_template.h" diff --git a/drivers/iommu/riscv/iommu.c b/drivers/iommu/riscv/iommu.c index 6c324f9fdc53..8ea085263f44 100644 --- a/drivers/iommu/riscv/iommu.c +++ b/drivers/iommu/riscv/iommu.c @@ -929,13 +929,29 @@ static void riscv_iommu_bond_unlink(struct riscv_iommu_domain *domain, #define RISCV_IOMMU_IOTLB_INVAL_LIMIT (2 << 20) static void riscv_iommu_iotlb_inval(struct riscv_iommu_domain *domain, - unsigned long start, unsigned long end) + struct iommu_iotlb_gather *gather) { + unsigned long start; + unsigned long end; struct riscv_iommu_bond *bond; struct riscv_iommu_device *iommu, *prev; struct riscv_iommu_command cmd; /* + * 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 (gather->pt.table_levels_bitmap) { + start = 0; + end = ULONG_MAX; + } else { + start = gather->start; + end = gather->end; + } + + /* * For each IOMMU linked with this protection domain (via bonds->dev), * an IOTLB invaliation command will be submitted and executed. * @@ -1145,8 +1161,14 @@ static void riscv_iommu_iodir_update(struct riscv_iommu_device *iommu, static void riscv_iommu_iotlb_flush_all(struct iommu_domain *iommu_domain) { struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); + struct iommu_iotlb_gather gather = { + .start = 0, + .end = ULONG_MAX, + .pt.leaf_levels_bitmap = 0xFF, + .pt.table_levels_bitmap = 0xFE, + }; - riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX); + riscv_iommu_iotlb_inval(domain, &gather); } static void riscv_iommu_iotlb_sync(struct iommu_domain *iommu_domain, @@ -1154,19 +1176,8 @@ static void riscv_iommu_iotlb_sync(struct iommu_domain *iommu_domain, { struct riscv_iommu_domain *domain = iommu_domain_to_riscv(iommu_domain); - if (iommu_pages_list_empty(&gather->freelist)) { - riscv_iommu_iotlb_inval(domain, gather->start, gather->end); - } else { - /* - * In 1.0 spec version, the smallest scope we can use to - * invalidate all levels of page table (i.e. leaf and non-leaf) - * is an invalidate-all-PSCID IOTINVAL.VMA with AV=0. - * This will be updated with hardware support for - * capability.NL (non-leaf) IOTINVAL command. - */ - riscv_iommu_iotlb_inval(domain, 0, ULONG_MAX); - iommu_put_pages_list(&gather->freelist); - } + riscv_iommu_iotlb_inval(domain, gather); + iommu_put_pages_list(&gather->freelist); } static void riscv_iommu_free_paging_domain(struct iommu_domain *iommu_domain) @@ -1267,7 +1278,8 @@ static struct iommu_domain *riscv_iommu_alloc_paging_domain(struct device *dev) */ cfg.common.features = BIT(PT_FEAT_SIGN_EXTEND) | BIT(PT_FEAT_FLUSH_RANGE) | - BIT(PT_FEAT_RISCV_SVNAPOT_64K); + BIT(PT_FEAT_RISCV_SVNAPOT_64K) | + BIT(PT_FEAT_DETAILED_GATHER); if (iommu->caps & RISCV_IOMMU_CAPABILITIES_SVPBMT) cfg.common.features |= BIT(PT_FEAT_RISCV_SVPBMT); domain->riscvpt.iommu.nid = dev_to_node(iommu->dev); |
