[PATCH v4 8/8] iommu/arm-smmu-v3: Support the DS expansion of RIL's SCALE
Jason Gunthorpe
jgg at nvidia.com
Wed Aug 5 12:15:26 PDT 2026
If DS is supported then SCALE can go up to 39. Compute a scale max that is
compatible for the entire invs list.
Reviewed-by: Nicolin Chen <nicolinc at nvidia.com>
Tested-by: Nicolin Chen <nicolinc at nvidia.com>
Signed-off-by: Jason Gunthorpe <jgg at nvidia.com>
---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c | 13 ++++++++++---
drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h | 2 ++
2 files changed, 12 insertions(+), 3 deletions(-)
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
index 5d3fed4d13a217..22ff4aa01d208a 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c
@@ -1056,6 +1056,8 @@ static inline int arm_smmu_invs_iter_next_cmp(struct arm_smmu_invs *invs_l,
static void arm_smmu_invs_update_caps(struct arm_smmu_invs *invs,
const struct arm_smmu_inv *inv)
{
+ unsigned int scale_max;
+
if (arm_smmu_inv_is_ats(inv))
invs->has_ats = true;
@@ -1063,6 +1065,9 @@ static void arm_smmu_invs_update_caps(struct arm_smmu_invs *invs,
return;
invs->has_range_inv = true;
+ scale_max = (inv->smmu->features & ARM_SMMU_FEAT_DS) ? 39 : 31;
+ if (!invs->range_inv_scale_max || scale_max < invs->range_inv_scale_max)
+ invs->range_inv_scale_max = scale_max;
}
/**
@@ -2558,7 +2563,8 @@ static unsigned int arm_smmu_compute_ttl(u8 leaf_bitmap, u8 table_bitmap,
* fits in the 5-bit NUM field (max 32 units of 2^SCALE pages). This may widen
* the invalidation range.
*/
-static void arm_smmu_tlbi_calc_range(struct arm_smmu_tlbi *tlbi)
+static void arm_smmu_tlbi_calc_range(struct arm_smmu_tlbi *tlbi,
+ unsigned int scale_max)
{
u8 tgsz_lg2 = tlbi->tgsz_lg2;
unsigned int ttl = arm_smmu_compute_ttl(
@@ -2607,7 +2613,7 @@ static void arm_smmu_tlbi_calc_range(struct arm_smmu_tlbi *tlbi)
* address beyond alignment to tg (so long as TTL=0).
*/
scale = fls64((num_tg - 1) / 32);
- if (scale > 31) {
+ if (scale > scale_max) {
/*
* Range too large for a single command, use full invalidation.
*/
@@ -2859,7 +2865,8 @@ void arm_smmu_domain_tlbi(struct arm_smmu_tlbi *tlbi,
*/
if (invs->has_range_inv) {
if (!tlbi->range.use_full_inv)
- arm_smmu_tlbi_calc_range(tlbi);
+ arm_smmu_tlbi_calc_range(tlbi,
+ invs->range_inv_scale_max);
}
/*
diff --git a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
index e381fca5a2be6f..fc4fe43d7fe53b 100644
--- a/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
+++ b/drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h
@@ -759,6 +759,7 @@ static inline bool arm_smmu_inv_is_ats(const struct arm_smmu_inv *inv)
* @rwlock: optional rwlock to fence ATS operations
* @has_ats: flag if the array contains an INV_TYPE_ATS or INV_TYPE_ATS_FULL
* @has_range_inv: flag if any entry's SMMU supports range invalidation
+ * @range_inv_scale_max: max SCALE usable by all range-capable SMMUs
* @rcu: rcu head for kfree_rcu()
* @inv: flexible invalidation array
*
@@ -789,6 +790,7 @@ struct arm_smmu_invs {
rwlock_t rwlock;
bool has_ats;
bool has_range_inv;
+ u8 range_inv_scale_max;
struct rcu_head rcu;
struct arm_smmu_inv inv[] __counted_by(max_invs);
};
--
2.43.0
More information about the linux-arm-kernel
mailing list