Skip to content

Commit 2450314

Browse files
shavitmichaelwilldeacon
authored andcommitted
iommu/arm-smmu-v3: Refactor write_ctx_desc
Update arm_smmu_write_ctx_desc and downstream functions to operate on a master instead of an smmu domain. We expect arm_smmu_write_ctx_desc() to only be called to write a CD entry into a CD table owned by the master. Under the hood, arm_smmu_write_ctx_desc still fetches the CD table from the domain that is attached to the master, but a subsequent commit will move that table's ownership to the master. Note that this change isn't a nop refactor since SVA will call arm_smmu_write_ctx_desc in a loop for every master the domain is attached to despite the fact that they all share the same CD table. This loop may look weird but becomes necessary when the CD table becomes per-master in a subsequent commit. Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Reviewed-by: Nicolin Chen <nicolinc@nvidia.com> Signed-off-by: Michael Shavit <mshavit@google.com> Tested-by: Nicolin Chen <nicolinc@nvidia.com> Link: https://lore.kernel.org/r/20230915211705.v8.5.I219054a6cf538df5bb22f4ada2d9933155d6058c@changeid Signed-off-by: Will Deacon <will@kernel.org>
1 parent 1228cc5 commit 2450314

File tree

3 files changed

+54
-35
lines changed

3 files changed

+54
-35
lines changed

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,25 @@ struct arm_smmu_bond {
3737

3838
static DEFINE_MUTEX(sva_lock);
3939

40+
/*
41+
* Write the CD to the CD tables for all masters that this domain is attached
42+
* to. Note that this is only used to update existing CD entries in the target
43+
* CD table, for which it's assumed that arm_smmu_write_ctx_desc can't fail.
44+
*/
45+
static void arm_smmu_update_ctx_desc_devices(struct arm_smmu_domain *smmu_domain,
46+
int ssid,
47+
struct arm_smmu_ctx_desc *cd)
48+
{
49+
struct arm_smmu_master *master;
50+
unsigned long flags;
51+
52+
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
53+
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
54+
arm_smmu_write_ctx_desc(master, ssid, cd);
55+
}
56+
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
57+
}
58+
4059
/*
4160
* Check if the CPU ASID is available on the SMMU side. If a private context
4261
* descriptor is using it, try to replace it.
@@ -80,7 +99,7 @@ arm_smmu_share_asid(struct mm_struct *mm, u16 asid)
8099
* be some overlap between use of both ASIDs, until we invalidate the
81100
* TLB.
82101
*/
83-
arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd);
102+
arm_smmu_update_ctx_desc_devices(smmu_domain, IOMMU_NO_PASID, cd);
84103

85104
/* Invalidate TLB entries previously associated with that context */
86105
arm_smmu_tlb_inv_asid(smmu, asid);
@@ -247,7 +266,7 @@ static void arm_smmu_mm_release(struct mmu_notifier *mn, struct mm_struct *mm)
247266
* DMA may still be running. Keep the cd valid to avoid C_BAD_CD events,
248267
* but disable translation.
249268
*/
250-
arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, &quiet_cd);
269+
arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, &quiet_cd);
251270

252271
arm_smmu_tlb_inv_asid(smmu_domain->smmu, smmu_mn->cd->asid);
253272
arm_smmu_atc_inv_domain(smmu_domain, mm->pasid, 0, 0);
@@ -273,8 +292,10 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
273292
struct mm_struct *mm)
274293
{
275294
int ret;
295+
unsigned long flags;
276296
struct arm_smmu_ctx_desc *cd;
277297
struct arm_smmu_mmu_notifier *smmu_mn;
298+
struct arm_smmu_master *master;
278299

279300
list_for_each_entry(smmu_mn, &smmu_domain->mmu_notifiers, list) {
280301
if (smmu_mn->mn.mm == mm) {
@@ -304,7 +325,16 @@ arm_smmu_mmu_notifier_get(struct arm_smmu_domain *smmu_domain,
304325
goto err_free_cd;
305326
}
306327

307-
ret = arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, cd);
328+
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
329+
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
330+
ret = arm_smmu_write_ctx_desc(master, mm->pasid, cd);
331+
if (ret) {
332+
list_for_each_entry_from_reverse(master, &smmu_domain->devices, domain_head)
333+
arm_smmu_write_ctx_desc(master, mm->pasid, NULL);
334+
break;
335+
}
336+
}
337+
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
308338
if (ret)
309339
goto err_put_notifier;
310340

@@ -329,7 +359,8 @@ static void arm_smmu_mmu_notifier_put(struct arm_smmu_mmu_notifier *smmu_mn)
329359
return;
330360

331361
list_del(&smmu_mn->list);
332-
arm_smmu_write_ctx_desc(smmu_domain, mm->pasid, NULL);
362+
363+
arm_smmu_update_ctx_desc_devices(smmu_domain, mm->pasid, NULL);
333364

334365
/*
335366
* If we went through clear(), we've already invalidated, and no

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

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -971,14 +971,12 @@ void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid)
971971
arm_smmu_cmdq_issue_cmd_with_sync(smmu, &cmd);
972972
}
973973

974-
static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
974+
static void arm_smmu_sync_cd(struct arm_smmu_master *master,
975975
int ssid, bool leaf)
976976
{
977977
size_t i;
978-
unsigned long flags;
979-
struct arm_smmu_master *master;
980978
struct arm_smmu_cmdq_batch cmds;
981-
struct arm_smmu_device *smmu = smmu_domain->smmu;
979+
struct arm_smmu_device *smmu = master->smmu;
982980
struct arm_smmu_cmdq_ent cmd = {
983981
.opcode = CMDQ_OP_CFGI_CD,
984982
.cfgi = {
@@ -988,15 +986,10 @@ static void arm_smmu_sync_cd(struct arm_smmu_domain *smmu_domain,
988986
};
989987

990988
cmds.num = 0;
991-
992-
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
993-
list_for_each_entry(master, &smmu_domain->devices, domain_head) {
994-
for (i = 0; i < master->num_streams; i++) {
995-
cmd.cfgi.sid = master->streams[i].id;
996-
arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
997-
}
989+
for (i = 0; i < master->num_streams; i++) {
990+
cmd.cfgi.sid = master->streams[i].id;
991+
arm_smmu_cmdq_batch_add(smmu, &cmds, &cmd);
998992
}
999-
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
1000993

1001994
arm_smmu_cmdq_batch_submit(smmu, &cmds);
1002995
}
@@ -1026,14 +1019,13 @@ static void arm_smmu_write_cd_l1_desc(__le64 *dst,
10261019
WRITE_ONCE(*dst, cpu_to_le64(val));
10271020
}
10281021

1029-
static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain,
1030-
u32 ssid)
1022+
static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid)
10311023
{
10321024
__le64 *l1ptr;
10331025
unsigned int idx;
10341026
struct arm_smmu_l1_ctx_desc *l1_desc;
1035-
struct arm_smmu_device *smmu = smmu_domain->smmu;
1036-
struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table;
1027+
struct arm_smmu_device *smmu = master->smmu;
1028+
struct arm_smmu_ctx_desc_cfg *cdcfg = &master->domain->cd_table;
10371029

10381030
if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR)
10391031
return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS;
@@ -1047,13 +1039,13 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_domain *smmu_domain,
10471039
l1ptr = cdcfg->cdtab + idx * CTXDESC_L1_DESC_DWORDS;
10481040
arm_smmu_write_cd_l1_desc(l1ptr, l1_desc);
10491041
/* An invalid L1CD can be cached */
1050-
arm_smmu_sync_cd(smmu_domain, ssid, false);
1042+
arm_smmu_sync_cd(master, ssid, false);
10511043
}
10521044
idx = ssid & (CTXDESC_L2_ENTRIES - 1);
10531045
return l1_desc->l2ptr + idx * CTXDESC_CD_DWORDS;
10541046
}
10551047

1056-
int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
1048+
int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
10571049
struct arm_smmu_ctx_desc *cd)
10581050
{
10591051
/*
@@ -1070,11 +1062,12 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
10701062
u64 val;
10711063
bool cd_live;
10721064
__le64 *cdptr;
1065+
struct arm_smmu_ctx_desc_cfg *cd_table = &master->domain->cd_table;
10731066

1074-
if (WARN_ON(ssid >= (1 << smmu_domain->cd_table.s1cdmax)))
1067+
if (WARN_ON(ssid >= (1 << cd_table->s1cdmax)))
10751068
return -E2BIG;
10761069

1077-
cdptr = arm_smmu_get_cd_ptr(smmu_domain, ssid);
1070+
cdptr = arm_smmu_get_cd_ptr(master, ssid);
10781071
if (!cdptr)
10791072
return -ENOMEM;
10801073

@@ -1102,7 +1095,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
11021095
* order. Ensure that it observes valid values before reading
11031096
* V=1.
11041097
*/
1105-
arm_smmu_sync_cd(smmu_domain, ssid, true);
1098+
arm_smmu_sync_cd(master, ssid, true);
11061099

11071100
val = cd->tcr |
11081101
#ifdef __BIG_ENDIAN
@@ -1114,7 +1107,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
11141107
FIELD_PREP(CTXDESC_CD_0_ASID, cd->asid) |
11151108
CTXDESC_CD_0_V;
11161109

1117-
if (smmu_domain->cd_table.stall_enabled)
1110+
if (cd_table->stall_enabled)
11181111
val |= CTXDESC_CD_0_S;
11191112
}
11201113

@@ -1128,7 +1121,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
11281121
* without first making the structure invalid.
11291122
*/
11301123
WRITE_ONCE(cdptr[0], cpu_to_le64(val));
1131-
arm_smmu_sync_cd(smmu_domain, ssid, true);
1124+
arm_smmu_sync_cd(master, ssid, true);
11321125
return 0;
11331126
}
11341127

@@ -1138,7 +1131,7 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
11381131
int ret;
11391132
size_t l1size;
11401133
size_t max_contexts;
1141-
struct arm_smmu_device *smmu = smmu_domain->smmu;
1134+
struct arm_smmu_device *smmu = master->smmu;
11421135
struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table;
11431136

11441137
cdcfg->stall_enabled = master->stall_enabled;
@@ -2122,12 +2115,7 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
21222115
CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64;
21232116
cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair;
21242117

2125-
/*
2126-
* Note that this will end up calling arm_smmu_sync_cd() before
2127-
* the master has been added to the devices list for this domain.
2128-
* This isn't an issue because the STE hasn't been installed yet.
2129-
*/
2130-
ret = arm_smmu_write_ctx_desc(smmu_domain, IOMMU_NO_PASID, cd);
2118+
ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, cd);
21312119
if (ret)
21322120
goto out_free_cd_tables;
21332121

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -745,7 +745,7 @@ extern struct xarray arm_smmu_asid_xa;
745745
extern struct mutex arm_smmu_asid_lock;
746746
extern struct arm_smmu_ctx_desc quiet_cd;
747747

748-
int arm_smmu_write_ctx_desc(struct arm_smmu_domain *smmu_domain, int ssid,
748+
int arm_smmu_write_ctx_desc(struct arm_smmu_master *smmu_master, int ssid,
749749
struct arm_smmu_ctx_desc *cd);
750750
void arm_smmu_tlb_inv_asid(struct arm_smmu_device *smmu, u16 asid);
751751
void arm_smmu_tlb_inv_range_asid(unsigned long iova, size_t size, int asid,

0 commit comments

Comments
 (0)