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
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, >
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
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
© 2016 - 2025 Red Hat, Inc.