Skip to content

Commit 5829a0f

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 aec4e00 commit 5829a0f

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
@@ -136,6 +136,7 @@
136136
#define DART_T8110_TCR 0x1000
137137
#define DART_T8110_TCR_REMAP GENMASK(11, 8)
138138
#define DART_T8110_TCR_REMAP_EN BIT(7)
139+
#define DART_T8110_TCR_FOUR_LEVEL BIT(3)
139140
#define DART_T8110_TCR_BYPASS_DAPF BIT(2)
140141
#define DART_T8110_TCR_BYPASS_DART BIT(1)
141142
#define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
@@ -180,6 +181,7 @@ struct apple_dart_hw {
180181
u32 tcr_enabled;
181182
u32 tcr_disabled;
182183
u32 tcr_bypass;
184+
u32 tcr_4level;
183185

184186
u32 ttbr;
185187
u32 ttbr_valid;
@@ -224,6 +226,7 @@ struct apple_dart {
224226
u32 supports_bypass : 1;
225227
u32 force_bypass : 1;
226228
u32 locked : 1;
229+
u32 four_level : 1;
227230

228231
struct iommu_group *sid2group[DART_MAX_STREAMS];
229232
struct iommu_device iommu;
@@ -309,14 +312,17 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
309312
}
310313

311314
static void
312-
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
315+
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
313316
{
314317
struct apple_dart *dart = stream_map->dart;
315318
int sid;
316319

320+
WARN_ON(levels != 3 && levels != 4);
321+
WARN_ON(levels == 4 && !dart->four_level);
317322
WARN_ON(stream_map->dart->locked);
318323
for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
319-
writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
324+
writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw->tcr_4level : 0),
325+
dart->regs + DART_TCR(dart, sid));
320326
}
321327

322328
static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
@@ -571,7 +577,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
571577
for (; i < stream_map->dart->hw->ttbr_count; ++i)
572578
apple_dart_hw_clear_ttbr(stream_map, i);
573579

574-
apple_dart_hw_enable_translation(stream_map);
580+
apple_dart_hw_enable_translation(stream_map,
581+
pgtbl_cfg->apple_dart_cfg.n_levels);
575582
}
576583
stream_map->dart->hw->invalidate_tlb(stream_map);
577584
}
@@ -661,6 +668,19 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
661668
phys = ((phys_addr_t) ttbr) << dart->hw->ttbr_shift;
662669
pgtbl_cfg.apple_dart_cfg.ttbr[0] = phys;
663670
pgtbl_cfg.quirks |= IO_PGTABLE_QUIRK_APPLE_LOCKED;
671+
672+
/* If the DART is locked, we need to keep the translation level count. */
673+
if (dart->hw->tcr_4level && dart->ias > 36) {
674+
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
675+
if (dart->ias < 37) {
676+
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
677+
pgtbl_cfg.ias = 37;
678+
}
679+
} else if (dart->ias > 36) {
680+
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
681+
pgtbl_cfg.ias = 36;
682+
}
683+
}
664684
}
665685

666686
dart_domain->pgtbl_ops =
@@ -672,7 +692,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
672692

673693
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
674694
domain->geometry.aperture_start = 0;
675-
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(dart->ias);
695+
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
676696
domain->geometry.force_aperture = true;
677697

678698
dart_domain->finalized = true;
@@ -1211,6 +1231,7 @@ static int apple_dart_probe(struct platform_device *pdev)
12111231
dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
12121232
dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
12131233
dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
1234+
dart->four_level = dart->ias > 36;
12141235
break;
12151236
}
12161237

@@ -1250,8 +1271,9 @@ static int apple_dart_probe(struct platform_device *pdev)
12501271

12511272
dev_info(
12521273
&pdev->dev,
1253-
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d] initialized\n",
1254-
dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass, dart->locked);
1274+
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d, AS %d -> %d] initialized\n",
1275+
dart->pgsize, dart->num_streams, dart->supports_bypass, dart->force_bypass, dart->locked,
1276+
dart->ias, dart->oas);
12551277
return 0;
12561278

12571279
err_sysfs_remove:
@@ -1350,6 +1372,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
13501372
.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
13511373
.tcr_disabled = 0,
13521374
.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
1375+
.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
13531376

13541377
.ttbr = DART_T8110_TTBR,
13551378
.ttbr_valid = DART_T8110_TTBR_VALID,

0 commit comments

Comments
 (0)