Skip to content

Commit e9d1e4f

Browse files
jgunthorpewilldeacon
authored andcommitted
iommu/arm-smmu-v3: Move the CD generation for S1 domains into a function
Introduce arm_smmu_make_s1_cd() to build the CD from the paging S1 domain, and reorganize all the places programming S1 domain CD table entries to call it. Split arm_smmu_update_s1_domain_cd_entry() from arm_smmu_update_ctx_desc_devices() so that the S1 path has its own call chain separate from the unrelated SVA path. arm_smmu_update_s1_domain_cd_entry() only works on S1 domains attached to RIDs and refreshes all their CDs. Remove case (3) from arm_smmu_write_ctx_desc() as it is now handled by directly calling arm_smmu_write_cd_entry(). Remove the forced clear of the CD during S1 domain attach, arm_smmu_write_cd_entry() will do this automatically if necessary. Tested-by: Nicolin Chen <[email protected]> Tested-by: Shameer Kolothum <[email protected]> Reviewed-by: Michael Shavit <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Reviewed-by: Mostafa Saleh <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] [will: Drop unused arm_smmu_clean_cd_entry() function] Signed-off-by: Will Deacon <[email protected]>
1 parent 78a5fbe commit e9d1e4f

File tree

3 files changed

+76
-29
lines changed

3 files changed

+76
-29
lines changed

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3-sva.c

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,29 @@ static void arm_smmu_update_ctx_desc_devices(struct arm_smmu_domain *smmu_domain
5353
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
5454
}
5555

56+
static void
57+
arm_smmu_update_s1_domain_cd_entry(struct arm_smmu_domain *smmu_domain)
58+
{
59+
struct arm_smmu_master *master;
60+
struct arm_smmu_cd target_cd;
61+
unsigned long flags;
62+
63+
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
64+
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
65+
struct arm_smmu_cd *cdptr;
66+
67+
/* S1 domains only support RID attachment right now */
68+
cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
69+
if (WARN_ON(!cdptr))
70+
continue;
71+
72+
arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
73+
arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
74+
&target_cd);
75+
}
76+
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
77+
}
78+
5679
/*
5780
* Check if the CPU ASID is available on the SMMU side. If a private context
5881
* descriptor is using it, try to replace it.
@@ -96,7 +119,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid)
96119
* be some overlap between use of both ASIDs, until we invalidate the
97120
* TLB.
98121
*/
99-
arm_smmu_update_ctx_desc_devices(smmu_domain, IOMMU_NO_PASID, cd);
122+
arm_smmu_update_s1_domain_cd_entry(smmu_domain);
100123

101124
/* Invalidate TLB entries previously associated with that context */
102125
arm_smmu_tlb_inv_asid(smmu, asid);

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.c

Lines changed: 43 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1203,8 +1203,8 @@ static void arm_smmu_write_cd_l1_desc(__le64 *dst,
12031203
WRITE_ONCE(*dst, cpu_to_le64(val));
12041204
}
12051205

1206-
static struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
1207-
u32 ssid)
1206+
struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
1207+
u32 ssid)
12081208
{
12091209
__le64 *l1ptr;
12101210
unsigned int idx;
@@ -1269,9 +1269,9 @@ static const struct arm_smmu_entry_writer_ops arm_smmu_cd_writer_ops = {
12691269
.get_used = arm_smmu_get_cd_used,
12701270
};
12711271

1272-
static void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
1273-
struct arm_smmu_cd *cdptr,
1274-
const struct arm_smmu_cd *target)
1272+
void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
1273+
struct arm_smmu_cd *cdptr,
1274+
const struct arm_smmu_cd *target)
12751275
{
12761276
struct arm_smmu_cd_writer cd_writer = {
12771277
.writer = {
@@ -1284,6 +1284,32 @@ static void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
12841284
arm_smmu_write_entry(&cd_writer.writer, cdptr->data, target->data);
12851285
}
12861286

1287+
void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
1288+
struct arm_smmu_master *master,
1289+
struct arm_smmu_domain *smmu_domain)
1290+
{
1291+
struct arm_smmu_ctx_desc *cd = &smmu_domain->cd;
1292+
1293+
memset(target, 0, sizeof(*target));
1294+
1295+
target->data[0] = cpu_to_le64(
1296+
cd->tcr |
1297+
#ifdef __BIG_ENDIAN
1298+
CTXDESC_CD_0_ENDI |
1299+
#endif
1300+
CTXDESC_CD_0_V |
1301+
CTXDESC_CD_0_AA64 |
1302+
(master->stall_enabled ? CTXDESC_CD_0_S : 0) |
1303+
CTXDESC_CD_0_R |
1304+
CTXDESC_CD_0_A |
1305+
CTXDESC_CD_0_ASET |
1306+
FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid)
1307+
);
1308+
1309+
target->data[1] = cpu_to_le64(cd->ttbr & CTXDESC_CD_1_TTB0_MASK);
1310+
target->data[3] = cpu_to_le64(cd->mair);
1311+
}
1312+
12871313
int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
12881314
struct arm_smmu_ctx_desc *cd)
12891315
{
@@ -1292,14 +1318,11 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
12921318
*
12931319
* (1) Install primary CD, for normal DMA traffic (SSID = IOMMU_NO_PASID = 0).
12941320
* (2) Install a secondary CD, for SID+SSID traffic.
1295-
* (3) Update ASID of a CD. Atomically write the first 64 bits of the
1296-
* CD, then invalidate the old entry and mappings.
12971321
* (4) Quiesce the context without clearing the valid bit. Disable
12981322
* translation, and ignore any translation fault.
12991323
* (5) Remove a secondary CD.
13001324
*/
13011325
u64 val;
1302-
bool cd_live;
13031326
struct arm_smmu_cd target;
13041327
struct arm_smmu_cd *cdptr = &target;
13051328
struct arm_smmu_cd *cd_table_entry;
@@ -1315,7 +1338,6 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
13151338

13161339
target = *cd_table_entry;
13171340
val = le64_to_cpu(cdptr->data[0]);
1318-
cd_live = !!(val & CTXDESC_CD_0_V);
13191341

13201342
if (!cd) { /* (5) */
13211343
memset(cdptr, 0, sizeof(*cdptr));
@@ -1328,13 +1350,6 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
13281350
val &= ~(CTXDESC_CD_0_S | CTXDESC_CD_0_R);
13291351
val |= CTXDESC_CD_0_TCR_EPD0;
13301352
cdptr->data[1] &= ~cpu_to_le64(CTXDESC_CD_1_TTB0_MASK);
1331-
} else if (cd_live) { /* (3) */
1332-
val &= ~CTXDESC_CD_0_ASID;
1333-
val |= FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid);
1334-
/*
1335-
* Until CD+TLB invalidation, both ASIDs may be used for tagging
1336-
* this substream's traffic
1337-
*/
13381353
} else { /* (1) and (2) */
13391354
cdptr->data[1] = cpu_to_le64(cd->ttbr & CTXDESC_CD_1_TTB0_MASK);
13401355
cdptr->data[2] = 0;
@@ -2633,29 +2648,29 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
26332648
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
26342649

26352650
switch (smmu_domain->stage) {
2636-
case ARM_SMMU_DOMAIN_S1:
2651+
case ARM_SMMU_DOMAIN_S1: {
2652+
struct arm_smmu_cd target_cd;
2653+
struct arm_smmu_cd *cdptr;
2654+
26372655
if (!master->cd_table.cdtab) {
26382656
ret = arm_smmu_alloc_cd_tables(master);
26392657
if (ret)
26402658
goto out_list_del;
2641-
} else {
2642-
/*
2643-
* arm_smmu_write_ctx_desc() relies on the entry being
2644-
* invalid to work, clear any existing entry.
2645-
*/
2646-
ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID,
2647-
NULL);
2648-
if (ret)
2649-
goto out_list_del;
26502659
}
26512660

2652-
ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, &smmu_domain->cd);
2653-
if (ret)
2661+
cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
2662+
if (!cdptr) {
2663+
ret = -ENOMEM;
26542664
goto out_list_del;
2665+
}
26552666

2667+
arm_smmu_make_s1_cd(&target_cd, master, smmu_domain);
2668+
arm_smmu_write_cd_entry(master, IOMMU_NO_PASID, cdptr,
2669+
&target_cd);
26562670
arm_smmu_make_cdtable_ste(&target, master);
26572671
arm_smmu_install_ste_for_dev(master, &target);
26582672
break;
2673+
}
26592674
case ARM_SMMU_DOMAIN_S2:
26602675
arm_smmu_make_s2_domain_ste(&target, master, smmu_domain);
26612676
arm_smmu_install_ste_for_dev(master, &target);

drivers/iommu/arm/arm-smmu-v3/arm-smmu-v3.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -751,6 +751,15 @@ extern struct xarray arm_smmu_asid_xa;
751751
extern struct mutex arm_smmu_asid_lock;
752752
extern struct arm_smmu_ctx_desc quiet_cd;
753753

754+
struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
755+
u32 ssid);
756+
void arm_smmu_make_s1_cd(struct arm_smmu_cd *target,
757+
struct arm_smmu_master *master,
758+
struct arm_smmu_domain *smmu_domain);
759+
void arm_smmu_write_cd_entry(struct arm_smmu_master *master, int ssid,
760+
struct arm_smmu_cd *cdptr,
761+
const struct arm_smmu_cd *target);
762+
754763
int arm_smmu_write_ctx_desc(struct arm_smmu_master *smmu_master, int ssid,
755764
struct arm_smmu_ctx_desc *cd);
756765
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);

0 commit comments

Comments
 (0)