@@ -1025,7 +1025,7 @@ static __le64 *arm_smmu_get_cd_ptr(struct arm_smmu_master *master, u32 ssid)
1025
1025
unsigned int idx ;
1026
1026
struct arm_smmu_l1_ctx_desc * l1_desc ;
1027
1027
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 ;
1029
1029
1030
1030
if (cdcfg -> s1fmt == STRTAB_STE_0_S1FMT_LINEAR )
1031
1031
return cdcfg -> cdtab + ssid * CTXDESC_CD_DWORDS ;
@@ -1062,7 +1062,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
1062
1062
u64 val ;
1063
1063
bool cd_live ;
1064
1064
__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 ;
1066
1066
1067
1067
if (WARN_ON (ssid >= (1 << cd_table -> s1cdmax )))
1068
1068
return - E2BIG ;
@@ -1125,14 +1125,13 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
1125
1125
return 0 ;
1126
1126
}
1127
1127
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 )
1130
1129
{
1131
1130
int ret ;
1132
1131
size_t l1size ;
1133
1132
size_t max_contexts ;
1134
1133
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 ;
1136
1135
1137
1136
cdcfg -> stall_enabled = master -> stall_enabled ;
1138
1137
cdcfg -> s1cdmax = master -> ssid_bits ;
@@ -1176,12 +1175,12 @@ static int arm_smmu_alloc_cd_tables(struct arm_smmu_domain *smmu_domain,
1176
1175
return ret ;
1177
1176
}
1178
1177
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 )
1180
1179
{
1181
1180
int i ;
1182
1181
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 ;
1185
1184
1186
1185
if (cdcfg -> l1_desc ) {
1187
1186
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,
1289
1288
if (smmu_domain ) {
1290
1289
switch (smmu_domain -> stage ) {
1291
1290
case ARM_SMMU_DOMAIN_S1 :
1292
- cd_table = & smmu_domain -> cd_table ;
1291
+ cd_table = & master -> cd_table ;
1293
1292
break ;
1294
1293
case ARM_SMMU_DOMAIN_S2 :
1295
1294
case ARM_SMMU_DOMAIN_NESTED :
@@ -2062,14 +2061,10 @@ static void arm_smmu_domain_free(struct iommu_domain *domain)
2062
2061
2063
2062
free_io_pgtable_ops (smmu_domain -> pgtbl_ops );
2064
2063
2065
- /* Free the CD and ASID, if we allocated them */
2064
+ /* Free the ASID or VMID */
2066
2065
if (smmu_domain -> stage == ARM_SMMU_DOMAIN_S1 ) {
2067
- struct arm_smmu_ctx_desc_cfg * cd_table = & smmu_domain -> cd_table ;
2068
-
2069
2066
/* Prevent SVA from touching the CD while we're freeing it */
2070
2067
mutex_lock (& arm_smmu_asid_lock );
2071
- if (cd_table -> cdtab )
2072
- arm_smmu_free_cd_tables (smmu_domain );
2073
2068
arm_smmu_free_asid (& smmu_domain -> cd );
2074
2069
mutex_unlock (& arm_smmu_asid_lock );
2075
2070
} else {
@@ -2100,10 +2095,6 @@ static int arm_smmu_domain_finalise_s1(struct arm_smmu_domain *smmu_domain,
2100
2095
if (ret )
2101
2096
goto out_unlock ;
2102
2097
2103
- ret = arm_smmu_alloc_cd_tables (smmu_domain , master );
2104
- if (ret )
2105
- goto out_free_asid ;
2106
-
2107
2098
cd -> asid = (u16 )asid ;
2108
2099
cd -> ttbr = pgtbl_cfg -> arm_lpae_s1_cfg .ttbr ;
2109
2100
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,
2115
2106
CTXDESC_CD_0_TCR_EPD1 | CTXDESC_CD_0_AA64 ;
2116
2107
cd -> mair = pgtbl_cfg -> arm_lpae_s1_cfg .mair ;
2117
2108
2118
- ret = arm_smmu_write_ctx_desc (master , IOMMU_NO_PASID , cd );
2119
- if (ret )
2120
- goto out_free_cd_tables ;
2121
-
2122
2109
mutex_unlock (& arm_smmu_asid_lock );
2123
2110
return 0 ;
2124
2111
2125
- out_free_cd_tables :
2126
- arm_smmu_free_cd_tables (smmu_domain );
2127
- out_free_asid :
2128
- arm_smmu_free_asid (cd );
2129
2112
out_unlock :
2130
2113
mutex_unlock (& arm_smmu_asid_lock );
2131
2114
return ret ;
@@ -2389,6 +2372,14 @@ static void arm_smmu_detach_dev(struct arm_smmu_master *master)
2389
2372
master -> domain = NULL ;
2390
2373
master -> ats_enabled = false;
2391
2374
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 );
2392
2383
}
2393
2384
2394
2385
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)
2423
2414
if (!smmu_domain -> smmu ) {
2424
2415
smmu_domain -> smmu = smmu ;
2425
2416
ret = arm_smmu_domain_finalise (domain , master );
2426
- if (ret ) {
2417
+ if (ret )
2427
2418
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 )
2435
2420
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 ;
2443
2425
2444
2426
master -> domain = smmu_domain ;
2445
2427
@@ -2453,16 +2435,42 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
2453
2435
if (smmu_domain -> stage != ARM_SMMU_DOMAIN_BYPASS )
2454
2436
master -> ats_enabled = arm_smmu_ats_supported (master );
2455
2437
2456
- arm_smmu_install_ste_for_dev (master );
2457
-
2458
2438
spin_lock_irqsave (& smmu_domain -> devices_lock , flags );
2459
2439
list_add (& master -> domain_head , & smmu_domain -> devices );
2460
2440
spin_unlock_irqrestore (& smmu_domain -> devices_lock , flags );
2461
2441
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
+
2462
2466
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 );
2463
2473
2464
- out_unlock :
2465
- mutex_unlock (& smmu_domain -> init_mutex );
2466
2474
return ret ;
2467
2475
}
2468
2476
@@ -2707,6 +2715,8 @@ static void arm_smmu_release_device(struct device *dev)
2707
2715
arm_smmu_detach_dev (master );
2708
2716
arm_smmu_disable_pasid (master );
2709
2717
arm_smmu_remove_master (master );
2718
+ if (master -> cd_table .cdtab )
2719
+ arm_smmu_free_cd_tables (master );
2710
2720
kfree (master );
2711
2721
}
2712
2722
0 commit comments