@@ -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 );
21292112out_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
23942385static 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
0 commit comments