Skip to content

Commit e53d630

Browse files
committed
iommu: apple-dart: Support specifying the DMA aperture in the DT
Apple DARTs are often connected directly to devices that expect only a portion of their address space to be used for DMA (for example, because other ranges are mapped directly to something else). Add an apple,dma-range property to allow specifying this range. This range *can* be outside of the DART's IAS. In that case, it is assumed that the hardware truncates addresses and the page tables will only map the lower bits of the address. However, the specified range cannot straddle an IAS boundary (you cannot cover more than IAS worth of address space nor wrap). This corresponds to the vm-base and vm-size properties on the Apple device tree side of things. Signed-off-by: Hector Martin <[email protected]>
1 parent 80e65d4 commit e53d630

1 file changed

Lines changed: 53 additions & 9 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 53 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <linux/io-pgtable.h>
2222
#include <linux/iommu.h>
2323
#include <linux/iopoll.h>
24+
#include <linux/minmax.h>
2425
#include <linux/module.h>
2526
#include <linux/of.h>
2627
#include <linux/of_address.h>
@@ -227,6 +228,9 @@ struct apple_dart {
227228
u32 locked : 1;
228229
u32 four_level : 1;
229230

231+
dma_addr_t dma_min;
232+
dma_addr_t dma_max;
233+
230234
struct iommu_group *sid2group[DART_MAX_STREAMS];
231235
struct iommu_device iommu;
232236

@@ -274,6 +278,7 @@ struct apple_dart_domain {
274278
struct io_pgtable_ops *pgtbl_ops;
275279

276280
bool finalized;
281+
u64 mask;
277282
struct mutex init_lock;
278283
struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
279284

@@ -621,7 +626,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
621626
if (!ops)
622627
return 0;
623628

624-
return ops->iova_to_phys(ops, iova);
629+
return ops->iova_to_phys(ops, iova & dart_domain->mask);
625630
}
626631

627632
static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
@@ -635,8 +640,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
635640
if (!ops)
636641
return -ENODEV;
637642

638-
return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
639-
mapped);
643+
return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize,
644+
pgcount, prot, gfp, mapped);
640645
}
641646

642647
static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
@@ -647,7 +652,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
647652
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
648653
struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
649654

650-
return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
655+
return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount,
656+
gather);
651657
}
652658

653659
static void
@@ -720,6 +726,8 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
720726
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
721727
struct apple_dart *dart = cfg->stream_maps[0].dart;
722728
struct io_pgtable_cfg pgtbl_cfg;
729+
dma_addr_t dma_max = dart->dma_max;
730+
u32 ias = min_t(u32, dart->ias, fls64(dma_max));
723731
int ret = 0;
724732
int i, j;
725733

@@ -737,7 +745,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
737745

738746
pgtbl_cfg = (struct io_pgtable_cfg){
739747
.pgsize_bitmap = dart->pgsize,
740-
.ias = dart->ias,
748+
.ias = ias,
741749
.oas = dart->oas,
742750
.coherent_walk = 1,
743751
.iommu_dev = dart->dev,
@@ -760,13 +768,21 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
760768
/* If the DART is locked, we need to keep the translation level count. */
761769
if (dart->hw->tcr_4level && dart->ias > 36) {
762770
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
763-
if (dart->ias < 37) {
771+
if (ias < 37) {
764772
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
765773
pgtbl_cfg.ias = 37;
766774
}
767-
} else if (dart->ias > 36) {
775+
} else if (ias > 36) {
768776
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
769777
pgtbl_cfg.ias = 36;
778+
if (dart->dma_min == 0 && dma_max == DMA_BIT_MASK(dart->ias)) {
779+
dma_max = DMA_BIT_MASK(pgtbl_cfg.ias);
780+
} else if ((dart->dma_min ^ dma_max) & ~DMA_BIT_MASK(36)) {
781+
dev_err(dart->dev,
782+
"Invalid DMA range for locked 3-level PT\n");
783+
ret = -ENOMEM;
784+
goto done;
785+
}
770786
}
771787
}
772788
}
@@ -778,9 +794,16 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
778794
goto done;
779795
}
780796

797+
if (pgtbl_cfg.pgsize_bitmap == SZ_4K)
798+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32));
799+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3)
800+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36));
801+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4)
802+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47));
803+
781804
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
782-
domain->geometry.aperture_start = 0;
783-
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
805+
domain->geometry.aperture_start = dart->dma_min;
806+
domain->geometry.aperture_end = dma_max;
784807
domain->geometry.force_aperture = true;
785808

786809
dart_domain->finalized = true;
@@ -1255,6 +1278,7 @@ static int apple_dart_probe(struct platform_device *pdev)
12551278
struct resource *res;
12561279
struct apple_dart *dart;
12571280
struct device *dev = &pdev->dev;
1281+
u64 dma_range[2];
12581282

12591283
dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
12601284
if (!dart)
@@ -1317,6 +1341,26 @@ static int apple_dart_probe(struct platform_device *pdev)
13171341
break;
13181342
}
13191343

1344+
dart->dma_min = 0;
1345+
dart->dma_max = DMA_BIT_MASK(dart->ias);
1346+
1347+
ret = of_property_read_u64_array(dev->of_node, "apple,dma-range", dma_range, 2);
1348+
if (ret == -EINVAL) {
1349+
ret = 0;
1350+
} else if (ret) {
1351+
goto err_clk_disable;
1352+
} else {
1353+
dart->dma_min = dma_range[0];
1354+
dart->dma_max = dma_range[0] + dma_range[1] - 1;
1355+
if ((dart->dma_min ^ dart->dma_max) & ~DMA_BIT_MASK(dart->ias)) {
1356+
dev_err(&pdev->dev, "Invalid DMA range for ias=%d\n",
1357+
dart->ias);
1358+
goto err_clk_disable;
1359+
}
1360+
dev_info(&pdev->dev, "Limiting DMA range to %pad..%pad\n",
1361+
&dart->dma_min, &dart->dma_max);
1362+
}
1363+
13201364
if (dart->num_streams > DART_MAX_STREAMS) {
13211365
dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
13221366
dart->num_streams, DART_MAX_STREAMS);

0 commit comments

Comments
 (0)