Skip to content

Commit 10e4968

Browse files
shavitmichaelwilldeacon
authored andcommitted
iommu/arm-smmu-v3: Move CD table to arm_smmu_master
With this change, each master will now own its own CD table instead of sharing one with other masters attached to the same domain. Attaching a stage 1 domain installs CD entries into the master's CD table. SVA writes its CD entries into each master's CD table if the domain is shared across masters. Also add the device to the devices list before writing the CD to the table so that SVA will know that the CD needs to be re-written to this device's CD table as well if it decides to update the CD's ASID concurrently with this function. Tested-by: Nicolin Chen <nicolinc@nvidia.com> Reviewed-by: Jason Gunthorpe <jgg@nvidia.com> Signed-off-by: Michael Shavit <mshavit@google.com> Link: https://lore.kernel.org/r/20230915211705.v8.6.Ice063dcf87d1b777a72e008d9e3406d2bcf6d876@changeid Signed-off-by: Will Deacon <will@kernel.org>
1 parent 2450314 commit 10e4968

File tree

2 files changed

+58
-49
lines changed

2 files changed

+58
-49
lines changed

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

Lines changed: 55 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,7 +1025,7 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid)
10251025
unsigned int idx;
10261026
struct arm_smmu_l1_ctx_desc *l1_desc;
10271027
struct arm_smmu_device *smmu = master->smmu;
1028-
struct arm_smmu_ctx_desc_cfg *cdcfg = &master->domain->cd_table;
1028+
struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table;
10291029

10301030
if (cdcfg->s1fmt == STRTAB_STE_0_S1FMT_LINEAR)
10311031
return cdcfg->cdtab + ssid * CTXDESC_CD_DWORDS;
@@ -1062,7 +1062,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
10621062
u64 val;
10631063
bool cd_live;
10641064
__le64 *cdptr;
1065-
struct arm_smmu_ctx_desc_cfg *cd_table = &master->domain->cd_table;
1065+
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
10661066

10671067
if (WARN_ON(ssid >= (1 << cd_table->s1cdmax)))
10681068
return -E2BIG;
@@ -1125,14 +1125,13 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
11251125
return 0;
11261126
}
11271127

1128-
static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
1129-
struct arm_smmu_master *master)
1128+
static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master)
11301129
{
11311130
int ret;
11321131
size_t l1size;
11331132
size_t max_contexts;
11341133
struct arm_smmu_device *smmu = master->smmu;
1135-
struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table;
1134+
struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table;
11361135

11371136
cdcfg->stall_enabled = master->stall_enabled;
11381137
cdcfg->s1cdmax = master->ssid_bits;
@@ -1176,12 +1175,12 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
11761175
return ret;
11771176
}
11781177

1179-
static void arm_smmu_free_cd_tables(struct arm_smmu_domain *smmu_domain)
1178+
static void arm_smmu_free_cd_tables(struct arm_smmu_master *master)
11801179
{
11811180
int i;
11821181
size_t size, l1size;
1183-
struct arm_smmu_device *smmu = smmu_domain->smmu;
1184-
struct arm_smmu_ctx_desc_cfg *cdcfg = &smmu_domain->cd_table;
1182+
struct arm_smmu_device *smmu = master->smmu;
1183+
struct arm_smmu_ctx_desc_cfg *cdcfg = &master->cd_table;
11851184

11861185
if (cdcfg->l1_desc) {
11871186
size = CTXDESC_L2_ENTRIES * (CTXDESC_CD_DWORDS << 3);
@@ -1289,7 +1288,7 @@ static void arm_smmu_write_strtab_ent(struct arm_smmu_master *master, u32 sid,
12891288
if (smmu_domain) {
12901289
switch (smmu_domain->stage) {
12911290
case ARM_SMMU_DOMAIN_S1:
1292-
cd_table = &smmu_domain->cd_table;
1291+
cd_table = &master->cd_table;
12931292
break;
12941293
case ARM_SMMU_DOMAIN_S2:
12951294
case ARM_SMMU_DOMAIN_NESTED:
@@ -2062,14 +2061,10 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
20622061

20632062
free_io_pgtable_ops(smmu_domain->pgtbl_ops);
20642063

2065-
/* Free the CD and ASID, if we allocated them */
2064+
/* Free the ASID or VMID */
20662065
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
2067-
struct arm_smmu_ctx_desc_cfg *cd_table = &smmu_domain->cd_table;
2068-
20692066
/* Prevent SVA from touching the CD while we're freeing it */
20702067
mutex_lock(&arm_smmu_asid_lock);
2071-
if (cd_table->cdtab)
2072-
arm_smmu_free_cd_tables(smmu_domain);
20732068
arm_smmu_free_asid(&smmu_domain->cd);
20742069
mutex_unlock(&arm_smmu_asid_lock);
20752070
} else {
@@ -2100,10 +2095,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
21002095
if (ret)
21012096
goto out_unlock;
21022097

2103-
ret = arm_smmu_alloc_cd_tables(smmu_domain, master);
2104-
if (ret)
2105-
goto out_free_asid;
2106-
21072098
cd->asid = (u16)asid;
21082099
cd->ttbr = pgtbl_cfg->arm_lpae_s1_cfg.ttbr;
21092100
cd->tcr = FIELD_PREP(CTXDESC_CD_0_TCR_T0SZ, tcr->tsz) |
@@ -2115,17 +2106,9 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
21152106
CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64;
21162107
cd->mair = pgtbl_cfg->arm_lpae_s1_cfg.mair;
21172108

2118-
ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, cd);
2119-
if (ret)
2120-
goto out_free_cd_tables;
2121-
21222109
mutex_unlock(&arm_smmu_asid_lock);
21232110
return 0;
21242111

2125-
out_free_cd_tables:
2126-
arm_smmu_free_cd_tables(smmu_domain);
2127-
out_free_asid:
2128-
arm_smmu_free_asid(cd);
21292112
out_unlock:
21302113
mutex_unlock(&arm_smmu_asid_lock);
21312114
return ret;
@@ -2389,6 +2372,14 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
23892372
master->domain = NULL;
23902373
master->ats_enabled = false;
23912374
arm_smmu_install_ste_for_dev(master);
2375+
/*
2376+
* Clearing the CD entry isn't strictly required to detach the domain
2377+
* since the table is uninstalled anyway, but it helps avoid confusion
2378+
* in the call to arm_smmu_write_ctx_desc on the next attach (which
2379+
* expects the entry to be empty).
2380+
*/
2381+
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 && master->cd_table.cdtab)
2382+
arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, NULL);
23922383
}
23932384

23942385
static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
@@ -2423,23 +2414,14 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
24232414
if (!smmu_domain->smmu) {
24242415
smmu_domain->smmu = smmu;
24252416
ret = arm_smmu_domain_finalise(domain, master);
2426-
if (ret) {
2417+
if (ret)
24272418
smmu_domain->smmu = NULL;
2428-
goto out_unlock;
2429-
}
2430-
} else if (smmu_domain->smmu != smmu) {
2431-
ret = -EINVAL;
2432-
goto out_unlock;
2433-
} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 &&
2434-
master->ssid_bits != smmu_domain->cd_table.s1cdmax) {
2419+
} else if (smmu_domain->smmu != smmu)
24352420
ret = -EINVAL;
2436-
goto out_unlock;
2437-
} else if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1 &&
2438-
smmu_domain->cd_table.stall_enabled !=
2439-
master->stall_enabled) {
2440-
ret = -EINVAL;
2441-
goto out_unlock;
2442-
}
2421+
2422+
mutex_unlock(&smmu_domain->init_mutex);
2423+
if (ret)
2424+
return ret;
24432425

24442426
master->domain = smmu_domain;
24452427

@@ -2453,16 +2435,42 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
24532435
if (smmu_domain->stage != ARM_SMMU_DOMAIN_BYPASS)
24542436
master->ats_enabled = arm_smmu_ats_supported(master);
24552437

2456-
arm_smmu_install_ste_for_dev(master);
2457-
24582438
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
24592439
list_add(&master->domain_head, &smmu_domain->devices);
24602440
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
24612441

2442+
if (smmu_domain->stage == ARM_SMMU_DOMAIN_S1) {
2443+
if (!master->cd_table.cdtab) {
2444+
ret = arm_smmu_alloc_cd_tables(master);
2445+
if (ret) {
2446+
master->domain = NULL;
2447+
goto out_list_del;
2448+
}
2449+
}
2450+
2451+
/*
2452+
* Prevent SVA from concurrently modifying the CD or writing to
2453+
* the CD entry
2454+
*/
2455+
mutex_lock(&arm_smmu_asid_lock);
2456+
ret = arm_smmu_write_ctx_desc(master, IOMMU_NO_PASID, &smmu_domain->cd);
2457+
mutex_unlock(&arm_smmu_asid_lock);
2458+
if (ret) {
2459+
master->domain = NULL;
2460+
goto out_list_del;
2461+
}
2462+
}
2463+
2464+
arm_smmu_install_ste_for_dev(master);
2465+
24622466
arm_smmu_enable_ats(master);
2467+
return 0;
2468+
2469+
out_list_del:
2470+
spin_lock_irqsave(&smmu_domain->devices_lock, flags);
2471+
list_del(&master->domain_head);
2472+
spin_unlock_irqrestore(&smmu_domain->devices_lock, flags);
24632473

2464-
out_unlock:
2465-
mutex_unlock(&smmu_domain->init_mutex);
24662474
return ret;
24672475
}
24682476

@@ -2707,6 +2715,8 @@ static void arm_smmu_release_device(struct device *dev)
27072715
arm_smmu_detach_dev(master);
27082716
arm_smmu_disable_pasid(master);
27092717
arm_smmu_remove_master(master);
2718+
if (master->cd_table.cdtab)
2719+
arm_smmu_free_cd_tables(master);
27102720
kfree(master);
27112721
}
27122722

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -695,6 +695,8 @@ struct arm_smmu_master {
695695
struct arm_smmu_domain *domain;
696696
struct list_head domain_head;
697697
struct arm_smmu_stream *streams;
698+
/* Locked by the iommu core using the group mutex */
699+
struct arm_smmu_ctx_desc_cfg cd_table;
698700
unsigned int num_streams;
699701
bool ats_enabled;
700702
bool stall_enabled;
@@ -721,11 +723,8 @@ struct arm_smmu_domain {
721723

722724
enum arm_smmu_domain_stage stage;
723725
union {
724-
struct {
725726
struct arm_smmu_ctx_desc cd;
726-
struct arm_smmu_ctx_desc_cfg cd_table;
727-
};
728-
struct arm_smmu_s2_cfg s2_cfg;
727+
struct arm_smmu_s2_cfg s2_cfg;
729728
};
730729

731730
struct iommu_domain domain;

0 commit comments

Comments
 (0)