Re: [PATCH v2 4/5] iommu: Add Broadcom BCM2712 IOMMU driver

From: Robin Murphy

Date: Tue Jul 28 2026 - 06:59:39 EST


On 27/07/2026 9:43 pm, Daniel Drake wrote:
[...]
+ * Each BCM2712 IOMMU has multiple devices hardwired into it, whose
+ * DMA transactions all route through the IOMMU. There is no stream ID tagging
+ * or any other kind of segmentation to differentiate between requests from
+ * different devices. It is also not possible to toggle a specific device
+ * between iommu-mapped and bypass modes.

Hmm, so it's kind of like an IOMMU and a GART had a baby?

+ * With these limitations in mind, we configure the hardware to operate over two
+ * windows:
+ * 1. The lower part of the address space operates in identity/bypass mode.
+ * This enables non-IOMMU-consumer devices to work as normal (including
+ * devices set up by the firmware, devices that don't require large DMA
+ * allocations, devices that handle scatter-gather natively, etc.)
+ * 2. A 4GB translation aperture is defined at a fixed, high address, beyond
+ * regular RAM and MMIO space. Mappings are operated in this aperture for
+ * devices that wish to take advantage of the IOMMU.
[...]
+static struct iommu_domain *bcm2712_iommu_domain_alloc(struct device *dev)
+{
+ struct bcm2712_iommu *mmu = dev_iommu_priv_get(dev);
+ struct bcm2712_iommu_domain *domain;
+ struct pt_iommu_bcm2712_cfg cfg;
+ int ret;
+
+ domain = kzalloc_obj(*domain);
+ if (!domain)
+ return NULL;
+
+ domain->mmu = mmu;
+ domain->pt.iommu.iommu_device = mmu->dev;
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.common.features = BIT(PT_FEAT_DMA_INCOHERENT);
+
+ /* Bigpage and superpage sizes are typically 64K and 1M, but may vary */
+ if (mmu->bigpage_size)
+ cfg.bigpage_lg2 = ilog2(mmu->bigpage_size);
+ if (mmu->superpage_size)
+ cfg.superpage_lg2 = ilog2(mmu->superpage_size);
+
+ /* 2-level format: 10-bit L1 + 10-bit L2 + 12-bit page offset */
+ cfg.common.hw_max_vasz_lg2 =
+ (2 * PTES_PER_IOPG_SHIFT) + IOMMU_PAGE_SHIFT;
+
+ /* PTEs encode a 28-bit output address PFN */
+ cfg.common.hw_max_oasz_lg2 = 28 + IOMMU_PAGE_SHIFT;
+
+ ret = pt_iommu_bcm2712_init(&domain->pt, &cfg, GFP_KERNEL);
+ if (ret)
+ goto err;
+
+ /* Set up a default (error) page used to catch illegal reads/writes */
+ domain->default_page = iommu_alloc_pages_sz(GFP_KERNEL, PAGE_SIZE);
+ if (!domain->default_page)
+ goto err;
+
+ domain->base.geometry.aperture_start = BCM2712_APERTURE_BASE;
+ domain->base.geometry.aperture_end = BCM2712_APERTURE_END - 1;
+ domain->base.geometry.force_aperture = true;

...and thus (as things stand) this is a lie :(

If you want to operate like an IOMMU, then the translation aperture and the bypass window should really be mutually-exclusive; conversely if you want to operate like a GART then you can't really pretend to support blocking domains which will also disrupt devices outside the IOMMU group. Trying to compromise leaves you with rather a worst-of-both-worlds setup as-is...

Thanks,
Robin.

+ domain->base.ops = &bcm2712_paging_domain_ops;
+ return &domain->base;
+
+err:
+ bcm2712_iommu_domain_free(&domain->base);
+ return NULL;
+}