Skip to content

Commit 40ce8ec

Browse files
marcanjannau
authored andcommitted
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 <marcan@marcan.st>
1 parent 4d5b50e commit 40ce8ec

1 file changed

Lines changed: 43 additions & 8 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 43 additions & 8 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>
@@ -224,6 +225,9 @@ struct apple_dart {
224225
u32 supports_bypass : 1;
225226
u32 four_level : 1;
226227

228+
dma_addr_t dma_min;
229+
dma_addr_t dma_max;
230+
227231
struct iommu_group *sid2group[DART_MAX_STREAMS];
228232
struct iommu_device iommu;
229233

@@ -268,6 +272,7 @@ struct apple_dart_domain {
268272
struct io_pgtable_ops *pgtbl_ops;
269273

270274
bool finalized;
275+
u64 mask;
271276
struct mutex init_lock;
272277
struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
273278

@@ -537,7 +542,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
537542
if (!ops)
538543
return 0;
539544

540-
return ops->iova_to_phys(ops, iova);
545+
return ops->iova_to_phys(ops, iova & dart_domain->mask);
541546
}
542547

543548
static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
@@ -551,8 +556,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
551556
if (!ops)
552557
return -ENODEV;
553558

554-
return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
555-
mapped);
559+
return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize,
560+
pgcount, prot, gfp, mapped);
556561
}
557562

558563
static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
@@ -563,7 +568,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
563568
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
564569
struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
565570

566-
return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
571+
return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount,
572+
gather);
567573
}
568574

569575
static void
@@ -590,6 +596,8 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
590596
{
591597
struct apple_dart *dart = cfg->stream_maps[0].dart;
592598
struct io_pgtable_cfg pgtbl_cfg;
599+
dma_addr_t dma_max = dart->dma_max;
600+
u32 ias = min_t(u32, dart->ias, fls64(dma_max));
593601
int ret = 0;
594602
int i, j;
595603

@@ -610,7 +618,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
610618

611619
pgtbl_cfg = (struct io_pgtable_cfg){
612620
.pgsize_bitmap = dart->pgsize,
613-
.ias = dart->ias,
621+
.ias = ias,
614622
.oas = dart->oas,
615623
.coherent_walk = 1,
616624
.iommu_dev = dart->dev,
@@ -623,10 +631,16 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
623631
goto done;
624632
}
625633

634+
if (pgtbl_cfg.pgsize_bitmap == SZ_4K)
635+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32));
636+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3)
637+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36));
638+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4)
639+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47));
640+
626641
dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
627-
dart_domain->domain.geometry.aperture_start = 0;
628-
dart_domain->domain.geometry.aperture_end =
629-
(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
642+
dart_domain->domain.geometry.aperture_start = dart->dma_min;
643+
dart_domain->domain.geometry.aperture_end = dma_max;
630644
dart_domain->domain.geometry.force_aperture = true;
631645

632646
dart_domain->finalized = true;
@@ -1132,6 +1146,7 @@ static int apple_dart_probe(struct platform_device *pdev)
11321146
struct resource *res;
11331147
struct apple_dart *dart;
11341148
struct device *dev = &pdev->dev;
1149+
u64 dma_range[2];
11351150

11361151
dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
11371152
if (!dart)
@@ -1194,6 +1209,26 @@ static int apple_dart_probe(struct platform_device *pdev)
11941209
break;
11951210
}
11961211

1212+
dart->dma_min = 0;
1213+
dart->dma_max = DMA_BIT_MASK(dart->ias);
1214+
1215+
ret = of_property_read_u64_array(dev->of_node, "apple,dma-range", dma_range, 2);
1216+
if (ret == -EINVAL) {
1217+
ret = 0;
1218+
} else if (ret) {
1219+
goto err_clk_disable;
1220+
} else {
1221+
dart->dma_min = dma_range[0];
1222+
dart->dma_max = dma_range[0] + dma_range[1] - 1;
1223+
if ((dart->dma_min ^ dart->dma_max) & ~DMA_BIT_MASK(dart->ias)) {
1224+
dev_err(&pdev->dev, "Invalid DMA range for ias=%d\n",
1225+
dart->ias);
1226+
goto err_clk_disable;
1227+
}
1228+
dev_info(&pdev->dev, "Limiting DMA range to %pad..%pad\n",
1229+
&dart->dma_min, &dart->dma_max);
1230+
}
1231+
11971232
if (dart->num_streams > DART_MAX_STREAMS) {
11981233
dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
11991234
dart->num_streams, DART_MAX_STREAMS);

0 commit comments

Comments
 (0)