Skip to content

Commit 32e1951

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 5863b5a commit 32e1951

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

@@ -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

@@ -615,7 +620,7 @@ static phys_addr_t apple_dart_iova_to_phys(struct iommu_domain *domain,
615620
if (!ops)
616621
return 0;
617622

618-
return ops->iova_to_phys(ops, iova);
623+
return ops->iova_to_phys(ops, iova & dart_domain->mask);
619624
}
620625

621626
static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
@@ -629,8 +634,8 @@ static int apple_dart_map_pages(struct iommu_domain *domain, unsigned long iova,
629634
if (!ops)
630635
return -ENODEV;
631636

632-
return ops->map_pages(ops, iova, paddr, pgsize, pgcount, prot, gfp,
633-
mapped);
637+
return ops->map_pages(ops, iova & dart_domain->mask, paddr, pgsize,
638+
pgcount, prot, gfp, mapped);
634639
}
635640

636641
static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
@@ -641,7 +646,8 @@ static size_t apple_dart_unmap_pages(struct iommu_domain *domain,
641646
struct apple_dart_domain *dart_domain = to_dart_domain(domain);
642647
struct io_pgtable_ops *ops = dart_domain->pgtbl_ops;
643648

644-
return ops->unmap_pages(ops, iova, pgsize, pgcount, gather);
649+
return ops->unmap_pages(ops, iova & dart_domain->mask, pgsize, pgcount,
650+
gather);
645651
}
646652

647653
static void
@@ -687,6 +693,8 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
687693
{
688694
struct apple_dart *dart = cfg->stream_maps[0].dart;
689695
struct io_pgtable_cfg pgtbl_cfg;
696+
dma_addr_t dma_max = dart->dma_max;
697+
u32 ias = min_t(u32, dart->ias, fls64(dma_max));
690698
int ret = 0;
691699
int i, j;
692700

@@ -707,7 +715,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
707715

708716
pgtbl_cfg = (struct io_pgtable_cfg){
709717
.pgsize_bitmap = dart->pgsize,
710-
.ias = dart->ias,
718+
.ias = ias,
711719
.oas = dart->oas,
712720
.coherent_walk = 1,
713721
.iommu_dev = dart->dev,
@@ -730,13 +738,21 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
730738
/* If the DART is locked, we need to keep the translation level count. */
731739
if (dart->hw->tcr_4level && dart->ias > 36) {
732740
if (readl(dart->regs + DART_TCR(dart, sid)) & dart->hw->tcr_4level) {
733-
if (dart->ias < 37) {
741+
if (ias < 37) {
734742
dev_info(dart->dev, "Expanded to ias=37 due to lock\n");
735743
pgtbl_cfg.ias = 37;
736744
}
737-
} else if (dart->ias > 36) {
745+
} else if (ias > 36) {
738746
dev_info(dart->dev, "Limited to ias=36 due to lock\n");
739747
pgtbl_cfg.ias = 36;
748+
if (dart->dma_min == 0 && dma_max == DMA_BIT_MASK(dart->ias)) {
749+
dma_max = DMA_BIT_MASK(pgtbl_cfg.ias);
750+
} else if ((dart->dma_min ^ dma_max) & ~DMA_BIT_MASK(36)) {
751+
dev_err(dart->dev,
752+
"Invalid DMA range for locked 3-level PT\n");
753+
ret = -ENOMEM;
754+
goto done;
755+
}
740756
}
741757
}
742758
}
@@ -748,10 +764,16 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
748764
goto done;
749765
}
750766

767+
if (pgtbl_cfg.pgsize_bitmap == SZ_4K)
768+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 32));
769+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 3)
770+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 36));
771+
else if (pgtbl_cfg.apple_dart_cfg.n_levels == 4)
772+
dart_domain->mask = DMA_BIT_MASK(min_t(u32, dart->ias, 47));
773+
751774
dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
752-
dart_domain->domain.geometry.aperture_start = 0;
753-
dart_domain->domain.geometry.aperture_end =
754-
(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
775+
dart_domain->domain.geometry.aperture_start = dart->dma_min;
776+
dart_domain->domain.geometry.aperture_end = dma_max;
755777
dart_domain->domain.geometry.force_aperture = true;
756778

757779
dart_domain->finalized = true;
@@ -1299,6 +1321,7 @@ static int apple_dart_probe(struct platform_device *pdev)
12991321
struct resource *res;
13001322
struct apple_dart *dart;
13011323
struct device *dev = &pdev->dev;
1324+
u64 dma_range[2];
13021325

13031326
dart = devm_kzalloc(dev, sizeof(*dart), GFP_KERNEL);
13041327
if (!dart)
@@ -1361,6 +1384,26 @@ static int apple_dart_probe(struct platform_device *pdev)
13611384
break;
13621385
}
13631386

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

0 commit comments

Comments
 (0)