linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/3] iommu: apple-dart: Four level page table support
@ 2025-08-14  8:40 Janne Grunau
  2025-08-14  8:40 ` [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s Janne Grunau
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Janne Grunau @ 2025-08-14  8:40 UTC (permalink / raw)
  To: Sven Peter, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Janne Grunau,
	Hector Martin

The DART instances found in T602x based SoCs (Apple's M2 Pro/Max/Ultra)
indicate an IAS of 42 bit. This results in alloc_io_pgtable_ops()
failing as io-pgtable-dart supports at most 36-bit IAS.
The t8110 DART design supports 4-level page tables. Implement support
for this in io-pgtable-dart and mark DART stream with more than 36-bit
IAS as 4-level page tables.

Signed-off-by: Janne Grunau <j@jannau.net>
---
Hector Martin (3):
      iommu: apple-dart: Make the hw register fields u32s
      iommu: io-pgtable: Add 4-level page table support
      iommu: apple-dart: Add 4-level page table support

 drivers/iommu/apple-dart.c      |  47 ++++++++-----
 drivers/iommu/io-pgtable-dart.c | 143 ++++++++++++++++++++++++----------------
 include/linux/io-pgtable.h      |   1 +
 3 files changed, 118 insertions(+), 73 deletions(-)
---
base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
change-id: 20250811-apple-dart-4levels-8f9ae8ac1347

Best regards,
-- 
Janne Grunau <j@jannau.net>


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s
  2025-08-14  8:40 [PATCH 0/3] iommu: apple-dart: Four level page table support Janne Grunau
@ 2025-08-14  8:40 ` Janne Grunau
  2025-08-16 13:51   ` Sven Peter
  2025-08-14  8:40 ` [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support Janne Grunau
  2025-08-14  8:40 ` [PATCH 3/3] iommu: apple-dart: " Janne Grunau
  2 siblings, 1 reply; 9+ messages in thread
From: Janne Grunau @ 2025-08-14  8:40 UTC (permalink / raw)
  To: Sven Peter, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Janne Grunau,
	Hector Martin

From: Hector Martin <marcan@marcan.st>

The registers are 32-bit and the offsets definitely don't need 64 bits
either, these should've been u32s.

Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Janne Grunau <j@jannau.net>
---
 drivers/iommu/apple-dart.c | 24 ++++++++++++------------
 1 file changed, 12 insertions(+), 12 deletions(-)

diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
index 190f28d76615159527649cd288df395a50d950ef..e72a93e78e26ca61b233c83d439dbdfadf040fc6 100644
--- a/drivers/iommu/apple-dart.c
+++ b/drivers/iommu/apple-dart.c
@@ -166,22 +166,22 @@ struct apple_dart_hw {
 
 	int max_sid_count;
 
-	u64 lock;
-	u64 lock_bit;
+	u32 lock;
+	u32 lock_bit;
 
-	u64 error;
+	u32 error;
 
-	u64 enable_streams;
+	u32 enable_streams;
 
-	u64 tcr;
-	u64 tcr_enabled;
-	u64 tcr_disabled;
-	u64 tcr_bypass;
+	u32 tcr;
+	u32 tcr_enabled;
+	u32 tcr_disabled;
+	u32 tcr_bypass;
 
-	u64 ttbr;
-	u64 ttbr_valid;
-	u64 ttbr_addr_field_shift;
-	u64 ttbr_shift;
+	u32 ttbr;
+	u32 ttbr_valid;
+	u32 ttbr_addr_field_shift;
+	u32 ttbr_shift;
 	int ttbr_count;
 };
 

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support
  2025-08-14  8:40 [PATCH 0/3] iommu: apple-dart: Four level page table support Janne Grunau
  2025-08-14  8:40 ` [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s Janne Grunau
@ 2025-08-14  8:40 ` Janne Grunau
  2025-08-16 14:02   ` Sven Peter
  2025-08-14  8:40 ` [PATCH 3/3] iommu: apple-dart: " Janne Grunau
  2 siblings, 1 reply; 9+ messages in thread
From: Janne Grunau @ 2025-08-14  8:40 UTC (permalink / raw)
  To: Sven Peter, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Janne Grunau,
	Hector Martin

From: Hector Martin <marcan@marcan.st>

DARTs on t602x SoCs are of the t8110 variant but have an IAS of 42,
which means optional support for an extra page table level.

Refactor the PTE management to support an arbitrary level count, and
then calculate how many levels we need for any given configuration.

Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Janne Grunau <j@jannau.net>
---
 drivers/iommu/io-pgtable-dart.c | 143 ++++++++++++++++++++++++----------------
 include/linux/io-pgtable.h      |   1 +
 2 files changed, 89 insertions(+), 55 deletions(-)

diff --git a/drivers/iommu/io-pgtable-dart.c b/drivers/iommu/io-pgtable-dart.c
index 679bda1047977602f468ef905b48aeeebcd7a234..9a63c80a2786bf70fc2544b1f96d2e4c8591c2f8 100644
--- a/drivers/iommu/io-pgtable-dart.c
+++ b/drivers/iommu/io-pgtable-dart.c
@@ -27,8 +27,9 @@
 
 #define DART1_MAX_ADDR_BITS	36
 
-#define DART_MAX_TABLES		4
-#define DART_LEVELS		2
+#define DART_MAX_TABLE_BITS	2
+#define DART_MAX_TABLES		BIT(DART_MAX_TABLE_BITS)
+#define DART_MAX_LEVELS		4 /* Includes TTBR level */
 
 /* Struct accessors */
 #define io_pgtable_to_data(x)						\
@@ -68,6 +69,7 @@
 struct dart_io_pgtable {
 	struct io_pgtable	iop;
 
+	int			levels;
 	int			tbl_bits;
 	int			bits_per_level;
 
@@ -156,44 +158,45 @@ static dart_iopte dart_install_table(dart_iopte *table,
 	return old;
 }
 
-static int dart_get_table(struct dart_io_pgtable *data, unsigned long iova)
+static int dart_get_index(struct dart_io_pgtable *data, unsigned long iova, int level)
 {
-	return (iova >> (3 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
-		((1 << data->tbl_bits) - 1);
+	return (iova >> (level * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
+		((1 << data->bits_per_level) - 1);
 }
 
-static int dart_get_l1_index(struct dart_io_pgtable *data, unsigned long iova)
-{
-
-	return (iova >> (2 * data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
-		 ((1 << data->bits_per_level) - 1);
-}
-
-static int dart_get_l2_index(struct dart_io_pgtable *data, unsigned long iova)
+static int dart_get_last_index(struct dart_io_pgtable *data, unsigned long iova)
 {
 
 	return (iova >> (data->bits_per_level + ilog2(sizeof(dart_iopte)))) &
 		 ((1 << data->bits_per_level) - 1);
 }
 
-static  dart_iopte *dart_get_l2(struct dart_io_pgtable *data, unsigned long iova)
+static dart_iopte *dart_get_last(struct dart_io_pgtable *data, unsigned long iova)
 {
 	dart_iopte pte, *ptep;
-	int tbl = dart_get_table(data, iova);
+	int level = data->levels;
+	int tbl = dart_get_index(data, iova, level);
+
+	if (tbl > (1 << data->tbl_bits))
+		return NULL;
 
 	ptep = data->pgd[tbl];
 	if (!ptep)
 		return NULL;
 
-	ptep += dart_get_l1_index(data, iova);
-	pte = READ_ONCE(*ptep);
+	while (--level > 1) {
+		ptep += dart_get_index(data, iova, level);
+		pte = READ_ONCE(*ptep);
 
-	/* Valid entry? */
-	if (!pte)
-		return NULL;
+		/* Valid entry? */
+		if (!pte)
+			return NULL;
 
-	/* Deref to get level 2 table */
-	return iopte_deref(pte, data);
+		/* Deref to get next level table */
+		ptep = iopte_deref(pte, data);
+	}
+
+	return ptep;
 }
 
 static dart_iopte dart_prot_to_pte(struct dart_io_pgtable *data,
@@ -230,6 +233,7 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
 	int ret = 0, tbl, num_entries, max_entries, map_idx_start;
 	dart_iopte pte, *cptep, *ptep;
 	dart_iopte prot;
+	int level = data->levels;
 
 	if (WARN_ON(pgsize != cfg->pgsize_bitmap))
 		return -EINVAL;
@@ -240,31 +244,36 @@ static int dart_map_pages(struct io_pgtable_ops *ops, unsigned long iova,
 	if (!(iommu_prot & (IOMMU_READ | IOMMU_WRITE)))
 		return -EINVAL;
 
-	tbl = dart_get_table(data, iova);
+	tbl = dart_get_index(data, iova, level);
+
+	if (tbl > (1 << data->tbl_bits))
+		return -ENOMEM;
 
 	ptep = data->pgd[tbl];
-	ptep += dart_get_l1_index(data, iova);
-	pte = READ_ONCE(*ptep);
-
-	/* no L2 table present */
-	if (!pte) {
-		cptep = iommu_alloc_pages_sz(gfp, tblsz);
-		if (!cptep)
-			return -ENOMEM;
-
-		pte = dart_install_table(cptep, ptep, 0, data);
-		if (pte)
-			iommu_free_pages(cptep);
-
-		/* L2 table is present (now) */
+	while (--level > 1) {
+		ptep += dart_get_index(data, iova, level);
 		pte = READ_ONCE(*ptep);
-	}
 
-	ptep = iopte_deref(pte, data);
+		/* no table present */
+		if (!pte) {
+			cptep = iommu_alloc_pages_sz(gfp, tblsz);
+			if (!cptep)
+				return -ENOMEM;
+
+			pte = dart_install_table(cptep, ptep, 0, data);
+			if (pte)
+				iommu_free_pages(cptep);
+
+			/* L2 table is present (now) */
+			pte = READ_ONCE(*ptep);
+		}
+
+		ptep = iopte_deref(pte, data);
+	}
 
 	/* install a leaf entries into L2 table */
 	prot = dart_prot_to_pte(data, iommu_prot);
-	map_idx_start = dart_get_l2_index(data, iova);
+	map_idx_start = dart_get_last_index(data, iova);
 	max_entries = DART_PTES_PER_TABLE(data) - map_idx_start;
 	num_entries = min_t(int, pgcount, max_entries);
 	ptep += map_idx_start;
@@ -293,13 +302,13 @@ static size_t dart_unmap_pages(struct io_pgtable_ops *ops, unsigned long iova,
 	if (WARN_ON(pgsize != cfg->pgsize_bitmap || !pgcount))
 		return 0;
 
-	ptep = dart_get_l2(data, iova);
+	ptep = dart_get_last(data, iova);
 
 	/* Valid L2 IOPTE pointer? */
 	if (WARN_ON(!ptep))
 		return 0;
 
-	unmap_idx_start = dart_get_l2_index(data, iova);
+	unmap_idx_start = dart_get_last_index(data, iova);
 	ptep += unmap_idx_start;
 
 	max_entries = DART_PTES_PER_TABLE(data) - unmap_idx_start;
@@ -330,13 +339,13 @@ static phys_addr_t dart_iova_to_phys(struct io_pgtable_ops *ops,
 	struct dart_io_pgtable *data = io_pgtable_ops_to_data(ops);
 	dart_iopte pte, *ptep;
 
-	ptep = dart_get_l2(data, iova);
+	ptep = dart_get_last(data, iova);
 
 	/* Valid L2 IOPTE pointer? */
 	if (!ptep)
 		return 0;
 
-	ptep += dart_get_l2_index(data, iova);
+	ptep += dart_get_last_index(data, iova);
 
 	pte = READ_ONCE(*ptep);
 	/* Found translation */
@@ -353,21 +362,37 @@ static struct dart_io_pgtable *
 dart_alloc_pgtable(struct io_pgtable_cfg *cfg)
 {
 	struct dart_io_pgtable *data;
-	int tbl_bits, bits_per_level, va_bits, pg_shift;
+	int levels, max_tbl_bits, tbl_bits, bits_per_level, va_bits, pg_shift;
+
+	/*
+	 * Old 4K page DARTs can use up to 4 top-level tables.
+	 * Newer ones only ever use a maximum of 1.
+	 */
+	if (cfg->pgsize_bitmap == SZ_4K)
+		max_tbl_bits = DART_MAX_TABLE_BITS;
+	else
+		max_tbl_bits = 0;
 
 	pg_shift = __ffs(cfg->pgsize_bitmap);
 	bits_per_level = pg_shift - ilog2(sizeof(dart_iopte));
 
 	va_bits = cfg->ias - pg_shift;
 
-	tbl_bits = max_t(int, 0, va_bits - (bits_per_level * DART_LEVELS));
-	if ((1 << tbl_bits) > DART_MAX_TABLES)
+	levels = max_t(int, 2, (va_bits - max_tbl_bits + bits_per_level - 1) / bits_per_level);
+
+	if (levels > (DART_MAX_LEVELS - 1))
+		return NULL;
+
+	tbl_bits = max_t(int, 0, va_bits - (bits_per_level * levels));
+
+	if (tbl_bits > max_tbl_bits)
 		return NULL;
 
 	data = kzalloc(sizeof(*data), GFP_KERNEL);
 	if (!data)
 		return NULL;
 
+	data->levels = levels + 1; /* Table level counts as one level */
 	data->tbl_bits = tbl_bits;
 	data->bits_per_level = bits_per_level;
 
@@ -403,6 +428,7 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
 		return NULL;
 
 	cfg->apple_dart_cfg.n_ttbrs = 1 << data->tbl_bits;
+	cfg->apple_dart_cfg.n_levels = data->levels;
 
 	for (i = 0; i < cfg->apple_dart_cfg.n_ttbrs; ++i) {
 		data->pgd[i] =
@@ -422,24 +448,31 @@ apple_dart_alloc_pgtable(struct io_pgtable_cfg *cfg, void *cookie)
 	return NULL;
 }
 
-static void apple_dart_free_pgtable(struct io_pgtable *iop)
+static void apple_dart_free_pgtables(struct dart_io_pgtable *data, dart_iopte *ptep, int level)
 {
-	struct dart_io_pgtable *data = io_pgtable_to_data(iop);
-	dart_iopte *ptep, *end;
-	int i;
+	dart_iopte *end;
+	dart_iopte *start = ptep;
 
-	for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i) {
-		ptep = data->pgd[i];
+	if (level > 1) {
 		end = (void *)ptep + DART_GRANULE(data);
 
 		while (ptep != end) {
 			dart_iopte pte = *ptep++;
 
 			if (pte)
-				iommu_free_pages(iopte_deref(pte, data));
+				apple_dart_free_pgtables(data, iopte_deref(pte, data), level - 1);
 		}
-		iommu_free_pages(data->pgd[i]);
 	}
+	iommu_free_pages(start);
+}
+
+static void apple_dart_free_pgtable(struct io_pgtable *iop)
+{
+	struct dart_io_pgtable *data = io_pgtable_to_data(iop);
+	int i;
+
+	for (i = 0; i < (1 << data->tbl_bits) && data->pgd[i]; ++i)
+		apple_dart_free_pgtables(data, data->pgd[i], data->levels - 1);
 
 	kfree(data);
 }
diff --git a/include/linux/io-pgtable.h b/include/linux/io-pgtable.h
index 138fbd89b1e633b8dad7a931d507c4809e40a171..8a823c6f2b4a88cbb96273d3aaf972b6a4c222a3 100644
--- a/include/linux/io-pgtable.h
+++ b/include/linux/io-pgtable.h
@@ -180,6 +180,7 @@ struct io_pgtable_cfg {
 		struct {
 			u64 ttbr[4];
 			u32 n_ttbrs;
+			u32 n_levels;
 		} apple_dart_cfg;
 
 		struct {

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* [PATCH 3/3] iommu: apple-dart: Add 4-level page table support
  2025-08-14  8:40 [PATCH 0/3] iommu: apple-dart: Four level page table support Janne Grunau
  2025-08-14  8:40 ` [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s Janne Grunau
  2025-08-14  8:40 ` [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support Janne Grunau
@ 2025-08-14  8:40 ` Janne Grunau
  2025-08-16 13:50   ` Sven Peter
  2 siblings, 1 reply; 9+ messages in thread
From: Janne Grunau @ 2025-08-14  8:40 UTC (permalink / raw)
  To: Sven Peter, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Janne Grunau,
	Hector Martin

From: Hector Martin <marcan@marcan.st>

The T8110 variant DART implementation on T602x SoCs indicates an IAS of
42, which requires an extra page table level. The extra level is
optional, but let's implement it.

Since the driver failed at IO page table creation with 42-bit IAS add
"apple,t6020-dart" as separate compatible using the T8110 HW data.

Later it might be useful to restrict this based on the actual attached
devices, since most won't need that much address space anyway.

Signed-off-by: Hector Martin <marcan@marcan.st>
Signed-off-by: Janne Grunau <j@jannau.net>
---
 drivers/iommu/apple-dart.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
index e72a93e78e26ca61b233c83d439dbdfadf040fc6..bb48e8603d6c84bcf107294d851c2f2fc1273298 100644
--- a/drivers/iommu/apple-dart.c
+++ b/drivers/iommu/apple-dart.c
@@ -133,6 +133,7 @@
 #define DART_T8110_TCR                  0x1000
 #define DART_T8110_TCR_REMAP            GENMASK(11, 8)
 #define DART_T8110_TCR_REMAP_EN         BIT(7)
+#define DART_T8110_TCR_FOUR_LEVEL       BIT(3)
 #define DART_T8110_TCR_BYPASS_DAPF      BIT(2)
 #define DART_T8110_TCR_BYPASS_DART      BIT(1)
 #define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
@@ -177,6 +178,7 @@ struct apple_dart_hw {
 	u32 tcr_enabled;
 	u32 tcr_disabled;
 	u32 tcr_bypass;
+	u32 tcr_4level;
 
 	u32 ttbr;
 	u32 ttbr_valid;
@@ -217,6 +219,7 @@ struct apple_dart {
 	u32 pgsize;
 	u32 num_streams;
 	u32 supports_bypass : 1;
+	u32 four_level : 1;
 
 	struct iommu_group *sid2group[DART_MAX_STREAMS];
 	struct iommu_device iommu;
@@ -305,13 +308,16 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
 }
 
 static void
-apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
+apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
 {
 	struct apple_dart *dart = stream_map->dart;
 	int sid;
 
+	WARN_ON(levels != 3 && levels != 4);
+	WARN_ON(levels == 4 && !dart->four_level);
 	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
-		writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
+		writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw->tcr_4level : 0),
+		       dart->regs + DART_TCR(dart, sid));
 }
 
 static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
@@ -569,7 +575,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
 	for (; i < stream_map->dart->hw->ttbr_count; ++i)
 		apple_dart_hw_clear_ttbr(stream_map, i);
 
-	apple_dart_hw_enable_translation(stream_map);
+	apple_dart_hw_enable_translation(stream_map,
+					 pgtbl_cfg->apple_dart_cfg.n_levels);
 	stream_map->dart->hw->invalidate_tlb(stream_map);
 }
 
@@ -614,7 +621,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
 	dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
 	dart_domain->domain.geometry.aperture_start = 0;
 	dart_domain->domain.geometry.aperture_end =
-		(dma_addr_t)DMA_BIT_MASK(dart->ias);
+		(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
 	dart_domain->domain.geometry.force_aperture = true;
 
 	dart_domain->finalized = true;
@@ -807,6 +814,8 @@ static int apple_dart_of_xlate(struct device *dev,
 	if (cfg_dart) {
 		if (cfg_dart->pgsize != dart->pgsize)
 			return -EINVAL;
+		if (cfg_dart->ias != dart->ias)
+			return -EINVAL;
 	}
 
 	cfg->supports_bypass &= dart->supports_bypass;
@@ -1137,6 +1146,7 @@ static int apple_dart_probe(struct platform_device *pdev)
 		dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
 		dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
 		dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
+		dart->four_level = dart->ias > 36;
 		break;
 	}
 
@@ -1169,9 +1179,9 @@ static int apple_dart_probe(struct platform_device *pdev)
 
 	dev_info(
 		&pdev->dev,
-		"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n",
+		"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, AS %d -> %d] initialized\n",
 		dart->pgsize, dart->num_streams, dart->supports_bypass,
-		dart->pgsize > PAGE_SIZE);
+		dart->pgsize > PAGE_SIZE, dart->ias, dart->oas);
 	return 0;
 
 err_sysfs_remove:
@@ -1292,6 +1302,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
 	.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
 	.tcr_disabled = 0,
 	.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
+	.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
 
 	.ttbr = DART_T8110_TTBR,
 	.ttbr_valid = DART_T8110_TTBR_VALID,

-- 
2.50.1


^ permalink raw reply related	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] iommu: apple-dart: Add 4-level page table support
  2025-08-14  8:40 ` [PATCH 3/3] iommu: apple-dart: " Janne Grunau
@ 2025-08-16 13:50   ` Sven Peter
  2025-08-16 14:19     ` Janne Grunau
  0 siblings, 1 reply; 9+ messages in thread
From: Sven Peter @ 2025-08-16 13:50 UTC (permalink / raw)
  To: Janne Grunau, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Hector Martin

On 14.08.25 10:40, Janne Grunau wrote:
> From: Hector Martin <marcan@marcan.st>
> 
> The T8110 variant DART implementation on T602x SoCs indicates an IAS of
> 42, which requires an extra page table level. The extra level is
> optional, but let's implement it.
> 
> Since the driver failed at IO page table creation with 42-bit IAS add
> "apple,t6020-dart" as separate compatible using the T8110 HW data.

Is the commit description outdated? I don't see this change anywhere.

> 
> Later it might be useful to restrict this based on the actual attached
> devices, since most won't need that much address space anyway.
> 
> Signed-off-by: Hector Martin <marcan@marcan.st>
> Signed-off-by: Janne Grunau <j@jannau.net>
> ---
>   drivers/iommu/apple-dart.c | 23 +++++++++++++++++------
>   1 file changed, 17 insertions(+), 6 deletions(-)
> 
> diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
> index e72a93e78e26ca61b233c83d439dbdfadf040fc6..bb48e8603d6c84bcf107294d851c2f2fc1273298 100644
> --- a/drivers/iommu/apple-dart.c
> +++ b/drivers/iommu/apple-dart.c
> @@ -133,6 +133,7 @@
>   #define DART_T8110_TCR                  0x1000
>   #define DART_T8110_TCR_REMAP            GENMASK(11, 8)
>   #define DART_T8110_TCR_REMAP_EN         BIT(7)
> +#define DART_T8110_TCR_FOUR_LEVEL       BIT(3)
>   #define DART_T8110_TCR_BYPASS_DAPF      BIT(2)
>   #define DART_T8110_TCR_BYPASS_DART      BIT(1)
>   #define DART_T8110_TCR_TRANSLATE_ENABLE BIT(0)
> @@ -177,6 +178,7 @@ struct apple_dart_hw {
>   	u32 tcr_enabled;
>   	u32 tcr_disabled;
>   	u32 tcr_bypass;
> +	u32 tcr_4level;
>   
>   	u32 ttbr;
>   	u32 ttbr_valid;
> @@ -217,6 +219,7 @@ struct apple_dart {
>   	u32 pgsize;
>   	u32 num_streams;
>   	u32 supports_bypass : 1;
> +	u32 four_level : 1;
>   
>   	struct iommu_group *sid2group[DART_MAX_STREAMS];
>   	struct iommu_device iommu;
> @@ -305,13 +308,16 @@ static struct apple_dart_domain *to_dart_domain(struct iommu_domain *dom)
>   }
>   
>   static void
> -apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map)
> +apple_dart_hw_enable_translation(struct apple_dart_stream_map *stream_map, int levels)
>   {
>   	struct apple_dart *dart = stream_map->dart;
>   	int sid;
>   
> +	WARN_ON(levels != 3 && levels != 4);
> +	WARN_ON(levels == 4 && !dart->four_level);
>   	for_each_set_bit(sid, stream_map->sidmap, dart->num_streams)
> -		writel(dart->hw->tcr_enabled, dart->regs + DART_TCR(dart, sid));
> +		writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw->tcr_4level : 0),
> +		       dart->regs + DART_TCR(dart, sid));

This is a bit hard to read, I'd prefer an explicit
if (dart->hw->tcr_4level) here.

>   }
>   
>   static void apple_dart_hw_disable_dma(struct apple_dart_stream_map *stream_map)
> @@ -569,7 +575,8 @@ apple_dart_setup_translation(struct apple_dart_domain *domain,
>   	for (; i < stream_map->dart->hw->ttbr_count; ++i)
>   		apple_dart_hw_clear_ttbr(stream_map, i);
>   
> -	apple_dart_hw_enable_translation(stream_map);
> +	apple_dart_hw_enable_translation(stream_map,
> +					 pgtbl_cfg->apple_dart_cfg.n_levels);
>   	stream_map->dart->hw->invalidate_tlb(stream_map);
>   }
>   
> @@ -614,7 +621,7 @@ static int apple_dart_finalize_domain(struct apple_dart_domain *dart_domain,
>   	dart_domain->domain.pgsize_bitmap = pgtbl_cfg.pgsize_bitmap;
>   	dart_domain->domain.geometry.aperture_start = 0;
>   	dart_domain->domain.geometry.aperture_end =
> -		(dma_addr_t)DMA_BIT_MASK(dart->ias);
> +		(dma_addr_t)DMA_BIT_MASK(pgtbl_cfg.ias);
>   	dart_domain->domain.geometry.force_aperture = true;
>   
>   	dart_domain->finalized = true;
> @@ -807,6 +814,8 @@ static int apple_dart_of_xlate(struct device *dev,
>   	if (cfg_dart) {
>   		if (cfg_dart->pgsize != dart->pgsize)
>   			return -EINVAL;
> +		if (cfg_dart->ias != dart->ias)
> +			return -EINVAL;
>   	}
>   
>   	cfg->supports_bypass &= dart->supports_bypass;
> @@ -1137,6 +1146,7 @@ static int apple_dart_probe(struct platform_device *pdev)
>   		dart->ias = FIELD_GET(DART_T8110_PARAMS3_VA_WIDTH, dart_params[2]);
>   		dart->oas = FIELD_GET(DART_T8110_PARAMS3_PA_WIDTH, dart_params[2]);
>   		dart->num_streams = FIELD_GET(DART_T8110_PARAMS4_NUM_SIDS, dart_params[3]);
> +		dart->four_level = dart->ias > 36;
>   		break;
>   	}
>   
> @@ -1169,9 +1179,9 @@ static int apple_dart_probe(struct platform_device *pdev)
>   
>   	dev_info(
>   		&pdev->dev,
> -		"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d] initialized\n",
> +		"DART [pagesize %x, %d streams, bypass support: %d, bypass forced: %d, AS %d -> %d] initialized\n",
>   		dart->pgsize, dart->num_streams, dart->supports_bypass,
> -		dart->pgsize > PAGE_SIZE);
> +		dart->pgsize > PAGE_SIZE, dart->ias, dart->oas);
>   	return 0;
>   
>   err_sysfs_remove:
> @@ -1292,6 +1302,7 @@ static const struct apple_dart_hw apple_dart_hw_t8110 = {
>   	.tcr_enabled = DART_T8110_TCR_TRANSLATE_ENABLE,
>   	.tcr_disabled = 0,
>   	.tcr_bypass = DART_T8110_TCR_BYPASS_DAPF | DART_T8110_TCR_BYPASS_DART,
> +	.tcr_4level = DART_T8110_TCR_FOUR_LEVEL,
>   
>   	.ttbr = DART_T8110_TTBR,
>   	.ttbr_valid = DART_T8110_TTBR_VALID,
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s
  2025-08-14  8:40 ` [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s Janne Grunau
@ 2025-08-16 13:51   ` Sven Peter
  0 siblings, 0 replies; 9+ messages in thread
From: Sven Peter @ 2025-08-16 13:51 UTC (permalink / raw)
  To: Janne Grunau, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Hector Martin

On 14.08.25 10:40, Janne Grunau wrote:
> From: Hector Martin <marcan@marcan.st>
> 
> The registers are 32-bit and the offsets definitely don't need 64 bits
> either, these should've been u32s.
> 
> Signed-off-by: Hector Martin <marcan@marcan.st>
> Signed-off-by: Janne Grunau <j@jannau.net>
> ---

The commit description should start with iommu/apple-dart to keep 
consistent with the subsystem style. With that:

Reviewed-by: Sven Peter <sven@kernel.org>



Thanks,

Sven


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support
  2025-08-14  8:40 ` [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support Janne Grunau
@ 2025-08-16 14:02   ` Sven Peter
  0 siblings, 0 replies; 9+ messages in thread
From: Sven Peter @ 2025-08-16 14:02 UTC (permalink / raw)
  To: Janne Grunau, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, linux-kernel, Hector Martin

On 14.08.25 10:40, Janne Grunau wrote:
> From: Hector Martin <marcan@marcan.st>
> 
> DARTs on t602x SoCs are of the t8110 variant but have an IAS of 42,
> which means optional support for an extra page table level.
> 
> Refactor the PTE management to support an arbitrary level count, and
> then calculate how many levels we need for any given configuration.
> 
> Signed-off-by: Hector Martin <marcan@marcan.st>
> Signed-off-by: Janne Grunau <j@jannau.net>
> ---

Same comment like for the previous patch about the commit description
but otherwise this looks good to me. With that changed:

Reviewed-by: Sven Peter <sven@kernel.org>


Thanks,


Sven


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] iommu: apple-dart: Add 4-level page table support
  2025-08-16 13:50   ` Sven Peter
@ 2025-08-16 14:19     ` Janne Grunau
  2025-08-16 15:26       ` Sven Peter
  0 siblings, 1 reply; 9+ messages in thread
From: Janne Grunau @ 2025-08-16 14:19 UTC (permalink / raw)
  To: Sven Peter, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, LKML, Hector Martin

Hej,

On Sat, Aug 16, 2025, at 15:50, Sven Peter wrote:
> On 14.08.25 10:40, Janne Grunau wrote:
>> From: Hector Martin <marcan@marcan.st>
>>
>> The T8110 variant DART implementation on T602x SoCs indicates an IAS
>> of 42, which requires an extra page table level. The extra level is
>> optional, but let's implement it.
>>
>> Since the driver failed at IO page table creation with 42-bit IAS add
>> "apple,t6020-dart" as separate compatible using the T8110 HW data.
>
> Is the commit description outdated? I don't see this change anywhere.

yes, I decided to handle this as missing feature / bug. Both end up with
the same result and as far as we can tell it is fully compatible.
Removed locally.

>> Later it might be useful to restrict this based on the actual
>> attached devices, since most won't need that much address space
>> anyway.
>>
>> Signed-off-by: Hector Martin <marcan@marcan.st> Signed-off-by: Janne
>> Grunau <j@jannau.net>
>> ---
>>   drivers/iommu/apple-dart.c | 23 +++++++++++++++++------ 1 file
>>   changed, 17 insertions(+), 6 deletions(-)
>>
>> diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
>> index e72a93e78e26ca61b233c83d439dbdfadf040fc6..bb48e8603d6c84bcf107-
>> 294d851c2f2fc1273298 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-
>> dart.c @@ -133,6 +133,7 @@  #define DART_T8110_TCR
>> 0x1000  #define DART_T8110_TCR_REMAP            GENMASK(11, 8)
>> #define DART_T8110_TCR_REMAP_EN         BIT(7) +#define
>> DART_T8110_TCR_FOUR_LEVEL       BIT(3)  #define
>> DART_T8110_TCR_BYPASS_DAPF      BIT(2)  #define
>> DART_T8110_TCR_BYPASS_DART      BIT(1)  #define
>> DART_T8110_TCR_TRANSLATE_ENABLE BIT(0) @@ -177,6 +178,7 @@ struct
>> apple_dart_hw {     u32 tcr_enabled;     u32 tcr_disabled;     u32
>> tcr_bypass;
>> +    u32 tcr_4level;
>>
>>      u32 ttbr; u32 ttbr_valid; @@ -217,6 +219,7 @@ struct apple_dart
>>      { u32 pgsize; u32 num_streams; u32 supports_bypass : 1;
>> +    u32 four_level : 1;
>>
>>      struct iommu_group *sid2group[DART_MAX_STREAMS]; struct
>>      iommu_device iommu; @@ -305,13 +308,16 @@ static struct
>>      apple_dart_domain *to_dart_domain(struct iommu_domain *dom) }
>>
>>   static void -apple_dart_hw_enable_translation(struct
>>   apple_dart_stream_map *stream_map)
>>   +apple_dart_hw_enable_translation(struct apple_dart_stream_map
>>   *stream_map, int levels) {   struct apple_dart *dart = stream_map-
>>   >dart;   int sid;
>>
>> +    WARN_ON(levels != 3 && levels != 4);
>> +    WARN_ON(levels == 4 && !dart->four_level); for_each_set_bit(sid,
>>      stream_map->sidmap, dart->num_streams)
>> -            writel(dart->hw->tcr_enabled, dart->regs +
>>              DART_TCR(dart, sid));
>> +            writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw-
>>              >tcr_4level : 0),
>> +                   dart->regs + DART_TCR(dart, sid));
>
> This is a bit hard to read, I'd prefer an explicit if (dart->hw-
> >tcr_4level) here.

you mean `if (levels == 4)`? `dart->hw->tcr_4level` will be `BIT(3)` for
t8110 darts even when they use just 3 page table levels.

Changed locally to

u32 tcr = dart->hw->tcr_enabled; if (levels == 4)        tcr |= dart->hw-
>tcr_4level;

and then writel(tcr, ...) in the loop.

I've change prefix of all commits in this series to "iommu/apple-dart"
and "iommu/io-pgtable-dart".

thanks,
Janne

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] iommu: apple-dart: Add 4-level page table support
  2025-08-16 14:19     ` Janne Grunau
@ 2025-08-16 15:26       ` Sven Peter
  0 siblings, 0 replies; 9+ messages in thread
From: Sven Peter @ 2025-08-16 15:26 UTC (permalink / raw)
  To: Janne Grunau, Alyssa Rosenzweig, Neal Gompa, Joerg Roedel,
	Will Deacon, Robin Murphy
  Cc: asahi, linux-arm-kernel, iommu, LKML, Hector Martin

On 16.08.25 16:19, Janne Grunau wrote:
> Hej,
> 
> On Sat, Aug 16, 2025, at 15:50, Sven Peter wrote:
>> On 14.08.25 10:40, Janne Grunau wrote:
>>> From: Hector Martin <marcan@marcan.st>
>>>
>>> The T8110 variant DART implementation on T602x SoCs indicates an IAS
>>> of 42, which requires an extra page table level. The extra level is
>>> optional, but let's implement it.
>>>
>>> Since the driver failed at IO page table creation with 42-bit IAS add
>>> "apple,t6020-dart" as separate compatible using the T8110 HW data.
>>
>> Is the commit description outdated? I don't see this change anywhere.
> 
> yes, I decided to handle this as missing feature / bug. Both end up with
> the same result and as far as we can tell it is fully compatible.
> Removed locally.
> 
>>> Later it might be useful to restrict this based on the actual
>>> attached devices, since most won't need that much address space
>>> anyway.
>>>
>>> Signed-off-by: Hector Martin <marcan@marcan.st> Signed-off-by: Janne
>>> Grunau <j@jannau.net>
>>> ---
>>>    drivers/iommu/apple-dart.c | 23 +++++++++++++++++------ 1 file
>>>    changed, 17 insertions(+), 6 deletions(-)
>>>
>>> diff --git a/drivers/iommu/apple-dart.c b/drivers/iommu/apple-dart.c
>>> index e72a93e78e26ca61b233c83d439dbdfadf040fc6..bb48e8603d6c84bcf107-
>>> 294d851c2f2fc1273298 100644 --- a/drivers/iommu/apple-dart.c +++ b/drivers/iommu/apple-
>>> dart.c @@ -133,6 +133,7 @@  #define DART_T8110_TCR
>>> 0x1000  #define DART_T8110_TCR_REMAP            GENMASK(11, 8)
>>> #define DART_T8110_TCR_REMAP_EN         BIT(7) +#define
>>> DART_T8110_TCR_FOUR_LEVEL       BIT(3)  #define
>>> DART_T8110_TCR_BYPASS_DAPF      BIT(2)  #define
>>> DART_T8110_TCR_BYPASS_DART      BIT(1)  #define
>>> DART_T8110_TCR_TRANSLATE_ENABLE BIT(0) @@ -177,6 +178,7 @@ struct
>>> apple_dart_hw {     u32 tcr_enabled;     u32 tcr_disabled;     u32
>>> tcr_bypass;
>>> +    u32 tcr_4level;
>>>
>>>       u32 ttbr; u32 ttbr_valid; @@ -217,6 +219,7 @@ struct apple_dart
>>>       { u32 pgsize; u32 num_streams; u32 supports_bypass : 1;
>>> +    u32 four_level : 1;
>>>
>>>       struct iommu_group *sid2group[DART_MAX_STREAMS]; struct
>>>       iommu_device iommu; @@ -305,13 +308,16 @@ static struct
>>>       apple_dart_domain *to_dart_domain(struct iommu_domain *dom) }
>>>
>>>    static void -apple_dart_hw_enable_translation(struct
>>>    apple_dart_stream_map *stream_map)
>>>    +apple_dart_hw_enable_translation(struct apple_dart_stream_map
>>>    *stream_map, int levels) {   struct apple_dart *dart = stream_map-
>>>    >dart;   int sid;
>>>
>>> +    WARN_ON(levels != 3 && levels != 4);
>>> +    WARN_ON(levels == 4 && !dart->four_level); for_each_set_bit(sid,
>>>       stream_map->sidmap, dart->num_streams)
>>> -            writel(dart->hw->tcr_enabled, dart->regs +
>>>               DART_TCR(dart, sid));
>>> +            writel(dart->hw->tcr_enabled | (levels == 4 ? dart->hw-
>>>               >tcr_4level : 0),
>>> +                   dart->regs + DART_TCR(dart, sid));
>>
>> This is a bit hard to read, I'd prefer an explicit if (dart->hw-
>>> tcr_4level) here.
> 
> you mean `if (levels == 4)`? `dart->hw->tcr_4level` will be `BIT(3)` for
> t8110 darts even when they use just 3 page table levels.

yup, I must've copy/pasted the wrong thing.

> 
> Changed locally to
> 
> u32 tcr = dart->hw->tcr_enabled; if (levels == 4)        tcr |= dart->hw-
>> tcr_4level;
> 
> and then writel(tcr, ...) in the loop.
Great, I didn't even realize you could move that entire thing out of the 
loop.

> I've change prefix of all commits in this series to "iommu/apple-dart"
> and "iommu/io-pgtable-dart".

Feel free to add my Reviewed-by for this commit as well then.



Thanks,

Sven


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2025-08-16 15:26 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-08-14  8:40 [PATCH 0/3] iommu: apple-dart: Four level page table support Janne Grunau
2025-08-14  8:40 ` [PATCH 1/3] iommu: apple-dart: Make the hw register fields u32s Janne Grunau
2025-08-16 13:51   ` Sven Peter
2025-08-14  8:40 ` [PATCH 2/3] iommu: io-pgtable: Add 4-level page table support Janne Grunau
2025-08-16 14:02   ` Sven Peter
2025-08-14  8:40 ` [PATCH 3/3] iommu: apple-dart: " Janne Grunau
2025-08-16 13:50   ` Sven Peter
2025-08-16 14:19     ` Janne Grunau
2025-08-16 15:26       ` Sven Peter

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).