mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Detlev Casanova <detlev.casanova@collabora.com>
To: Mauro Carvalho Chehab <mchehab@kernel.org>,
	 Ezequiel Garcia <ezequiel@vanguardiasur.com.ar>,
	 Heiko Stuebner <heiko@sntech.de>,
	 Nicolas Dufresne <nicolas.dufresne@collabora.com>,
	 Hans Verkuil <hverkuil+cisco@kernel.org>,
	Jonas Karlman <jonas@kwiboo.se>
Cc: kernel@collabora.com, linux-media@vger.kernel.org,
	 linux-kernel@vger.kernel.org,
	linux-rockchip@lists.infradead.org,
	 linux-arm-kernel@lists.infradead.org,
	 Detlev Casanova <detlev.casanova@collabora.com>
Subject: [PATCH 7/7] media: rkvdec: Add multicore IOMMU support
Date: Thu, 09 Apr 2026 09:50:42 -0400	[thread overview]
Message-ID: <20260409-rkvdec-multicore-v1-7-62b316abf0f7@collabora.com> (raw)
In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com>

As each core has its own IOMMU core, buffers must be mapped in each
core's IOMMU so that any run() call can use any core without having to
remap everything.

To do that, we use rockchip iommu domain's iommu devices list.
With that, one IOMMU domain can be mapped on multiple devices, meaning
that each call to iommu_map() will flush the new mapping on all devices
in the list.

The IOMMU domain that will have all devices in its list is the first
core's default domain.

Another domain cannot be used because VB2 allocates buffers through the
DMA engine, which uses iommu_get_dma_domain() to find the domain to map
buffers through.

The IOMMU restore function can still work as before, but needs to be more
explicit in what domain to attach the device to.
That is because detaching the empty domain will reattach the core's default
domain, which is wrong (except for the first "main" core).

The RCB temporary buffers are allocated in a dedicated SRAM, each
core has its own SRAM, so the mapping for each core's SRAM is added in the
global domain.

Everything else is mapped through the first core's default domain, making
the driver write the mappings on both IOMMU cores.

Signed-off-by: Detlev Casanova <detlev.casanova@collabora.com>
---
 .../media/platform/rockchip/rkvdec/rkvdec-rcb.c    | 21 ++++++-------
 .../media/platform/rockchip/rkvdec/rkvdec-rcb.h    |  6 ++--
 drivers/media/platform/rockchip/rkvdec/rkvdec.c    | 35 +++++++++++++++++-----
 drivers/media/platform/rockchip/rkvdec/rkvdec.h    |  2 +-
 4 files changed, 44 insertions(+), 20 deletions(-)

diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
index 190fb7438e8c..977e37cf209b 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c
@@ -57,7 +57,7 @@ bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx)
 	return ret;
 }
 
-void rkvdec_free_rcb(struct rkvdec_core *core)
+void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core)
 {
 	struct rkvdec_rcb_config *cfg = core->rcb_config;
 	unsigned long virt_addr;
@@ -76,12 +76,12 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
 		case RKVDEC_ALLOC_SRAM:
 			virt_addr = (unsigned long)cfg->rcb_bufs[i].cpu;
 
-			if (core->iommu_domain)
-				iommu_unmap(core->iommu_domain, virt_addr, rcb_size);
+			if (rkvdec->iommu_global_domain)
+				iommu_unmap(rkvdec->iommu_global_domain, virt_addr, rcb_size);
 			gen_pool_free(core->sram_pool, virt_addr, rcb_size);
 			break;
 		case RKVDEC_ALLOC_DMA:
-			dma_free_coherent(core->dev,
+			dma_free_coherent(rkvdec->main_core->dev,
 					  rcb_size,
 					  cfg->rcb_bufs[i].cpu,
 					  cfg->rcb_bufs[i].dma);
@@ -97,7 +97,8 @@ void rkvdec_free_rcb(struct rkvdec_core *core)
 	core->rcb_config = NULL;
 }
 
-int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
+int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
+			u32 width, u32 height,
 			const struct rcb_size_info *size_info,
 			size_t rcb_count)
 {
@@ -132,7 +133,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
 
 		/* Try allocating an SRAM buffer */
 		if (core->sram_pool) {
-			if (core->iommu_domain)
+			if (rkvdec->iommu_global_domain)
 				rcb_size = ALIGN(rcb_size, SZ_4K);
 
 			cpu = gen_pool_dma_zalloc_align(core->sram_pool,
@@ -142,11 +143,11 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
 		}
 
 		/* If an IOMMU is used, map the SRAM address through it */
-		if (cpu && core->iommu_domain) {
+		if (cpu && rkvdec->iommu_global_domain) {
 			unsigned long virt_addr = (unsigned long)cpu;
 			phys_addr_t phys_addr = dma;
 
-			ret = iommu_map(core->iommu_domain, virt_addr, phys_addr,
+			ret = iommu_map(rkvdec->iommu_global_domain, virt_addr, phys_addr,
 					rcb_size, IOMMU_READ | IOMMU_WRITE, 0);
 			if (ret) {
 				gen_pool_free(core->sram_pool,
@@ -166,7 +167,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
 ram_fallback:
 		/* Fallback to RAM */
 		if (!cpu) {
-			cpu = dma_alloc_coherent(core->dev,
+			cpu = dma_alloc_coherent(rkvdec->main_core->dev,
 						 rcb_size,
 						 &dma,
 						 GFP_KERNEL);
@@ -189,7 +190,7 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
 	return 0;
 
 err_alloc:
-	rkvdec_free_rcb(core);
+	rkvdec_free_rcb(rkvdec, core);
 
 	return ret;
 }
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
index a12af9b7dc2b..d1149afe7fda 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h
@@ -8,6 +8,7 @@
 
 #include <linux/types.h>
 
+struct rkvdec_dev;
 struct rkvdec_ctx;
 struct rkvdec_core;
 
@@ -21,11 +22,12 @@ struct rcb_size_info {
 	enum rcb_axis axis;
 };
 
-int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height,
+int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core,
+			u32 width, u32 height,
 			const struct rcb_size_info *size_info,
 			size_t rcb_count);
 dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id);
 size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id);
 int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx);
 bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx);
-void rkvdec_free_rcb(struct rkvdec_core *core);
+void rkvdec_free_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *core);
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
index c2818f1575ef..2930e9b64906 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c
@@ -1204,9 +1204,9 @@ static void rkvdec_device_run(void *priv)
 	}
 
 	if (!rkvdec_rcb_buf_validate_size(ctx)) {
-		rkvdec_free_rcb(ctx->core);
+		rkvdec_free_rcb(ctx->dev, ctx->core);
 
-		ret = rkvdec_allocate_rcb(ctx->core,
+		ret = rkvdec_allocate_rcb(ctx->dev, ctx->core,
 					  ctx->decoded_fmt.fmt.pix_mp.width,
 					  ctx->decoded_fmt.fmt.pix_mp.height,
 					  ctx->dev->variant->rcb_sizes,
@@ -1486,6 +1486,7 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rkvdec)
 
 static void rkvdec_iommu_restore(struct rkvdec_core *core)
 {
+	int ret;
 	if (core->empty_domain) {
 		/*
 		 * To rewrite mapping into the attached IOMMU core, attach a new empty domain that
@@ -1494,8 +1495,14 @@ static void rkvdec_iommu_restore(struct rkvdec_core *core)
 		 * This is safely done in this interrupt handler to make sure no memory get mapped
 		 * through the IOMMU while the empty domain is attached.
 		 */
-		iommu_attach_device(core->empty_domain, core->dev);
+		iommu_detach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
+		ret = iommu_attach_device(core->empty_domain, core->dev);
+		if (ret)
+			dev_warn(core->dev, "Cannot attach empty domain: %d\n", ret);
 		iommu_detach_device(core->empty_domain, core->dev);
+		ret = iommu_attach_device(core->curr_ctx->dev->iommu_global_domain, core->dev);
+		if (ret)
+			dev_warn(core->dev, "Cannot attach global domain: %d\n", ret);
 	}
 }
 
@@ -1858,6 +1865,8 @@ static int rkvdec_probe(struct platform_device *pdev)
 
 	core = &rkvdec->cores[rkvdec->core_count++];
 
+	core->id = rkvdec->core_count - 1;
+
 	platform_set_drvdata(pdev, rkvdec);
 	core->dev = &pdev->dev;
 	INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func);
@@ -1883,12 +1892,24 @@ static int rkvdec_probe(struct platform_device *pdev)
 			return PTR_ERR(core->link);
 	}
 
-	core->iommu_domain = iommu_get_domain_for_dev(&pdev->dev);
-	if (core->iommu_domain) {
+	if (iommu_get_domain_for_dev(&pdev->dev)) {
 		core->empty_domain = iommu_paging_domain_alloc(core->dev);
 
-		if (!core->empty_domain)
+		if (IS_ERR(core->empty_domain))
 			dev_warn(core->dev, "cannot alloc new empty domain\n");
+
+		if (!rkvdec->iommu_global_domain) {
+			rkvdec->iommu_global_domain = iommu_get_domain_for_dev(core->dev);
+
+			if (IS_ERR(rkvdec->iommu_global_domain)) {
+				rkvdec->iommu_global_domain = NULL;
+				dev_warn_once(core->dev, "cannot alloc new global domain\n");
+			}
+		}
+
+		ret = iommu_attach_device(rkvdec->iommu_global_domain, core->dev);
+		if (ret)
+			dev_warn(core->dev, "cannot attach global domain to core %d\n", core->id);
 	}
 
 	ret = dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
@@ -1961,7 +1982,7 @@ static void rkvdec_remove(struct platform_device *pdev)
 		if (rkvdec->cores[i].empty_domain)
 			iommu_domain_free(rkvdec->cores[i].empty_domain);
 
-		rkvdec_free_rcb(&rkvdec->cores[i]);
+		rkvdec_free_rcb(rkvdec, &rkvdec->cores[i]);
 	}
 }
 
diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
index 4f042a367dc0..ccd766b220c7 100644
--- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h
+++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h
@@ -135,7 +135,6 @@ struct rkvdec_core {
 	void __iomem *link;
 	struct delayed_work watchdog_work;
 	struct gen_pool *sram_pool;
-	struct iommu_domain *iommu_domain;
 	struct iommu_domain *empty_domain;
 	struct rkvdec_rcb_config *rcb_config;
 	struct rkvdec_ctx *curr_ctx;
@@ -155,6 +154,7 @@ struct rkvdec_dev {
 	unsigned int available_core_count;
 	spinlock_t cores_lock; /* serializes core list access */
 	struct rkvdec_core *main_core;
+	struct iommu_domain *iommu_global_domain;
 };
 
 struct rkvdec_ctx {

-- 
2.53.0


  parent reply	other threads:[~2026-04-09 13:51 UTC|newest]

Thread overview: 11+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-09 13:50 [PATCH 0/7] media: rkvdec: Enable multi-core support Detlev Casanova
2026-04-09 13:50 ` [PATCH 1/7] media: v4l2-mem2mem: Add v4l2_m2m_buf_done_manual() Detlev Casanova
2026-04-09 13:50 ` [PATCH 2/7] media: v4l2-mem2mem: Remove WARN_ON() in v4l2_m2m_job_finish() Detlev Casanova
2026-04-09 13:50 ` [PATCH 3/7] media: rkvdec: Keep RCB to the correct size Detlev Casanova
2026-04-09 13:50 ` [PATCH 4/7] media: rkvdec: Remove unused need_reset Detlev Casanova
2026-04-09 13:50 ` [PATCH 5/7] media: rkvdec: Add multicore support Detlev Casanova
2026-04-09 13:50 ` [PATCH 6/7] media: rkvdec: Wait for all buffers before stop_streaming Detlev Casanova
2026-04-09 13:50 ` Detlev Casanova [this message]
2026-04-09 14:19   ` [PATCH 7/7] media: rkvdec: Add multicore IOMMU support Nicolas Dufresne
2026-04-09 14:49     ` Detlev Casanova
2026-04-09 15:24       ` Nicolas Dufresne

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=20260409-rkvdec-multicore-v1-7-62b316abf0f7@collabora.com \
    --to=detlev.casanova@collabora.com \
    --cc=ezequiel@vanguardiasur.com.ar \
    --cc=heiko@sntech.de \
    --cc=hverkuil+cisco@kernel.org \
    --cc=jonas@kwiboo.se \
    --cc=kernel@collabora.com \
    --cc=linux-arm-kernel@lists.infradead.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-media@vger.kernel.org \
    --cc=linux-rockchip@lists.infradead.org \
    --cc=mchehab@kernel.org \
    --cc=nicolas.dufresne@collabora.com \
    /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

all inboxes | Powered by JetHome®