Skip to content

Commit 80e65d4

Browse files
committed
iommu: apple-dart: Add 4-level page table support
The T8110 variant DART implementation on T602x SoCs indicates an IAS of 42, which requires an extra page table level. The extra level is optional, but let's implement it. Later it might be useful to restrict this based on the actual attached devices, since most won't need that much address space anyway. Signed-off-by: Hector Martin <[email protected]>
1 parent 66bf5f5 commit 80e65d4

1 file changed

Lines changed: 29 additions & 6 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,7 @@
135135
#define DART_T8110_TCR 0x1000
136136
#define DART_T8110_TCR_REMAP GENMASK(11, 8)
137137
#define DART_T8110_TCR_REMAP_EN BIT(7)
138+
#define DART_T8110_TCR_FOUR_LEVEL BIT(3)
138139
#define DART_T8110_TCR_BYPASS_DAPF BIT(2)
139140
#define DART_T8110_TCR_BYPASS_DART BIT(1)
140141
#define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
@@ -179,6 +180,7 @@ struct apple_dart_hw {
179180
u32 tcr_enabled;
180181
u32 tcr_disabled;
181182
u32 tcr_bypass;
183+
u32 tcr_4level;
182184

183185
u32 ttbr;
184186
u32 ttbr_valid;
@@ -223,6 +225,7 @@ struct apple_dart {
223225
u32 supports_bypass : 1;
224226
u32 force_bypass : 1;
225227
u32 locked : 1;
228+
u32 four_level : 1;
226229

227230
struct iommu_group *sid2group[DART_MAX_STREAMS];
228231
struct iommu_device iommu;
@@ -311,14 +314,17 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
311314
}
312315

313316
static void
314-
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
317+
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
315318
{
316319
struct apple_dart *dart = stream_map->dart;
317320
int sid;
318321

322+
WARN_ON(levels != 3 && levels != 4);
323+
WARN_ON(levels == 4 && !dart->four_level);
319324
WARN_ON(stream_map->dart->locked);
320325
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
321-
writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
326+
writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw->tcr_4level : 0),
327+
dart->regs + DART_TCR(dart, sid));
322328
}
323329

324330
static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
@@ -667,7 +673,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
667673
for (; i < stream_map->dart->hw->ttbr_count; ++i)
668674
apple_dart_hw_clear_ttbr(stream_map, i);
669675

670-
apple_dart_hw_enable_translation(stream_map);
676+
apple_dart_hw_enable_translation(stream_map,
677+
pgtbl_cfg->apple_dart_cfg.n_levels);
671678
}
672679
stream_map->dart->hw->invalidate_tlb(stream_map);
673680
}
@@ -749,6 +756,19 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
749756
ttbr = readl(dart->regs + DART_TTBR(dart, sid, 0));
750757

751758
WARN_ON(!(ttbr & dart->hw->ttbr_valid));
759+
760+
/* If the DART is locked, we need to keep the translation level count. */
761+
if (dart->hw->tcr_4level && dart->ias > 36) {
762+
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
763+
if (dart->ias < 37) {
764+
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
765+
pgtbl_cfg.ias = 37;
766+
}
767+
} else if (dart->ias > 36) {
768+
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
769+
pgtbl_cfg.ias = 36;
770+
}
771+
}
752772
}
753773

754774
dart_domain->pgtbl_ops =
@@ -760,7 +780,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
760780

761781
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
762782
domain->geometry.aperture_start = 0;
763-
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(dart->ias);
783+
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
764784
domain->geometry.force_aperture = true;
765785

766786
dart_domain->finalized = true;
@@ -1293,6 +1313,7 @@ static int apple_dart_probe(struct platform_device *pdev)
12931313
dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
12941314
dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
12951315
dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
1316+
dart->four_level = dart->ias > 36;
12961317
break;
12971318
}
12981319

@@ -1332,8 +1353,9 @@ static int apple_dart_probe(struct platform_device *pdev)
13321353

13331354
dev_info(
13341355
&pdev->dev,
1335-
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d] initialized\n",
1336-
dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass, dart->locked);
1356+
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d, AS %d -> %d] initialized\n",
1357+
dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass, dart->locked,
1358+
dart->ias, dart->oas);
13371359
return 0;
13381360

13391361
err_sysfs_remove:
@@ -1430,6 +1452,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
14301452
.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
14311453
.tcr_disabled = 0,
14321454
.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
1455+
.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
14331456

14341457
.ttbr = DART_T8110_TTBR,
14351458
.ttbr_valid = DART_T8110_TTBR_VALID,

0 commit comments

Comments
 (0)