Skip to content

Commit 6a481a9

Browse files
robherringwilldeacon
authored andcommitted
iommu/arm-smmu-v3: Add SMMUv3.2 range invalidation support
Arm SMMUv3.2 adds support for TLB range invalidate operations. Support for range invalidate is determined by the RIL bit in the IDR3 register. The range invalidate is in units of the leaf page size and operates on 1-32 chunks of a power of 2 multiple pages. First, we determine from the size what power of 2 multiple we can use. Then we calculate how many chunks (1-31) of the power of 2 size for the range on the iteration. On each iteration, we move up in size by at least 5 bits. Cc: Jean-Philippe Brucker <[email protected]> Cc: Will Deacon <[email protected]> Cc: Robin Murphy <[email protected]> Cc: Joerg Roedel <[email protected]> Reviewed-by: Eric Auger <[email protected]> Signed-off-by: Rob Herring <[email protected]> Signed-off-by: Will Deacon <[email protected]>
1 parent 9e773ae commit 6a481a9

File tree

1 file changed

+67
-2
lines changed

1 file changed

+67
-2
lines changed

drivers/iommu/arm-smmu-v3.c

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,9 @@
6969
#define IDR1_SSIDSIZE GENMASK(10, 6)
7070
#define IDR1_SIDSIZE GENMASK(5, 0)
7171

72+
#define ARM_SMMU_IDR3 0xc
73+
#define IDR3_RIL (1 << 10)
74+
7275
#define ARM_SMMU_IDR5 0x14
7376
#define IDR5_STALL_MAX GENMASK(31, 16)
7477
#define IDR5_GRAN64K (1 << 6)
@@ -346,9 +349,14 @@
346349
#define CMDQ_CFGI_1_LEAF (1UL << 0)
347350
#define CMDQ_CFGI_1_RANGE GENMASK_ULL(4, 0)
348351

352+
#define CMDQ_TLBI_0_NUM GENMASK_ULL(16, 12)
353+
#define CMDQ_TLBI_RANGE_NUM_MAX 31
354+
#define CMDQ_TLBI_0_SCALE GENMASK_ULL(24, 20)
349355
#define CMDQ_TLBI_0_VMID GENMASK_ULL(47, 32)
350356
#define CMDQ_TLBI_0_ASID GENMASK_ULL(63, 48)
351357
#define CMDQ_TLBI_1_LEAF (1UL << 0)
358+
#define CMDQ_TLBI_1_TTL GENMASK_ULL(9, 8)
359+
#define CMDQ_TLBI_1_TG GENMASK_ULL(11, 10)
352360
#define CMDQ_TLBI_1_VA_MASK GENMASK_ULL(63, 12)
353361
#define CMDQ_TLBI_1_IPA_MASK GENMASK_ULL(51, 12)
354362

@@ -473,9 +481,13 @@ struct arm_smmu_cmdq_ent {
473481
#define CMDQ_OP_TLBI_S2_IPA 0x2a
474482
#define CMDQ_OP_TLBI_NSNH_ALL 0x30
475483
struct {
484+
u8 num;
485+
u8 scale;
476486
u16 asid;
477487
u16 vmid;
478488
bool leaf;
489+
u8 ttl;
490+
u8 tg;
479491
u64 addr;
480492
} tlbi;
481493

@@ -632,6 +644,7 @@ struct arm_smmu_device {
632644
#define ARM_SMMU_FEAT_HYP (1 << 12)
633645
#define ARM_SMMU_FEAT_STALL_FORCE (1 << 13)
634646
#define ARM_SMMU_FEAT_VAX (1 << 14)
647+
#define ARM_SMMU_FEAT_RANGE_INV (1 << 15)
635648
u32 features;
636649

637650
#define ARM_SMMU_OPT_SKIP_PREFETCH (1 << 0)
@@ -900,14 +913,22 @@ static int arm_smmu_cmdq_build_cmd(u64 *cmd, struct arm_smmu_cmdq_ent *ent)
900913
cmd[1] |= FIELD_PREP(CMDQ_CFGI_1_RANGE, 31);
901914
break;
902915
case CMDQ_OP_TLBI_NH_VA:
916+
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
917+
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
903918
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
904919
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_ASID, ent->tlbi.asid);
905920
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
921+
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
922+
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
906923
cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_VA_MASK;
907924
break;
908925
case CMDQ_OP_TLBI_S2_IPA:
926+
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_NUM, ent->tlbi.num);
927+
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_SCALE, ent->tlbi.scale);
909928
cmd[0] |= FIELD_PREP(CMDQ_TLBI_0_VMID, ent->tlbi.vmid);
910929
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_LEAF, ent->tlbi.leaf);
930+
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TTL, ent->tlbi.ttl);
931+
cmd[1] |= FIELD_PREP(CMDQ_TLBI_1_TG, ent->tlbi.tg);
911932
cmd[1] |= ent->tlbi.addr & CMDQ_TLBI_1_IPA_MASK;
912933
break;
913934
case CMDQ_OP_TLBI_NH_ASID:
@@ -2252,7 +2273,8 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
22522273
struct arm_smmu_domain *smmu_domain)
22532274
{
22542275
struct arm_smmu_device *smmu = smmu_domain->smmu;
2255-
unsigned long start = iova, end = iova + size;
2276+
unsigned long start = iova, end = iova + size, num_pages = 0, tg = 0;
2277+
size_t inv_range = granule;
22562278
struct arm_smmu_cmdq_batch cmds = {};
22572279
struct arm_smmu_cmdq_ent cmd = {
22582280
.tlbi = {
@@ -2271,10 +2293,48 @@ static void arm_smmu_tlb_inv_range(unsigned long iova, size_t size,
22712293
cmd.tlbi.vmid = smmu_domain->s2_cfg.vmid;
22722294
}
22732295

2296+
if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
2297+
/* Get the leaf page size */
2298+
tg = __ffs(smmu_domain->domain.pgsize_bitmap);
2299+
2300+
/* Convert page size of 12,14,16 (log2) to 1,2,3 */
2301+
cmd.tlbi.tg = (tg - 10) / 2;
2302+
2303+
/* Determine what level the granule is at */
2304+
cmd.tlbi.ttl = 4 - ((ilog2(granule) - 3) / (tg - 3));
2305+
2306+
num_pages = size >> tg;
2307+
}
2308+
22742309
while (iova < end) {
2310+
if (smmu->features & ARM_SMMU_FEAT_RANGE_INV) {
2311+
/*
2312+
* On each iteration of the loop, the range is 5 bits
2313+
* worth of the aligned size remaining.
2314+
* The range in pages is:
2315+
*
2316+
* range = (num_pages & (0x1f << __ffs(num_pages)))
2317+
*/
2318+
unsigned long scale, num;
2319+
2320+
/* Determine the power of 2 multiple number of pages */
2321+
scale = __ffs(num_pages);
2322+
cmd.tlbi.scale = scale;
2323+
2324+
/* Determine how many chunks of 2^scale size we have */
2325+
num = (num_pages >> scale) & CMDQ_TLBI_RANGE_NUM_MAX;
2326+
cmd.tlbi.num = num - 1;
2327+
2328+
/* range is num * 2^scale * pgsize */
2329+
inv_range = num << (scale + tg);
2330+
2331+
/* Clear out the lower order bits for the next iteration */
2332+
num_pages -= num << scale;
2333+
}
2334+
22752335
cmd.tlbi.addr = iova;
22762336
arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
2277-
iova += granule;
2337+
iova += inv_range;
22782338
}
22792339
arm_smmu_cmdq_batch_submit(smmu, &cmds);
22802340

@@ -3783,6 +3843,11 @@ static int arm_smmu_device_hw_probe(struct arm_smmu_device *smmu)
37833843
if (smmu->sid_bits <= STRTAB_SPLIT)
37843844
smmu->features &= ~ARM_SMMU_FEAT_2_LVL_STRTAB;
37853845

3846+
/* IDR3 */
3847+
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR3);
3848+
if (FIELD_GET(IDR3_RIL, reg))
3849+
smmu->features |= ARM_SMMU_FEAT_RANGE_INV;
3850+
37863851
/* IDR5 */
37873852
reg = readl_relaxed(smmu->base + ARM_SMMU_IDR5);
37883853

0 commit comments

Comments
 (0)