Skip to content

Commit 5863b5a

Browse files
marcanjannau
authored andcommitted
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 <marcan@marcan.st>
1 parent 053917e commit 5863b5a

1 file changed

Lines changed: 28 additions & 6 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 28 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;
@@ -222,6 +224,7 @@ struct apple_dart {
222224
u32 num_streams;
223225
u32 supports_bypass : 1;
224226
u32 locked : 1;
227+
u32 four_level : 1;
225228

226229
struct iommu_group *sid2group[DART_MAX_STREAMS];
227230
struct iommu_device iommu;
@@ -312,13 +315,16 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
312315
}
313316

314317
static void
315-
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
318+
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
316319
{
317320
struct apple_dart *dart = stream_map->dart;
318321
int sid;
319322

323+
WARN_ON(levels != 3 && levels != 4);
324+
WARN_ON(levels == 4 && !dart->four_level);
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)
@@ -653,7 +659,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
653659
for (; i < stream_map->dart->hw->ttbr_count; ++i)
654660
apple_dart_hw_clear_ttbr(stream_map, i);
655661

656-
apple_dart_hw_enable_translation(stream_map);
662+
apple_dart_hw_enable_translation(stream_map,
663+
pgtbl_cfg->apple_dart_cfg.n_levels);
657664
stream_map->dart->hw->invalidate_tlb(stream_map);
658665
}
659666

@@ -719,6 +726,19 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
719726
ttbr = readl(dart->regs + DART_TTBR(dart, sid, 0));
720727

721728
WARN_ON(!(ttbr & dart->hw->ttbr_valid));
729+
730+
/* If the DART is locked, we need to keep the translation level count. */
731+
if (dart->hw->tcr_4level && dart->ias > 36) {
732+
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
733+
if (dart->ias < 37) {
734+
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
735+
pgtbl_cfg.ias = 37;
736+
}
737+
} else if (dart->ias > 36) {
738+
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
739+
pgtbl_cfg.ias = 36;
740+
}
741+
}
722742
}
723743

724744
dart_domain->pgtbl_ops = alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg,
@@ -731,7 +751,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
731751
dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
732752
dart_domain->domain.geometry.aperture_start = 0;
733753
dart_domain->domain.geometry.aperture_end =
734-
(dma_addr_t)DMA_BIT_MASK(dart->ias);
754+
(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
735755
dart_domain->domain.geometry.force_aperture = true;
736756

737757
dart_domain->finalized = true;
@@ -1337,6 +1357,7 @@ static int apple_dart_probe(struct platform_device *pdev)
13371357
dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
13381358
dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
13391359
dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
1360+
dart->four_level = dart->ias > 36;
13401361
break;
13411362
}
13421363

@@ -1379,9 +1400,9 @@ static int apple_dart_probe(struct platform_device *pdev)
13791400

13801401
dev_info(
13811402
&pdev->dev,
1382-
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d] initialized\n",
1403+
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d, AS %d -> %d] initialized\n",
13831404
dart->pgsize, dart->num_streams, dart->supports_bypass,
1384-
dart->pgsize > PAGE_SIZE, dart->locked);
1405+
dart->pgsize > PAGE_SIZE, dart->locked, dart->ias, dart->oas);
13851406
return 0;
13861407

13871408
err_sysfs_remove:
@@ -1505,6 +1526,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
15051526
.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
15061527
.tcr_disabled = 0,
15071528
.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
1529+
.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
15081530

15091531
.ttbr = DART_T8110_TTBR,
15101532
.ttbr_valid = DART_T8110_TTBR_VALID,

0 commit comments

Comments
 (0)