Skip to content

Commit 59096bb

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 5829a0f commit 59096bb

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>
@@ -228,6 +229,9 @@ struct apple_dart {
228229
u32 locked : 1;
229230
u32 four_level : 1;
230231

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

@@ -272,6 +276,7 @@ struct apple_dart_domain {
272276
struct io_pgtable_ops *pgtbl_ops;
273277

274278
bool finalized;
279+
u64 mask;
275280
struct mutex init_lock;
276281
struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
277282

@@ -532,7 +537,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
532537
if (!ops)
533538
return 0;
534539

535-
return ops->iova_to_phys(ops, iova);
540+
return ops->iova_to_phys(ops, iova & dart_domain->mask);
536541
}
537542

538543
static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
@@ -546,8 +551,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
546551
if (!ops)
547552
return -ENODEV;
548553

549-
return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
550-
mapped);
554+
return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize,
555+
pgcount, prot, gfp, mapped);
551556
}
552557

553558
static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
@@ -558,7 +563,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
558563
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
559564
struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
560565

561-
return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
566+
return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount,
567+
gather);
562568
}
563569

564570
static void
@@ -624,6 +630,8 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
624630
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
625631
struct apple_dart *dart = cfg->stream_maps[0].dart;
626632
struct io_pgtable_cfg pgtbl_cfg;
633+
dma_addr_t dma_max = dart->dma_max;
634+
u32 ias = min_t(u32, dart->ias, fls64(dma_max));
627635
int ret = 0;
628636
int i, j;
629637

@@ -641,7 +649,7 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
641649

642650
pgtbl_cfg = (struct io_pgtable_cfg){
643651
.pgsize_bitmap = dart->pgsize,
644-
.ias = dart->ias,
652+
.ias = ias,
645653
.oas = dart->oas,
646654
.coherent_walk = 1,
647655
.iommu_dev = dart->dev,
@@ -672,13 +680,21 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
672680
/* If the DART is locked, we need to keep the translation level count. */
673681
if (dart->hw->tcr_4level && dart->ias > 36) {
674682
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
675-
if (dart->ias < 37) {
683+
if (ias < 37) {
676684
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
677685
pgtbl_cfg.ias = 37;
678686
}
679-
} else if (dart->ias > 36) {
687+
} else if (ias > 36) {
680688
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
681689
pgtbl_cfg.ias = 36;
690+
if (dart->dma_min == 0 && dma_max == DMA_BIT_MASK(dart->ias)) {
691+
dma_max = DMA_BIT_MASK(pgtbl_cfg.ias);
692+
} else if ((dart->dma_min ^ dma_max) & ~DMA_BIT_MASK(36)) {
693+
dev_err(dart->dev,
694+
"Invalid DMA range for locked 3-level PT\n");
695+
ret = -ENOMEM;
696+
goto done;
697+
}
682698
}
683699
}
684700
}
@@ -690,9 +706,16 @@ static int apple_dart_finalize_domain(struct iommu_domain *domain,
690706
goto done;
691707
}
692708

709+
if (pgtbl_cfg.pgsize_bitmap == SZ_4K)
710+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32));
711+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3)
712+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36));
713+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4)
714+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47));
715+
693716
domain->pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
694-
domain->geometry.aperture_start = 0;
695-
domain->geometry.aperture_end = (dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
717+
domain->geometry.aperture_start = dart->dma_min;
718+
domain->geometry.aperture_end = dma_max;
696719
domain->geometry.force_aperture = true;
697720

698721
dart_domain->finalized = true;
@@ -1173,6 +1196,7 @@ static int apple_dart_probe(struct platform_device *pdev)
11731196
struct resource *res;
11741197
struct apple_dart *dart;
11751198
struct device *dev = &pdev->dev;
1199+
u64 dma_range[2];
11761200

11771201
dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
11781202
if (!dart)
@@ -1235,6 +1259,26 @@ static int apple_dart_probe(struct platform_device *pdev)
12351259
break;
12361260
}
12371261

1262+
dart->dma_min = 0;
1263+
dart->dma_max = DMA_BIT_MASK(dart->ias);
1264+
1265+
ret = of_property_read_u64_array(dev->of_node, "apple,dma-range", dma_range, 2);
1266+
if (ret == -EINVAL) {
1267+
ret = 0;
1268+
} else if (ret) {
1269+
goto err_clk_disable;
1270+
} else {
1271+
dart->dma_min = dma_range[0];
1272+
dart->dma_max = dma_range[0] + dma_range[1] - 1;
1273+
if ((dart->dma_min ^ dart->dma_max) & ~DMA_BIT_MASK(dart->ias)) {
1274+
dev_err(&pdev->dev, "Invalid DMA range for ias=%d\n",
1275+
dart->ias);
1276+
goto err_clk_disable;
1277+
}
1278+
dev_info(&pdev->dev, "Limiting DMA range to %pad..%pad\n",
1279+
&dart->dma_min, &dart->dma_max);
1280+
}
1281+
12381282
if (dart->num_streams > DART_MAX_STREAMS) {
12391283
dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
12401284
dart->num_streams, DART_MAX_STREAMS);

0 commit comments

Comments
 (0)