Skip to content

Commit b2f4c0f

Browse files
jgunthorpewilldeacon
authored andcommitted
iommu/arm-smmu-v3: Make arm_smmu_alloc_cd_ptr()
Only the attach callers can perform an allocation for the CD table entry, the other callers must not do so, they do not have the correct locking and they cannot sleep. Split up the functions so this is clear. arm_smmu_get_cd_ptr() will return pointer to a CD table entry without doing any kind of allocation. arm_smmu_alloc_cd_ptr() will allocate the table and any required leaf. A following patch will add lockdep assertions to arm_smmu_alloc_cd_ptr() once the restructuring is completed and arm_smmu_alloc_cd_ptr() is never called in the wrong context. Tested-by: Nicolin Chen <[email protected]> Reviewed-by: Nicolin Chen <[email protected]> Signed-off-by: Jason Gunthorpe <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Will Deacon <[email protected]>
1 parent af8f0b8 commit b2f4c0f

File tree

2 files changed

+39
-23
lines changed

2 files changed

+39
-23
lines changed

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

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ static struct arm_smmu_option_prop arm_smmu_options[] = {
9797

9898
static int arm_smmu_domain_finalise(struct arm_smmu_domain *smmu_domain,
9999
struct arm_smmu_device *smmu);
100+
static int arm_smmu_alloc_cd_tables(struct arm_smmu_master *master);
100101

101102
static void parse_driver_options(struct arm_smmu_device *smmu)
102103
{
@@ -1206,29 +1207,51 @@ static void arm_smmu_write_cd_l1_desc(__le64 *dst,
12061207
struct arm_smmu_cd *arm_smmu_get_cd_ptr(struct arm_smmu_master *master,
12071208
u32 ssid)
12081209
{
1209-
__le64 *l1ptr;
1210-
unsigned int idx;
12111210
struct arm_smmu_l1_ctx_desc *l1_desc;
1212-
struct arm_smmu_device *smmu = master->smmu;
12131211
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
12141212

1213+
if (!cd_table->cdtab)
1214+
return NULL;
1215+
12151216
if (cd_table->s1fmt == STRTAB_STE_0_S1FMT_LINEAR)
12161217
return (struct arm_smmu_cd *)(cd_table->cdtab +
12171218
ssid * CTXDESC_CD_DWORDS);
12181219

1219-
idx = ssid >> CTXDESC_SPLIT;
1220-
l1_desc = &cd_table->l1_desc[idx];
1221-
if (!l1_desc->l2ptr) {
1222-
if (arm_smmu_alloc_cd_leaf_table(smmu, l1_desc))
1220+
l1_desc = &cd_table->l1_desc[ssid / CTXDESC_L2_ENTRIES];
1221+
if (!l1_desc->l2ptr)
1222+
return NULL;
1223+
return &l1_desc->l2ptr[ssid % CTXDESC_L2_ENTRIES];
1224+
}
1225+
1226+
static struct arm_smmu_cd *arm_smmu_alloc_cd_ptr(struct arm_smmu_master *master,
1227+
u32 ssid)
1228+
{
1229+
struct arm_smmu_ctx_desc_cfg *cd_table = &master->cd_table;
1230+
struct arm_smmu_device *smmu = master->smmu;
1231+
1232+
if (!cd_table->cdtab) {
1233+
if (arm_smmu_alloc_cd_tables(master))
12231234
return NULL;
1235+
}
1236+
1237+
if (cd_table->s1fmt == STRTAB_STE_0_S1FMT_64K_L2) {
1238+
unsigned int idx = ssid / CTXDESC_L2_ENTRIES;
1239+
struct arm_smmu_l1_ctx_desc *l1_desc;
1240+
1241+
l1_desc = &cd_table->l1_desc[idx];
1242+
if (!l1_desc->l2ptr) {
1243+
__le64 *l1ptr;
12241244

1225-
l1ptr = cd_table->cdtab + idx * CTXDESC_L1_DESC_DWORDS;
1226-
arm_smmu_write_cd_l1_desc(l1ptr, l1_desc);
1227-
/* An invalid L1CD can be cached */
1228-
arm_smmu_sync_cd(master, ssid, false);
1245+
if (arm_smmu_alloc_cd_leaf_table(smmu, l1_desc))
1246+
return NULL;
1247+
1248+
l1ptr = cd_table->cdtab + idx * CTXDESC_L1_DESC_DWORDS;
1249+
arm_smmu_write_cd_l1_desc(l1ptr, l1_desc);
1250+
/* An invalid L1CD can be cached */
1251+
arm_smmu_sync_cd(master, ssid, false);
1252+
}
12291253
}
1230-
idx = ssid & (CTXDESC_L2_ENTRIES - 1);
1231-
return &l1_desc->l2ptr[idx];
1254+
return arm_smmu_get_cd_ptr(master, ssid);
12321255
}
12331256

12341257
struct arm_smmu_cd_writer {
@@ -1344,7 +1367,7 @@ int arm_smmu_write_ctx_desc(struct arm_smmu_master *master, int ssid,
13441367
if (WARN_ON(ssid >= (1 << cd_table->s1cdmax)))
13451368
return -E2BIG;
13461369

1347-
cd_table_entry = arm_smmu_get_cd_ptr(master, ssid);
1370+
cd_table_entry = arm_smmu_alloc_cd_ptr(master, ssid);
13481371
if (!cd_table_entry)
13491372
return -ENOMEM;
13501373

@@ -2661,13 +2684,7 @@ static int arm_smmu_attach_dev(struct iommu_domain *domain, struct device *dev)
26612684
struct arm_smmu_cd target_cd;
26622685
struct arm_smmu_cd *cdptr;
26632686

2664-
if (!master->cd_table.cdtab) {
2665-
ret = arm_smmu_alloc_cd_tables(master);
2666-
if (ret)
2667-
goto out_list_del;
2668-
}
2669-
2670-
cdptr = arm_smmu_get_cd_ptr(master, IOMMU_NO_PASID);
2687+
cdptr = arm_smmu_alloc_cd_ptr(master, IOMMU_NO_PASID);
26712688
if (!cdptr) {
26722689
ret = -ENOMEM;
26732690
goto out_list_del;

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,8 +275,7 @@ struct arm_smmu_ste {
275275
* 2lvl: at most 1024 L1 entries,
276276
* 1024 lazy entries per table.
277277
*/
278-
#define CTXDESC_SPLIT 10
279-
#define CTXDESC_L2_ENTRIES (1 << CTXDESC_SPLIT)
278+
#define CTXDESC_L2_ENTRIES 1024
280279

281280
#define CTXDESC_L1_DESC_DWORDS 1
282281
#define CTXDESC_L1_DESC_V (1UL << 0)

0 commit comments

Comments
 (0)