Skip to content

Commit 698749e

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 bdb105d commit 698749e

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;
@@ -310,14 +313,17 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
310313
}
311314

312315
static void
313-
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
316+
apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
314317
{
315318
struct apple_dart *dart = stream_map->dart;
316319
int sid;
317320

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

323329
static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
@@ -669,7 +675,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
669675
for (; i < stream_map->dart->hw->ttbr_count; ++i)
670676
apple_dart_hw_clear_ttbr(stream_map, i);
671677

672-
apple_dart_hw_enable_translation(stream_map);
678+
apple_dart_hw_enable_translation(stream_map,
679+
pgtbl_cfg->apple_dart_cfg.n_levels);
673680
}
674681
stream_map->dart->hw->invalidate_tlb(stream_map);
675682
}
@@ -753,6 +760,19 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
753760
ttbr = readl(dart->regs + DART_TTBR(dart, sid, 0));
754761

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

758778
dart_domain->pgtbl_ops = alloc_io_pgtable_ops(dart->hw->fmt, &pgtbl_cfg,
@@ -765,7 +785,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
765785
dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
766786
dart_domain->domain.geometry.aperture_start = 0;
767787
dart_domain->domain.geometry.aperture_end =
768-
(dma_addr_t)DMA_BIT_MASK(dart->ias);
788+
(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
769789
dart_domain->domain.geometry.force_aperture = true;
770790

771791
dart_domain->finalized = true;
@@ -1336,6 +1356,7 @@ static int apple_dart_probe(struct platform_device *pdev)
13361356
dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
13371357
dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
13381358
dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
1359+
dart->four_level = dart->ias > 36;
13391360
break;
13401361
}
13411362

@@ -1373,9 +1394,9 @@ static int apple_dart_probe(struct platform_device *pdev)
13731394

13741395
dev_info(
13751396
&pdev->dev,
1376-
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d] initialized\n",
1397+
"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, locked: %d, AS %d -> %d] initialized\n",
13771398
dart->pgsize, dart->num_streams, dart->supports_bypass,
1378-
dart->pgsize > PAGE_SIZE, dart->locked);
1399+
dart->pgsize > PAGE_SIZE, dart->locked, dart->ias, dart->oas);
13791400
return 0;
13801401

13811402
err_sysfs_remove:
@@ -1499,6 +1520,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
14991520
.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
15001521
.tcr_disabled = 0,
15011522
.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
1523+
.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
15021524

15031525
.ttbr = DART_T8110_TTBR,
15041526
.ttbr_valid = DART_T8110_TTBR_VALID,

0 commit comments

Comments
 (0)