Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
From: Florian Fainelli <florian.fainelli@broadcom.com>
To: Daniel Drake <dan@reactivated.net>,
	"Joerg Roedel (AMD)" <joro@8bytes.org>,
	Will Deacon <will@kernel.org>,
	Robin Murphy <robin.murphy@arm.com>,
	Rob Herring <robh@kernel.org>,
	Krzysztof Kozlowski <krzk+dt@kernel.org>,
	Conor Dooley <conor+dt@kernel.org>,
	Broadcom internal kernel review list
	<bcm-kernel-feedback-list@broadcom.com>
Cc: iommu@lists.linux.dev, linux-kernel@vger.kernel.org,
	devicetree@vger.kernel.org, linux-rpi-kernel@lists.infradead.org,
	linux-arm-kernel@lists.infradead.org,
	nick.hollinghurst@raspberrypi.com, james.quinlan@broadcom.com,
	Jason Gunthorpe <jgg@ziepe.ca>
Subject: Re: [PATCH v3 4/5] iommu: Add Broadcom BCM2712 IOMMU driver
Date: Wed, 26 Aug 2026 11:33:49 -0700	[thread overview]
Message-ID: <635282ef-5c24-4820-abfa-7eaaea6e7f0e@broadcom.com> (raw)
In-Reply-To: <20260825-bcm2712-iommu-submit-v3-4-7f143e7289b6@reactivated.net>

On 8/25/26 13:56, Daniel Drake wrote:
> This IOMMU translates memory access requests for the VC6 display
> pipeline and various multimedia devices in the Broadcom BCM2712 SoC used
> on Raspberry Pi 5.
> 
> The driver uses the generic_pt framework to manage the 2-level page
> tables. It also provides support for the centralized L2 TLB (IOMMUC),
> which is shared across the SoC's IOMMU instances and must be flushed
> when modifying or unmapping page table entries.
> 
> Adapted from Raspberry Pi's downstream bcm2712-iommu driver
> (original author Nick Hollinghurst).
> 
> Signed-off-by: Daniel Drake <dan@reactivated.net>
> ---
>   drivers/iommu/Kconfig               |  15 +
>   drivers/iommu/Makefile              |   1 +
>   drivers/iommu/bcm2712-iommu-cache.c |  83 ++++++
>   drivers/iommu/bcm2712-iommu-cache.h |   9 +
>   drivers/iommu/bcm2712-iommu.c       | 556 ++++++++++++++++++++++++++++++++++++
>   5 files changed, 664 insertions(+)
> 
> diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
> index 6e07bd69467a..f2c8788158b0 100644
> --- a/drivers/iommu/Kconfig
> +++ b/drivers/iommu/Kconfig
> @@ -386,6 +386,21 @@ config VSI_IOMMU
>   	  Say Y here if you want to use this IOMMU in front of these
>   	  hardware blocks.
>   
> +config BCM2712_IOMMU
> +	bool "BCM2712 IOMMU driver"
> +	depends on (ARCH_BCM && ARM64) || COMPILE_TEST
> +	select IOMMU_API
> +	select GENERIC_PT
> +	select IOMMU_PT
> +	select IOMMU_PT_BCM2712
> +	help
> +	  Support for IOMMU on BCM2712 SoC. This IOMMU can be used by the
> +	  display controller and various multimedia devices to perform
> +	  efficient memory management.
> +
> +	  Say Y here if you want to use this IOMMU in front of these
> +	  hardware blocks.
> +
>   config IOMMU_DEBUG_PAGEALLOC
>   	bool "Debug IOMMU mappings against page allocations"
>   	depends on DEBUG_PAGEALLOC && IOMMU_API && PAGE_EXTENSION
> diff --git a/drivers/iommu/Makefile b/drivers/iommu/Makefile
> index 2f05725eaab1..29a26d2a3af1 100644
> --- a/drivers/iommu/Makefile
> +++ b/drivers/iommu/Makefile
> @@ -37,4 +37,5 @@ obj-$(CONFIG_IOMMU_IOPF) += io-pgfault.o
>   obj-$(CONFIG_SPRD_IOMMU) += sprd-iommu.o
>   obj-$(CONFIG_APPLE_DART) += apple-dart.o
>   obj-$(CONFIG_VSI_IOMMU) += vsi-iommu.o
> +obj-$(CONFIG_BCM2712_IOMMU) += bcm2712-iommu.o bcm2712-iommu-cache.o
>   obj-$(CONFIG_IOMMU_DEBUG_PAGEALLOC) += iommu-debug-pagealloc.o
> diff --git a/drivers/iommu/bcm2712-iommu-cache.c b/drivers/iommu/bcm2712-iommu-cache.c
> new file mode 100644
> index 000000000000..040cfc4ccf9f
> --- /dev/null
> +++ b/drivers/iommu/bcm2712-iommu-cache.c
> @@ -0,0 +1,83 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * IOMMU driver for BCM2712 TLB cache
> + *
> + * Copyright (c) 2023 Raspberry Pi Ltd.
> + * Copyright (c) 2026 Daniel Drake
> + *
> + * The BCM2712 IOMMUC is a centralized TLB which accelerates address translation
> + * across the SoC's IOMMU devices. If an address mapping is not found in the
> + * IOMMU's local TLB cache, then this IOMMUC is consulted. The IOMMUC must be
> + * explicitly invalidated when modifying or unmapping IOMMU page tables.
> + */
> +
> +#include <linux/cleanup.h>
> +#include <linux/err.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/iopoll.h>
> +
> +#include "bcm2712-iommu-cache.h"
> +
> +struct bcm2712_iommu_cache {
> +	struct device *dev;
> +	spinlock_t hw_lock;
> +	void __iomem *reg_base;
> +};
> +
> +#define MMUC_CONTROL_ENABLE   1
> +#define MMUC_CONTROL_FLUSH    2
> +#define MMUC_CONTROL_FLUSHING 4

Those should be BIT(0), BIT(1) and BIT(2) respectively.

> +
> +void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache)
> +{
> +	u32 val;
> +	int ret;
> +
> +	scoped_guard(spinlock_irqsave, &cache->hw_lock) {
> +		writel(MMUC_CONTROL_ENABLE | MMUC_CONTROL_FLUSH,
> +		       cache->reg_base);
> +
> +		ret = readl_poll_timeout_atomic(cache->reg_base, val,
> +						!(val & MMUC_CONTROL_FLUSHING),
> +						0, 50);
> +	}
> +
> +	if (ret)
> +		dev_err_ratelimited(cache->dev, "cache flush timed out\n");
> +}
> +
> +static int bcm2712_iommu_cache_probe(struct platform_device *pdev)
> +{
> +	struct bcm2712_iommu_cache *cache;
> +
> +	cache = devm_kzalloc(&pdev->dev, sizeof(*cache), GFP_KERNEL);
> +	if (!cache)
> +		return -ENOMEM;
> +
> +	cache->dev = &pdev->dev;
> +	spin_lock_init(&cache->hw_lock);
> +
> +	cache->reg_base = devm_platform_ioremap_resource(pdev, 0);
> +	if (IS_ERR(cache->reg_base))
> +		return PTR_ERR(cache->reg_base);
> +
> +	platform_set_drvdata(pdev, cache);
> +	return 0;
> +}
> +
> +static const struct of_device_id bcm2712_iommu_cache_of_match[] = {
> +	{ .compatible = "brcm,bcm2712-iommuc" },
> +	{ /* sentinel */ },
> +};
> +
> +static struct platform_driver bcm2712_iommu_cache_driver = {
> +	.probe = bcm2712_iommu_cache_probe,
> +	.driver = {
> +		.name = "bcm2712-iommu-cache",
> +		.of_match_table = bcm2712_iommu_cache_of_match,
> +		.suppress_bind_attrs = true,
> +	},
> +};
> +builtin_platform_driver(bcm2712_iommu_cache_driver);
> diff --git a/drivers/iommu/bcm2712-iommu-cache.h b/drivers/iommu/bcm2712-iommu-cache.h
> new file mode 100644
> index 000000000000..d2f7851831cc
> --- /dev/null
> +++ b/drivers/iommu/bcm2712-iommu-cache.h
> @@ -0,0 +1,9 @@
> +/* SPDX-License-Identifier: GPL-2.0-only */
> +#ifndef _BCM2712_IOMMU_CACHE_H
> +#define _BCM2712_IOMMU_CACHE_H
> +
> +struct bcm2712_iommu_cache;
> +
> +void bcm2712_iommu_cache_flush(struct bcm2712_iommu_cache *cache);
> +
> +#endif
> diff --git a/drivers/iommu/bcm2712-iommu.c b/drivers/iommu/bcm2712-iommu.c
> new file mode 100644
> index 000000000000..1bb456a83df5
> --- /dev/null
> +++ b/drivers/iommu/bcm2712-iommu.c
> @@ -0,0 +1,556 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + * IOMMU driver for Broadcom BCM2712
> + *
> + * Copyright (c) 2023-2025 Raspberry Pi Ltd.
> + * Copyright (c) 2026 Daniel Drake
> + *
> + * 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.
> + *
> + * The hardware supports the simultaneous configuration of a bypass window
> + * (where memory accesses operate in identity mode) and a translation aperture
> + * (supporting page mapping). While combining these two would allow for
> + * GART-like operation, this driver's paging domain implementation configures
> + * only the translation aperture (starting at IOVA 0) offering a degree of
> + * memory protection.
> + *
> + * The page table format is a two-level format handled by generic_pt/bcm2712.
> + */
> +
> +#include <linux/bitfield.h>
> +#include <linux/cleanup.h>
> +#include <linux/dma-mapping.h>
> +#include <linux/err.h>
> +#include <linux/iommu.h>
> +#include <linux/iopoll.h>
> +#include <linux/of_platform.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/sizes.h>
> +#include <linux/generic_pt/iommu.h>
> +
> +#include "bcm2712-iommu-cache.h"
> +#include "dma-iommu.h"
> +#include "iommu-pages.h"
> +
> +/* BCM2712 IOMMU is organized around 4Kbyte pages */
> +#define IOMMU_PAGE_SHIFT       12
> +#define IOMMU_PAGE_SIZE        (1ul << IOMMU_PAGE_SHIFT)
> +/* A PTE is 4 bytes */
> +#define PTE_SIZE_SHIFT         2
> +/* L1/L2 table sizing (IOMMU hardware pages): 1024 entries per page */
> +#define PTES_PER_IOPG_SHIFT    (IOMMU_PAGE_SHIFT - PTE_SIZE_SHIFT)
> +
> +#define MMMU_CTRL_OFFSET                       0x00
> +#define MMMU_CTRL_CAP_EXCEEDED                 BIT(27)
> +#define MMMU_CTRL_CAP_EXCEEDED_ABORT_EN        BIT(26)
> +#define MMMU_CTRL_CAP_EXCEEDED_INT_EN          BIT(25)
> +#define MMMU_CTRL_CAP_EXCEEDED_EXCEPTION_EN    BIT(24)
> +#define MMMU_CTRL_PT_INVALID                   BIT(20)
> +#define MMMU_CTRL_PT_INVALID_ABORT_EN          BIT(19)
> +#define MMMU_CTRL_PT_INVALID_INT_EN            BIT(18)
> +#define MMMU_CTRL_PT_INVALID_EXCEPTION_EN      BIT(17)
> +#define MMMU_CTRL_PT_INVALID_EN                BIT(16)
> +#define MMMU_CTRL_WRITE_VIOLATION              BIT(12)
> +#define MMMU_CTRL_WRITE_VIOLATION_ABORT_EN     BIT(11)
> +#define MMMU_CTRL_WRITE_VIOLATION_INT_EN       BIT(10)
> +#define MMMU_CTRL_WRITE_VIOLATION_EXCEPTION_EN BIT(9)
> +#define MMMU_CTRL_BYPASS                       BIT(8)
> +#define MMMU_CTRL_TLB_CLEARING                 BIT(7)
> +#define MMMU_CTRL_STATS_CLEAR                  BIT(3)
> +#define MMMU_CTRL_TLB_CLEAR                    BIT(2)
> +#define MMMU_CTRL_STATS_ENABLE                 BIT(1)
> +#define MMMU_CTRL_ENABLE                       BIT(0)
> +
> +#define MMMU_CTRL_OPERATING_FLAGS (\
> +	MMMU_CTRL_CAP_EXCEEDED_ABORT_EN    | \
> +	MMMU_CTRL_PT_INVALID_ABORT_EN      | \
> +	MMMU_CTRL_PT_INVALID_EN            | \
> +	MMMU_CTRL_WRITE_VIOLATION_ABORT_EN | \
> +	MMMU_CTRL_STATS_ENABLE             | \
> +	MMMU_CTRL_ENABLE)
> +
> +#define MMMU_PT_PA_BASE_OFFSET                 0x04
> +
> +#define MMMU_ADDR_CAP_OFFSET                   0x14
> +#define MMMU_ADDR_CAP_ENABLE                   BIT(31)
> +#define ADDR_CAP_SHIFT                         ilog2(SZ_256M)
> +
> +#define MMMU_SHOOT_DOWN_OFFSET                 0x18
> +#define MMMU_SHOOT_DOWN_SHOOTING               BIT(31)
> +#define MMMU_SHOOT_DOWN_SHOOT                  BIT(30)
> +
> +#define MMMU_BYPASS_START_OFFSET               0x1c
> +#define MMMU_BYPASS_START_ENABLE               BIT(31)
> +
> +#define MMMU_BYPASS_END_OFFSET                 0x20
> +#define MMMU_BYPASS_END_ENABLE                 BIT(31)
> +
> +#define MMMU_MISC_OFFSET                       0x24
> +#define MMMU_MISC_SINGLE_TABLE                 BIT(31)
> +
> +#define MMMU_ILLEGAL_ADR_OFFSET                0x30
> +#define MMMU_ILLEGAL_ADR_ENABLE                BIT(31)
> +
> +#define MMMU_DEBUG_INFO_OFFSET                 0x38
> +#define MMMU_DEBUG_INFO_VERSION_MASK           0x0000000Fu
> +#define MMMU_DEBUG_INFO_VA_WIDTH_MASK          0x000000F0u
> +#define MMMU_DEBUG_INFO_PA_WIDTH_MASK          0x00000F00u
> +#define MMMU_DEBUG_INFO_BIGPAGE_WIDTH_MASK     0x000FF000u
> +#define MMMU_DEBUG_INFO_SUPERPAGE_WIDTH_MASK   0x0FF00000u
> +#define MMMU_DEBUG_INFO_BYPASS_4M              BIT(28)
> +#define MMMU_DEBUG_INFO_BYPASS                 BIT(29)
> +
> +struct bcm2712_iommu {
> +	struct device *dev;
> +	struct iommu_device iommu;
> +	struct bcm2712_iommu_domain *domain;
> +	struct bcm2712_iommu_cache *cache;
> +	void __iomem *reg_base;
> +	spinlock_t hw_lock;
> +	size_t bigpage_size;
> +	size_t superpage_size;
> +};
> +
> +struct bcm2712_iommu_domain {
> +	union {
> +		struct iommu_domain base;
> +		struct pt_iommu_bcm2712 pt;
> +	};
> +	struct bcm2712_iommu *mmu;
> +	void *default_page;
> +};
> +
> +#define MMU_WR(off, val)  writel(val, mmu->reg_base + (off))
> +#define MMU_RD(off)       readl(mmu->reg_base + (off))

I would prefer using static inline wrappers here because it gets super 
easy to just instrument those with debug prints by adding a couple of 
lines, it also gives you type validation at the same time.

[snip]

> +static struct iommu_domain bcm2712_blocking_domain = {
> +	.type = IOMMU_DOMAIN_BLOCKED,
> +	.ops = &(const struct iommu_domain_ops) {
> +		.attach_dev = bcm2712_iommu_blocking_attach,
> +	},
> +};
> +
> +static int bcm2712_iommu_enable_and_clear_tlb(struct bcm2712_iommu *mmu)

Maybe add __must_hold() here to indicate when this is called?

The rest looks good to me, but I defer to Jim for the functional review.
-- 
Florian


  parent reply	other threads:[~2026-08-26 18:34 UTC|newest]

Thread overview: 12+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-25 20:56 [PATCH v3 0/5] Add support for Broadcom BCM2712 IOMMU driver (Raspberry Pi 5) Daniel Drake
2026-08-25 20:56 ` [PATCH v3 1/5] iommu_pt: Fix test_pgsize_boundary() failure on narrow-OA formats Daniel Drake
2026-08-26 18:18   ` Jason Gunthorpe
2026-08-25 20:56 ` [PATCH v3 2/5] dt-bindings: iommu: Add Broadcom BCM2712 IOMMU Daniel Drake
2026-08-26 20:19   ` Florian Fainelli
2026-08-28 10:16   ` Krzysztof Kozlowski
2026-08-25 20:56 ` [PATCH v3 3/5] iommu/generic_pt: Add Broadcom BCM2712 page table format Daniel Drake
2026-08-26 18:18   ` Jason Gunthorpe
2026-08-25 20:56 ` [PATCH v3 4/5] iommu: Add Broadcom BCM2712 IOMMU driver Daniel Drake
2026-08-26 18:18   ` Jason Gunthorpe
2026-08-26 18:33   ` Florian Fainelli [this message]
2026-08-25 20:56 ` [PATCH v3 5/5] arm64: dts: broadcom: bcm2712: Add GPU IOMMU and IOMMU cache nodes Daniel Drake

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=635282ef-5c24-4820-abfa-7eaaea6e7f0e@broadcom.com \
    --to=florian.fainelli@broadcom.com \
    --cc=bcm-kernel-feedback-list@broadcom.com \
    --cc=conor+dt@kernel.org \
    --cc=dan@reactivated.net \
    --cc=devicetree@vger.kernel.org \
    --cc=iommu@lists.linux.dev \
    --cc=james.quinlan@broadcom.com \
    --cc=jgg@ziepe.ca \
    --cc=joro@8bytes.org \
    --cc=krzk+dt@kernel.org \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-rpi-kernel@lists.infradead.org \
    --cc=nick.hollinghurst@raspberrypi.com \
    --cc=robh@kernel.org \
    --cc=robin.murphy@arm.com \
    --cc=will@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox