Skip to content

Commit a5e4f38

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

1 file changed

Lines changed: 53 additions & 10 deletions

File tree

drivers/iommu/apple-dart.c

Lines changed: 53 additions & 10 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>
@@ -226,6 +227,9 @@ struct apple_dart {
226227
u32 locked : 1;
227228
u32 four_level : 1;
228229

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

@@ -273,6 +277,7 @@ struct apple_dart_domain {
273277
struct io_pgtable_ops *pgtbl_ops;
274278

275279
bool finalized;
280+
u64 mask;
276281
struct mutex init_lock;
277282
struct apple_dart_atomic_stream_map stream_maps[MAX_DARTS_PER_DEVICE];
278283

@@ -623,7 +628,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
623628
if (!ops)
624629
return 0;
625630

626-
return ops->iova_to_phys(ops, iova);
631+
return ops->iova_to_phys(ops, iova & dart_domain->mask);
627632
}
628633

629634
static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
@@ -637,8 +642,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
637642
if (!ops)
638643
return -ENODEV;
639644

640-
return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
641-
mapped);
645+
return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize,
646+
pgcount, prot, gfp, mapped);
642647
}
643648

644649
static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
@@ -649,7 +654,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
649654
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
650655
struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
651656

652-
return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
657+
return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount,
658+
gather);
653659
}
654660

655661
static void
@@ -721,6 +727,8 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
721727
{
722728
struct apple_dart *dart = cfg->stream_maps[0].dart;
723729
struct io_pgtable_cfg pgtbl_cfg;
730+
dma_addr_t dma_max = dart->dma_max;
731+
u32 ias = min_t(u32, dart->ias, fls64(dma_max));
724732
int ret = 0;
725733
int i, j;
726734

@@ -741,7 +749,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
741749

742750
pgtbl_cfg = (struct io_pgtable_cfg){
743751
.pgsize_bitmap = dart->pgsize,
744-
.ias = dart->ias,
752+
.ias = ias,
745753
.oas = dart->oas,
746754
.coherent_walk = 1,
747755
.iommu_dev = dart->dev,
@@ -764,13 +772,21 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
764772
/* If the DART is locked, we need to keep the translation level count. */
765773
if (dart->hw->tcr_4level && dart->ias > 36) {
766774
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
767-
if (dart->ias < 37) {
775+
if (ias < 37) {
768776
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
769777
pgtbl_cfg.ias = 37;
770778
}
771-
} else if (dart->ias > 36) {
779+
} else if (ias > 36) {
772780
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
773781
pgtbl_cfg.ias = 36;
782+
if (dart->dma_min == 0 && dma_max == DMA_BIT_MASK(dart->ias)) {
783+
dma_max = DMA_BIT_MASK(pgtbl_cfg.ias);
784+
} else if ((dart->dma_min ^ dma_max) & ~DMA_BIT_MASK(36)) {
785+
dev_err(dart->dev,
786+
"Invalid DMA range for locked 3-level PT\n");
787+
ret = -ENOMEM;
788+
goto done;
789+
}
774790
}
775791
}
776792
}
@@ -782,10 +798,16 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
782798
goto done;
783799
}
784800

801+
if (pgtbl_cfg.pgsize_bitmap == SZ_4K)
802+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32));
803+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3)
804+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36));
805+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4)
806+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47));
807+
785808
dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
786-
dart_domain->domain.geometry.aperture_start = 0;
787-
dart_domain->domain.geometry.aperture_end =
788-
(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
809+
dart_domain->domain.geometry.aperture_start = dart->dma_min;
810+
dart_domain->domain.geometry.aperture_end = dma_max;
789811
dart_domain->domain.geometry.force_aperture = true;
790812

791813
dart_domain->finalized = true;
@@ -1298,6 +1320,7 @@ static int apple_dart_probe(struct platform_device *pdev)
12981320
struct resource *res;
12991321
struct apple_dart *dart;
13001322
struct device *dev = &pdev->dev;
1323+
u64 dma_range[2];
13011324

13021325
dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
13031326
if (!dart)
@@ -1360,6 +1383,26 @@ static int apple_dart_probe(struct platform_device *pdev)
13601383
break;
13611384
}
13621385

1386+
dart->dma_min = 0;
1387+
dart->dma_max = DMA_BIT_MASK(dart->ias);
1388+
1389+
ret = of_property_read_u64_array(dev->of_node, "apple,dma-range", dma_range, 2);
1390+
if (ret == -EINVAL) {
1391+
ret = 0;
1392+
} else if (ret) {
1393+
goto err_clk_disable;
1394+
} else {
1395+
dart->dma_min = dma_range[0];
1396+
dart->dma_max = dma_range[0] + dma_range[1] - 1;
1397+
if ((dart->dma_min ^ dart->dma_max) & ~DMA_BIT_MASK(dart->ias)) {
1398+
dev_err(&pdev->dev, "Invalid DMA range for ias=%d\n",
1399+
dart->ias);
1400+
goto err_clk_disable;
1401+
}
1402+
dev_info(&pdev->dev, "Limiting DMA range to %pad..%pad\n",
1403+
&dart->dma_min, &dart->dma_max);
1404+
}
1405+
13631406
if (dart->num_streams > DART_MAX_STREAMS) {
13641407
dev_err(&pdev->dev, "Too many streams (%d > %d)\n",
13651408
dart->num_streams, DART_MAX_STREAMS);

0 commit comments

Comments
 (0)