From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 841CF3D3489; Thu, 9 Apr 2026 13:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742700; cv=none; b=Pi6ugevXK5TbMclGI506+yXPIUkMk0CjEwz8/+nE7k8SpEn1CnK9EJYJITg3/GxAPrPSiVe+9du0/fPcRYgykfBG37ek2XcKBIDH/UPN8111dqVNFRkChHSkgL0klc4kEwctLipnVCjLsRh0hfDaopM3b4ewxrgj6LwbRPL71Ek= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742700; c=relaxed/simple; bh=EANjXK0pUgPsxuTannl80kTzacZ17wagSvF/zmR7XQE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=N8NR8orMqIb5wzc7Uz5CMNnOkHo9gx7W8KdjNtjVBTV0BQvvC0y2UkVwp/S246VNPIU4vhNKAw5KkYtrFL6Y09YWWdppYWOixxPo+eIWPoeZ5aYwOuEbQz0HYfToQ+fxXnXP8xsfwg9msA0aoMHOCHWdF2sjMIRYuB3Pq4OWoBo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=dXvO3xJx; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="dXvO3xJx" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742690; bh=EANjXK0pUgPsxuTannl80kTzacZ17wagSvF/zmR7XQE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=dXvO3xJxl7lDEOkIRDGLuC+39/Sm6Y2njQQiRjybGrV0XFhGDJ9mL99rvQktUq7cN VqFYAexEknC3JnYkGlCzdstdGN9PalgO49S6bStNXE5piAuVPXWxh5v8uypHd7Mltj KhlW0hg5HJg+jJjVATlAwO8MtJf97+deopOT6vum7r9xBfiL4IWuiRl+7zYLBD+XTO nRjJbzSkrl4GNPBHgmoeBfJZJWpYKtT2LY72khK5p9LqnpnJOxbWimZUSmlj/HnuLR hVlCld99uuUMyy1wucuS/xXkYmx6UdWdb8LwbDEb8SNcz5CnCsdegNBPmRdYMUT6fk xmDcvA5ir4z+w== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id 2C1C917E0D23; Thu, 9 Apr 2026 15:51:29 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:36 -0400 Subject: [PATCH 1/7] media: v4l2-mem2mem: Add v4l2_m2m_buf_done_manual() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-1-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 This function can be used to mark buffers as done, handling locking, but not finishing the job as it is done by v4l2_m2m_buf_done_and_finish_job(). To avoid copying similar code, a static function is added with an extra finish argument. The code path of v4l2_m2m_buf_done_and_finish_job() is unchanged. This allows for finer grained buffer management in drivers, scheduling new jobs before the previous one is finished and prepares for enabling multicore support in rkvdec. Signed-off-by: Detlev Casanova --- drivers/media/v4l2-core/v4l2-mem2mem.c | 27 ++++++++++++++++++++++----- include/media/v4l2-mem2mem.h | 20 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-co= re/v4l2-mem2mem.c index a65cbb124cfe..7f9fad4f6807 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -503,9 +503,9 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, } EXPORT_SYMBOL(v4l2_m2m_job_finish); =20 -void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, - struct v4l2_m2m_ctx *m2m_ctx, - enum vb2_buffer_state state) +static void _buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state, bool finish) { struct vb2_v4l2_buffer *src_buf, *dst_buf; bool schedule_next =3D false; @@ -532,13 +532,30 @@ void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m= _dev *m2m_dev, * before the CAPTURE buffer is done. */ v4l2_m2m_buf_done(src_buf, state); - schedule_next =3D _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); + if (finish) + schedule_next =3D _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); unlock: spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); =20 - if (schedule_next) + if (schedule_next || !finish) v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx); } + + +void v4l2_m2m_buf_done_manual(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state) +{ + _buf_done_and_job_finish(m2m_dev, m2m_ctx, state, false); +} +EXPORT_SYMBOL(v4l2_m2m_buf_done_manual); + +void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state) +{ + _buf_done_and_job_finish(m2m_dev, m2m_ctx, state, true); +} EXPORT_SYMBOL(v4l2_m2m_buf_done_and_job_finish); =20 void v4l2_m2m_suspend(struct v4l2_m2m_dev *m2m_dev) diff --git a/include/media/v4l2-mem2mem.h b/include/media/v4l2-mem2mem.h index 31de25d792b9..6a36fc885f5f 100644 --- a/include/media/v4l2-mem2mem.h +++ b/include/media/v4l2-mem2mem.h @@ -227,6 +227,26 @@ void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_= dev *m2m_dev, struct v4l2_m2m_ctx *m2m_ctx, enum vb2_buffer_state state); =20 +/** + * v4l2_m2m_buf_done_manual() - manually mark the job as done, but do not + * finish it. + * + * @m2m_dev: opaque pointer to the internal data to handle M2M context + * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2= m_ctx + * @state: vb2 buffer state passed to v4l2_m2m_buf_done(). + * + * The function works the same way as v4l2_m2m_buf_done_and_job_finish() + * but does not inform the framework that the job has been finished, + * leaving the user the responsability to call v4l2_m2m_job_finish() + * when a buffer can be released to userspace. + * + * It allows driver to process new buffers, before the previous one is + * done. + */ +void v4l2_m2m_buf_done_manual(struct v4l2_m2m_dev *m2m_dev, + struct v4l2_m2m_ctx *m2m_ctx, + enum vb2_buffer_state state); + static inline void v4l2_m2m_buf_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state) { --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7E1CA3D4107; Thu, 9 Apr 2026 13:51:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742701; cv=none; b=pxQawypZouKx4cYfi0kh7S7Lg0sdv2tMew6E4Hz0mB9s1723pb3GiFLiuEwHhTqNGkUV8K2UnN08N+qucAAgtR71L6j8Wm2nxzlVZcwllExSgv7YN5rewGQBr9cjgoY+BJYKBtfH3aXgSr5deTmGN+mce0JGTtSqcO/fdYUULFg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742701; c=relaxed/simple; bh=Uf3oawvhkOYDFsuF3t/kHZrtN6yz3uwa92uWH3g5zZM=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=shXA3ZOwE2JRqbc7SwfJuFLfINW+vMjURGHDpQbHZip3OEB3IGthvyJ8anArdRC7B8OYL8rYLnRt5LTbivHKAg/pQmQA3RSMJf4nr1SdAp+oDIQY1RJBCRGhGOqV+zmqPLmdNtlydGwDq5FVdrfYdf8OULbqJklFgQEi/kKFMh4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=jOsFp6YU; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="jOsFp6YU" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742692; bh=Uf3oawvhkOYDFsuF3t/kHZrtN6yz3uwa92uWH3g5zZM=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=jOsFp6YU19b4d9Al8Ya16eVbiA5JsxqAJk1Td7XesbTO3lecWg/CaHDjV0z88Z+wb DyGdSLd82ehcyXpESkkersjoow99twav8ffpVGSyo3ljejE60umkCJ9pbHze46LVhs oxjOOr/1tbekHy8UbuabqjGHmFVtrRN3wJcra9WNgm9OC1T/V4Q0YOy79DOrQlMl44 3lMVLCTZyFfuGEWUpqiSDomLanqEgLF4fT7glpfMKA0b+hD3NKsbNNNTYA51Bg50BZ R9Oqk6nhI4gqtPtVmYnR9TjTyP1CWvkNOO90zFU29Aey0SxevVZ1FuUg+E6VCQVF+6 wGCto+Wtu4K+w== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id 09A3017E1313; Thu, 9 Apr 2026 15:51:30 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:37 -0400 Subject: [PATCH 2/7] media: v4l2-mem2mem: Remove WARN_ON() in v4l2_m2m_job_finish() Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-2-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 This warning was added because there was no way, for drivers that support holding capture buffers to mark jobs done correctly without calling v4l2_m2m_buf_done_and_job_finish(). Now that v4l2_m2m_buf_done_manual() has been introduced, it has become possible and drivers can use it with v4l2_m2m_job_finish() for finer grained buffer management. Signed-off-by: Detlev Casanova --- drivers/media/v4l2-core/v4l2-mem2mem.c | 7 ------- 1 file changed, 7 deletions(-) diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-co= re/v4l2-mem2mem.c index 7f9fad4f6807..27f7dd7974b5 100644 --- a/drivers/media/v4l2-core/v4l2-mem2mem.c +++ b/drivers/media/v4l2-core/v4l2-mem2mem.c @@ -487,13 +487,6 @@ void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev, unsigned long flags; bool schedule_next; =20 - /* - * This function should not be used for drivers that support - * holding capture buffers. Those should use - * v4l2_m2m_buf_done_and_job_finish() instead. - */ - WARN_ON(m2m_ctx->out_q_ctx.q.subsystem_flags & - VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF); spin_lock_irqsave(&m2m_dev->job_spinlock, flags); schedule_next =3D _v4l2_m2m_job_finish(m2m_dev, m2m_ctx); spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags); --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 36C663D6487; Thu, 9 Apr 2026 13:51:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742705; cv=none; b=CsTq6DMqg6S/rvEBvlGPXNtW2+EDE8KuTjOyhr1vkUCa4FMMtk6ZrqWjcobHxcb0LK3WCsOH28i95kAM8cNmB06syfcXQuvuIyu65SNx9MVBpmrSVhyfwyAVlISCAQ2fXac3qHa/rWhKM4+W2FBGDgMrMmjpSs5OkR5qYenPx6Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742705; c=relaxed/simple; bh=RSXqqXBeCA6gtCqM9bPU3XduJDdYCviviiS0NH06u4c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=DGXGxlm1c/TDLulmq4l1dMCf4aYXFkuYAOO/NqdRll2btP2vW6Iln4ienHgiW1sNXXnvnWkF1yjxipqkPWjQcbNT9jyuXzm4m/K3Umk0u4v0LbeYImN8wzHocS6BaGLoTRSlgpNwGyLhx5rIrDWF8Z82oEU4qbYs75TPV3KEm70= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=PlDuXPYh; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="PlDuXPYh" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742694; bh=RSXqqXBeCA6gtCqM9bPU3XduJDdYCviviiS0NH06u4c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=PlDuXPYh9iFHSE99Vm2uPMpq8YIeslosXFoEw/ERifLU7sIKFBhdYjMR67mIUTqcL BKQAAsO8b1fxdJeTAo85USrPI1TTe92V+WqNZRCq8NoPzC1uwM3kvRGrcQbrreopWF QxaPdeO+Cpm17dlxYy0krLms9pxmWDiCJdkXAOB1XPXwovFLeFdtk2DaO47ZNYM5SO z/koExQNhwgkvqshVz41gSGcD+5XnVDMSjPJ5CzErljR4YFQvPrmPjdLDeViWKqtSK cCCYj+L9zCS4YNAzxxEU3L1bmE3wzu/BqAlzI7Z7AdJ2OmRX/AnDncTt03DN+0LArf HPohmFozY/C7Q== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id D273817E1330; Thu, 9 Apr 2026 15:51:32 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:38 -0400 Subject: [PATCH 3/7] media: rkvdec: Keep RCB to the correct size Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-3-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 Currently, if a video changes resolution, the RCB size might be too small and the HW could try to write out of the allocated buffer. To fix that, make sure that the RCB size is validated for each run and increase the buffer size when needed. Fixes: e5640dbb991c ("media: rkvdec: Add RCB and SRAM support") Signed-off-by: Detlev Casanova --- .../media/platform/rockchip/rkvdec/rkvdec-rcb.c | 26 +++++++++++++++--- .../media/platform/rockchip/rkvdec/rkvdec-rcb.h | 3 ++- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 31 +++++++++++-------= ---- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/= media/platform/rockchip/rkvdec/rkvdec-rcb.c index fdcf1f177379..191f78278c01 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c @@ -17,6 +17,8 @@ struct rkvdec_rcb_config { struct rkvdec_aux_buf *rcb_bufs; size_t rcb_count; + u32 width; + u32 height; }; =20 static size_t rkvdec_rcb_size(const struct rcb_size_info *size_info, @@ -40,6 +42,21 @@ int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx) return ctx->rcb_config->rcb_count; } =20 +bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx) +{ + struct rkvdec_rcb_config *cfg =3D ctx->rcb_config; + + bool ret =3D cfg && cfg->height >=3D ctx->decoded_fmt.fmt.pix_mp.height && + cfg->width >=3D ctx->decoded_fmt.fmt.pix_mp.width; + + if (!ret && cfg) { + dev_dbg(ctx->dev->dev, "RCB size %ux%u -> %ux%u\n", cfg->width, cfg->hei= ght, + ctx->decoded_fmt.fmt.pix_mp.width, ctx->decoded_fmt.fmt.pix_mp.height); + } + + return ret; +} + void rkvdec_free_rcb(struct rkvdec_ctx *ctx) { struct rkvdec_dev *dev =3D ctx->dev; @@ -77,14 +94,15 @@ void rkvdec_free_rcb(struct rkvdec_ctx *ctx) devm_kfree(dev->dev, cfg->rcb_bufs); =20 devm_kfree(dev->dev, cfg); + + ctx->rcb_config =3D NULL; } =20 -int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height, const struct rcb_size_info *size_info, size_t rcb_count) { int ret, i; - u32 width, height; struct rkvdec_dev *rkvdec =3D ctx->dev; struct rkvdec_rcb_config *cfg; =20 @@ -105,8 +123,8 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, goto err_alloc; } =20 - width =3D ctx->decoded_fmt.fmt.pix_mp.width; - height =3D ctx->decoded_fmt.fmt.pix_mp.height; + cfg->width =3D width; + cfg->height =3D height; =20 for (i =3D 0; i < rcb_count; i++) { void *cpu =3D NULL; diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/= media/platform/rockchip/rkvdec/rkvdec-rcb.h index 30e8002555c8..0662a4359bdf 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h @@ -20,10 +20,11 @@ struct rcb_size_info { enum rcb_axis axis; }; =20 -int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, +int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, 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_ctx *ctx); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.c index 1d1e9bfef8e9..31ddfcc58894 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -978,8 +978,7 @@ static int rkvdec_start_streaming(struct vb2_queue *q, = unsigned int count) { struct rkvdec_ctx *ctx =3D vb2_get_drv_priv(q); const struct rkvdec_coded_fmt_desc *desc; - const struct rkvdec_variant *variant =3D ctx->dev->variant; - int ret; + int ret =3D 0; =20 if (V4L2_TYPE_IS_CAPTURE(q->type)) return 0; @@ -988,20 +987,8 @@ static int rkvdec_start_streaming(struct vb2_queue *q,= unsigned int count) if (WARN_ON(!desc)) return -EINVAL; =20 - ret =3D rkvdec_allocate_rcb(ctx, variant->rcb_sizes, variant->num_rcb_siz= es); - if (ret) - return ret; - - if (desc->ops->start) { + if (desc->ops->start) ret =3D desc->ops->start(ctx); - if (ret) - goto err_ops_start; - } - - return 0; - -err_ops_start: - rkvdec_free_rcb(ctx); =20 return ret; } @@ -1174,6 +1161,20 @@ static void rkvdec_device_run(void *priv) return; } =20 + if (!rkvdec_rcb_buf_validate_size(ctx)) { + rkvdec_free_rcb(ctx); + + ret =3D rkvdec_allocate_rcb(ctx, + ctx->decoded_fmt.fmt.pix_mp.width, + ctx->decoded_fmt.fmt.pix_mp.height, + ctx->dev->variant->rcb_sizes, + ctx->dev->variant->num_rcb_sizes); + if (ret) { + rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); + return; + } + } + ret =3D desc->ops->run(ctx); if (ret) rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A3B463A2550; Thu, 9 Apr 2026 13:51:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742699; cv=none; b=URY7Z/WKALWb+NOM1D6V9M1BS/eZGU9fEGlXCeKCyVQ/RYI9tu0dZ7iV9aviyQsPxx8ySbd8x6ad+XWZ9NBHaKLBG6Lff2/gtoWk6wl4wJbbk9X2Gmvp+pHBqfTVNeiTsu0dA3h0PcinB2q4SVbFujs/0k+buC0QD3yXkAauxis= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742699; c=relaxed/simple; bh=KyzQwUnfDm1fztBC6M2uhc6YYJnSNz50uKom2fCwuZQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=b7U8dBdjh4DRrYErltsb/9gg6JkROQ1JJIYyv2573TOuX1YgS/WuBn+hr0PivObXxMmOQNS8+gZMf0drZkxLty0lh4Ph78sCeadUTsZDr3hQSmMQvOdyR/F2Ohv+lOppTQnhA5LjFgt6HK2j9ZfkIfA6nvCw5HdgLoZJ20KoaAg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=l4XS61sD; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="l4XS61sD" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742696; bh=KyzQwUnfDm1fztBC6M2uhc6YYJnSNz50uKom2fCwuZQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=l4XS61sDtun10RvRrmAQdt2YKZsc3mBoeRg457cBWGGTuDs9yhOa93DjK/eKkcis/ I2jBM8k7jCXzYrakt2XSG/SUk+l3jYS0EN9pPNVJb45KOl9scpyPpxGFWTIw7QC0gQ jOjaQDiSsKbnF1N7LAFSnfWJZ3zee3/v9sIi+a4DHcQ+Vmm1dq8Q82wEr7pUTLkUj6 LykLGfPf9suuSmY/syNld4fwOqDt+pJ6tlgud/jlwlMDKpO/Bj1hzOY7/BOvP58UIW +3bNDUZyohkpOSW3EJvvvn70SBDrd6CIwaJga2/V6QSTkv3EST0WAPHSTi6mCuUwOg Pu3/rB7H6f5DQ== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id AAE7917E1340; Thu, 9 Apr 2026 15:51:34 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:39 -0400 Subject: [PATCH 4/7] media: rkvdec: Remove unused need_reset Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-4-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 A left-over from the iommu restore mecanism was forgotten. As need_reset is never set to true, the if has no use. The actual restore function is called above it vase the IRQ isn't in a success status. Signed-off-by: Detlev Casanova --- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.c index 31ddfcc58894..db2731af06cf 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -1462,7 +1462,6 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_= ctx *ctx) { struct rkvdec_dev *rkvdec =3D ctx->dev; enum vb2_buffer_state state; - bool need_reset =3D 0; u32 status; =20 status =3D readl(rkvdec->regs + VDPU381_REG_STA_INT); @@ -1478,9 +1477,6 @@ static irqreturn_t vdpu381_irq_handler(struct rkvdec_= ctx *ctx) rkvdec_iommu_restore(rkvdec); } =20 - if (need_reset) - rkvdec_iommu_restore(rkvdec); - if (cancel_delayed_work(&rkvdec->watchdog_work)) rkvdec_job_finish(ctx, state); =20 @@ -1491,7 +1487,6 @@ static irqreturn_t vdpu383_irq_handler(struct rkvdec_= ctx *ctx) { struct rkvdec_dev *rkvdec =3D ctx->dev; enum vb2_buffer_state state; - bool need_reset =3D 0; u32 status; =20 status =3D readl(rkvdec->link + VDPU383_LINK_STA_INT); @@ -1507,9 +1502,6 @@ static irqreturn_t vdpu383_irq_handler(struct rkvdec_= ctx *ctx) rkvdec_iommu_restore(rkvdec); } =20 - if (need_reset) - rkvdec_iommu_restore(rkvdec); - if (cancel_delayed_work(&rkvdec->watchdog_work)) rkvdec_job_finish(ctx, state); =20 --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 36BA73B9DA8; Thu, 9 Apr 2026 13:51:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742707; cv=none; b=Ie5aMF4Al3UzUp/RQp8zrvJicJl149ALpQYYzAbbbwVCIuyOJUbcdlhukipVraolWQVm73vaOU5YBWCHIIMdvuFeYTkW/xzfmwsMkW4zhw1+QrIYf7aYL+B3MIPjwFReIOkMp5H5VDWqQnFS1kW69+MvoNk8hE92oNkANyYPZdg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742707; c=relaxed/simple; bh=Liu/oRggu1n9YjyIDxPUgj+IUuHY6Obi1pOPsEJ6gq4=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=BytCbAGEDJOUVI9wNdCyH5WmFKLwKn2OXtPDznc5Moff/q2vW6YJ5GbBHaJQPo/skatF8jHiCmgiokMx+KBt6NuvLFb0mUJb4j+j5Ck0YOaARGEKvX1QkjzU4Xjb1YEopr51C16hKPSSdb3HvRIra3WO2oq1vdV4iSj4P96ubx0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=PqDDXwpf; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="PqDDXwpf" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742698; bh=Liu/oRggu1n9YjyIDxPUgj+IUuHY6Obi1pOPsEJ6gq4=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=PqDDXwpf3OCFUw6zWnGNQ7t7IUPTTb36HznjfzMtUmm832uE1rTiuePm52yYbgo66 KcywMNwOosSyNaoD8H3l6buJrsSFT1xOdr0er3K7502Th5A6gqX9cXrDmp5EtDR9f9 C23LfArMCJYYjnjZD/G9QaJ0tXkSZQWW26wFeJMQCmsUtLyuRATmgtJMTUjEpkmOTA LWLNDWkvOpQpTsXAfjaUcN5Zg+iUDZoSMHQSy+q9FSaHEl+2cH73x23tfJg6Cesry8 gci8mXv5m28BhIROsxHbaP46eCxiBjXSPuBmHbH43WH0YuIEdi+yJv/MrxVD+0rs9t 9a218DwYCJXug== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7E70817E12B9; Thu, 9 Apr 2026 15:51:36 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:40 -0400 Subject: [PATCH 5/7] media: rkvdec: Add multicore support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-5-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 Rockchip SoCs like the RK3588 have multiple independent decoder cores They are defined in the device tree as separate DT nodes sharing the same compatible. Rework the driver to discover and drive all of them from the same v4l2 device. During probe, rkvdec_probe_get_first() finds the first available DT node with a matching compatible. If the probing device is that node, a new rkvdec_dev is allocated and a rkvdec_core is added to it to become the main core. Otherwise the existing rkvdec_dev is retrieved via platform_get_drvdata() and the new core is appended to the list. V4L2/m2m registration happens only once, on the main core. Per-core hardware resources (MMIO, clocks, SRAM pool, IOMMU domain, watchdog, RCB buffers) are moved into a new struct rkvdec_core. A spinlock-protected pool of available cores tracks which cores are idle and acquire_core() is used to pop a core before each decode, with release_core() returning it after completion. The m2m job_ready callback is implemented to prevent scheduling a context that is already actively decoding on a core, allowing the framework to move on to the next queued context instead. Buffer completion is split from job completion: v4l2_m2m_buf_done_manual() marks buffers done and release_core() returns the core, then v4l2_m2m_try_schedule() is called to wake waiters. v4l2_m2m_job_finish() is called unconditionally at the end of device_run() so the m2m framework can immediately schedule the next job for enother core, while this one is still running. This mechanism allows jobs from multiple contexts to run simultaneously, but does not allow parallele decoding within a single context. Scheduling such jobs would need more analyses on reference frames availability for each job to run, and could not yield impressive performance gain if frames depend on the previous one being fully decoded. Signed-off-by: Detlev Casanova --- .../media/platform/rockchip/rkvdec/rkvdec-h264.c | 17 +- .../media/platform/rockchip/rkvdec/rkvdec-hevc.c | 16 +- .../media/platform/rockchip/rkvdec/rkvdec-rcb.c | 58 ++- .../media/platform/rockchip/rkvdec/rkvdec-rcb.h | 5 +- .../platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c | 24 +- .../platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c | 24 +- .../platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c | 24 +- .../platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c | 26 +- .../media/platform/rockchip/rkvdec/rkvdec-vp9.c | 27 +- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 430 +++++++++++++----= ---- drivers/media/platform/rockchip/rkvdec/rkvdec.h | 29 +- 11 files changed, 401 insertions(+), 279 deletions(-) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c b/drivers= /media/platform/rockchip/rkvdec/rkvdec-h264.c index d3202cecb988..215676c55069 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-h264.c @@ -248,6 +248,7 @@ static void set_poc_reg(struct rkvdec_regs *regs, uint3= 2_t poc, int id, bool bot static void config_registers(struct rkvdec_ctx *ctx, struct rkvdec_h264_run *run) { + struct rkvdec_core *core =3D ctx->core; struct rkvdec_dev *rkvdec =3D ctx->dev; const struct v4l2_ctrl_h264_decode_params *dec_params =3D run->decode_par= ams; const struct v4l2_ctrl_h264_sps *sps =3D run->sps; @@ -354,7 +355,7 @@ static void config_registers(struct rkvdec_ctx *ctx, offset =3D offsetof(struct rkvdec_h264_priv_tbl, err_info); regs->h26x.errorinfo_base =3D priv_start_addr + offset; =20 - rkvdec_memcpy_toio(rkvdec->regs, regs, + rkvdec_memcpy_toio(core->regs, regs, MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs)); } =20 @@ -379,7 +380,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) if (!h264_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &h264_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -404,7 +405,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, h264_ctx->priv_tbl.size, h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma); kfree(h264_ctx); } @@ -412,7 +413,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) static int rkvdec_h264_run(struct rkvdec_ctx *ctx) { struct v4l2_h264_reflist_builder reflist_builder; - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; struct rkvdec_h264_run run; struct rkvdec_h264_priv_tbl *tbl =3D h264_ctx->priv_tbl.cpu; @@ -434,15 +435,15 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) =20 rkvdec_run_postamble(ctx, &run.base); =20 - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); + schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000)); =20 - writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); =20 /* Start decoding! */ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, - rkvdec->regs + RKVDEC_REG_INTERRUPT); + core->regs + RKVDEC_REG_INTERRUPT); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c b/drivers= /media/platform/rockchip/rkvdec/rkvdec-hevc.c index ac8b825d080a..fd664ac63698 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-hevc.c @@ -402,6 +402,7 @@ static void assemble_sw_rps(struct rkvdec_ctx *ctx, static void config_registers(struct rkvdec_ctx *ctx, struct rkvdec_hevc_run *run) { + struct rkvdec_core *core =3D ctx->core; struct rkvdec_dev *rkvdec =3D ctx->dev; const struct v4l2_ctrl_hevc_decode_params *decode_params =3D run->decode_= params; const struct v4l2_ctrl_hevc_sps *sps =3D run->sps; @@ -498,7 +499,7 @@ static void config_registers(struct rkvdec_ctx *ctx, offset =3D offsetof(struct rkvdec_hevc_priv_tbl, rps); regs->h26x.rps_base =3D priv_start_addr + offset; =20 - rkvdec_memcpy_toio(rkvdec->regs, regs, + rkvdec_memcpy_toio(core->regs, regs, MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs)); } =20 @@ -532,7 +533,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) if (!hevc_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &hevc_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { kfree(hevc_ctx); @@ -553,13 +554,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size, hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); kfree(hevc_ctx); } =20 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) { + struct rkvdec_core *core =3D ctx->core; struct rkvdec_dev *rkvdec =3D ctx->dev; struct rkvdec_hevc_run run; struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; @@ -576,10 +578,10 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) =20 rkvdec_run_postamble(ctx, &run.base); =20 - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); + schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000)); =20 - writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); =20 if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS) rkvdec_quirks_disable_qos(ctx); @@ -589,7 +591,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) 0 : RKVDEC_WR_DDR_ALIGN_EN; writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E | reg, - rkvdec->regs + RKVDEC_REG_INTERRUPT); + core->regs + RKVDEC_REG_INTERRUPT); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c b/drivers/= media/platform/rockchip/rkvdec/rkvdec-rcb.c index 191f78278c01..190fb7438e8c 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.c @@ -29,38 +29,37 @@ static size_t rkvdec_rcb_size(const struct rcb_size_inf= o *size_info, =20 dma_addr_t rkvdec_rcb_buf_dma_addr(struct rkvdec_ctx *ctx, int id) { - return ctx->rcb_config->rcb_bufs[id].dma; + return ctx->core->rcb_config->rcb_bufs[id].dma; } =20 size_t rkvdec_rcb_buf_size(struct rkvdec_ctx *ctx, int id) { - return ctx->rcb_config->rcb_bufs[id].size; + return ctx->core->rcb_config->rcb_bufs[id].size; } =20 int rkvdec_rcb_buf_count(struct rkvdec_ctx *ctx) { - return ctx->rcb_config->rcb_count; + return ctx->core->rcb_config->rcb_count; } =20 bool rkvdec_rcb_buf_validate_size(struct rkvdec_ctx *ctx) { - struct rkvdec_rcb_config *cfg =3D ctx->rcb_config; + struct rkvdec_rcb_config *cfg =3D ctx->core->rcb_config; =20 bool ret =3D cfg && cfg->height >=3D ctx->decoded_fmt.fmt.pix_mp.height && cfg->width >=3D ctx->decoded_fmt.fmt.pix_mp.width; =20 if (!ret && cfg) { - dev_dbg(ctx->dev->dev, "RCB size %ux%u -> %ux%u\n", cfg->width, cfg->hei= ght, + dev_dbg(ctx->core->dev, "RCB size %ux%u -> %ux%u\n", cfg->width, cfg->he= ight, ctx->decoded_fmt.fmt.pix_mp.width, ctx->decoded_fmt.fmt.pix_mp.height); } =20 return ret; } =20 -void rkvdec_free_rcb(struct rkvdec_ctx *ctx) +void rkvdec_free_rcb(struct rkvdec_core *core) { - struct rkvdec_dev *dev =3D ctx->dev; - struct rkvdec_rcb_config *cfg =3D ctx->rcb_config; + struct rkvdec_rcb_config *cfg =3D core->rcb_config; unsigned long virt_addr; int i; =20 @@ -77,12 +76,12 @@ void rkvdec_free_rcb(struct rkvdec_ctx *ctx) case RKVDEC_ALLOC_SRAM: virt_addr =3D (unsigned long)cfg->rcb_bufs[i].cpu; =20 - if (dev->iommu_domain) - iommu_unmap(dev->iommu_domain, virt_addr, rcb_size); - gen_pool_free(dev->sram_pool, virt_addr, rcb_size); + if (core->iommu_domain) + iommu_unmap(core->iommu_domain, virt_addr, rcb_size); + gen_pool_free(core->sram_pool, virt_addr, rcb_size); break; case RKVDEC_ALLOC_DMA: - dma_free_coherent(dev->dev, + dma_free_coherent(core->dev, rcb_size, cfg->rcb_bufs[i].cpu, cfg->rcb_bufs[i].dma); @@ -91,33 +90,32 @@ void rkvdec_free_rcb(struct rkvdec_ctx *ctx) } =20 if (cfg->rcb_bufs) - devm_kfree(dev->dev, cfg->rcb_bufs); + devm_kfree(core->dev, cfg->rcb_bufs); =20 - devm_kfree(dev->dev, cfg); + devm_kfree(core->dev, cfg); =20 - ctx->rcb_config =3D NULL; + core->rcb_config =3D NULL; } =20 -int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height, +int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height, const struct rcb_size_info *size_info, size_t rcb_count) { int ret, i; - struct rkvdec_dev *rkvdec =3D ctx->dev; struct rkvdec_rcb_config *cfg; =20 if (!size_info || !rcb_count) { - ctx->rcb_config =3D NULL; + core->rcb_config =3D NULL; return 0; } =20 - ctx->rcb_config =3D devm_kzalloc(rkvdec->dev, sizeof(*ctx->rcb_config), G= FP_KERNEL); - if (!ctx->rcb_config) + core->rcb_config =3D devm_kzalloc(core->dev, sizeof(*core->rcb_config), G= FP_KERNEL); + if (!core->rcb_config) return -ENOMEM; =20 - cfg =3D ctx->rcb_config; + cfg =3D core->rcb_config; =20 - cfg->rcb_bufs =3D devm_kzalloc(rkvdec->dev, sizeof(*cfg->rcb_bufs) * rcb_= count, GFP_KERNEL); + cfg->rcb_bufs =3D devm_kzalloc(core->dev, sizeof(*cfg->rcb_bufs) * rcb_co= unt, GFP_KERNEL); if (!cfg->rcb_bufs) { ret =3D -ENOMEM; goto err_alloc; @@ -133,25 +131,25 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 w= idth, u32 height, enum rkvdec_alloc_type alloc_type =3D RKVDEC_ALLOC_SRAM; =20 /* Try allocating an SRAM buffer */ - if (ctx->dev->sram_pool) { - if (rkvdec->iommu_domain) + if (core->sram_pool) { + if (core->iommu_domain) rcb_size =3D ALIGN(rcb_size, SZ_4K); =20 - cpu =3D gen_pool_dma_zalloc_align(ctx->dev->sram_pool, + cpu =3D gen_pool_dma_zalloc_align(core->sram_pool, rcb_size, &dma, SZ_4K); } =20 /* If an IOMMU is used, map the SRAM address through it */ - if (cpu && rkvdec->iommu_domain) { + if (cpu && core->iommu_domain) { unsigned long virt_addr =3D (unsigned long)cpu; phys_addr_t phys_addr =3D dma; =20 - ret =3D iommu_map(rkvdec->iommu_domain, virt_addr, phys_addr, + ret =3D iommu_map(core->iommu_domain, virt_addr, phys_addr, rcb_size, IOMMU_READ | IOMMU_WRITE, 0); if (ret) { - gen_pool_free(ctx->dev->sram_pool, + gen_pool_free(core->sram_pool, (unsigned long)cpu, rcb_size); cpu =3D NULL; @@ -168,7 +166,7 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 wid= th, u32 height, ram_fallback: /* Fallback to RAM */ if (!cpu) { - cpu =3D dma_alloc_coherent(ctx->dev->dev, + cpu =3D dma_alloc_coherent(core->dev, rcb_size, &dma, GFP_KERNEL); @@ -191,7 +189,7 @@ int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 wid= th, u32 height, return 0; =20 err_alloc: - rkvdec_free_rcb(ctx); + rkvdec_free_rcb(core); =20 return ret; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h b/drivers/= media/platform/rockchip/rkvdec/rkvdec-rcb.h index 0662a4359bdf..a12af9b7dc2b 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-rcb.h @@ -9,6 +9,7 @@ #include =20 struct rkvdec_ctx; +struct rkvdec_core; =20 enum rcb_axis { PIC_WIDTH =3D 0, @@ -20,11 +21,11 @@ struct rcb_size_info { enum rcb_axis axis; }; =20 -int rkvdec_allocate_rcb(struct rkvdec_ctx *ctx, u32 width, u32 height, +int rkvdec_allocate_rcb(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_ctx *ctx); +void rkvdec_free_rcb(struct rkvdec_core *core); diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c b= /drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c index b961fddc8583..667c5d36f3ea 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-h264.c @@ -185,22 +185,22 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, =20 static void rkvdec_write_regs(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; =20 - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_REGS, &h264_ctx->regs.common, sizeof(h264_ctx->regs.common)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_PARAMS_REGS, &h264_ctx->regs.h264_param, sizeof(h264_ctx->regs.h264_param)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_ADDR_REGS, &h264_ctx->regs.common_addr, sizeof(h264_ctx->regs.common_addr)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_ADDR_REGS, &h264_ctx->regs.h264_addr, sizeof(h264_ctx->regs.h264_addr)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_POC_HIGHBIT_REGS, &h264_ctx->regs.h264_highpoc, sizeof(h264_ctx->regs.h264_highpoc)); } @@ -368,7 +368,6 @@ static void config_registers(struct rkvdec_ctx *ctx, =20 static int rkvdec_h264_start(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; struct rkvdec_h264_priv_tbl *priv_tbl; struct rkvdec_h264_ctx *h264_ctx; struct v4l2_ctrl *ctrl; @@ -387,7 +386,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) if (!h264_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(ctx->dev->main_core->dev, sizeof(*priv_tb= l), &h264_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -410,9 +409,8 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) { struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; - struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, + dma_free_coherent(ctx->dev->main_core->dev, h264_ctx->priv_tbl.size, h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma); kfree(h264_ctx); } @@ -420,7 +418,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) static int rkvdec_h264_run(struct rkvdec_ctx *ctx) { struct v4l2_h264_reflist_builder reflist_builder; - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; struct rkvdec_h264_priv_tbl *tbl =3D h264_ctx->priv_tbl.cpu; struct rkvdec_h264_run run; @@ -443,10 +441,10 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) =20 rkvdec_run_postamble(ctx, &run.base); =20 - rkvdec_schedule_watchdog(rkvdec, h264_ctx->regs.common.reg032_timeout_thr= eshold); + rkvdec_schedule_watchdog(core, h264_ctx->regs.common.reg032_timeout_thres= hold); =20 /* Start decoding! */ - writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E); + writel(VDPU381_DEC_E_BIT, core->regs + VDPU381_REG_DEC_E); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c b= /drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c index fe6414a17551..bd68120b74c6 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu381-hevc.c @@ -356,22 +356,22 @@ static void set_ref_valid(struct rkvdec_vdpu381_regs_= hevc *regs, int id, u32 val =20 static void rkvdec_write_regs(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; =20 - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_REGS, &hevc_ctx->regs.common, sizeof(hevc_ctx->regs.common)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_PARAMS_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_PARAMS_REGS, &hevc_ctx->regs.hevc_param, sizeof(hevc_ctx->regs.hevc_param)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_COMMON_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_COMMON_ADDR_REGS, &hevc_ctx->regs.common_addr, sizeof(hevc_ctx->regs.common_addr)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_CODEC_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_CODEC_ADDR_REGS, &hevc_ctx->regs.hevc_addr, sizeof(hevc_ctx->regs.hevc_addr)); - rkvdec_memcpy_toio(rkvdec->regs + OFFSET_POC_HIGHBIT_REGS, + rkvdec_memcpy_toio(core->regs + OFFSET_POC_HIGHBIT_REGS, &hevc_ctx->regs.hevc_highpoc, sizeof(hevc_ctx->regs.hevc_highpoc)); } @@ -555,7 +555,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) if (!hevc_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &hevc_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -580,14 +580,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size, hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); kfree(hevc_ctx); } =20 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_hevc_run run; struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; struct rkvdec_hevc_priv_tbl *tbl =3D hevc_ctx->priv_tbl.cpu; @@ -604,7 +604,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) */ if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) || (!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) { - dev_warn_ratelimited(rkvdec->dev, "Long and short term RPS not set\n"); + dev_warn_ratelimited(core->dev, "Long and short term RPS not set\n"); } else { rkvdec_hevc_assemble_hw_rps(&run, &tbl->rps, &hevc_ctx->st_cache); } @@ -613,10 +613,10 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) =20 rkvdec_run_postamble(ctx, &run.base); =20 - rkvdec_schedule_watchdog(rkvdec, hevc_ctx->regs.common.reg032_timeout_thr= eshold); + rkvdec_schedule_watchdog(core, hevc_ctx->regs.common.reg032_timeout_thres= hold); =20 /* Start decoding! */ - writel(VDPU381_DEC_E_BIT, rkvdec->regs + VDPU381_REG_DEC_E); + writel(VDPU381_DEC_E_BIT, ctx->core->regs + VDPU381_REG_DEC_E); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c b= /drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c index fb4f849d7366..f3a1c31d84d3 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-h264.c @@ -291,19 +291,19 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, =20 static void rkvdec_write_regs(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; =20 - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_REGS, &h264_ctx->regs.common, sizeof(h264_ctx->regs.common)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_ADDR_REGS, &h264_ctx->regs.common_addr, sizeof(h264_ctx->regs.common_addr)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS, &h264_ctx->regs.h26x_params, sizeof(h264_ctx->regs.h26x_params)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_ADDR_REGS, &h264_ctx->regs.h26x_addr, sizeof(h264_ctx->regs.h26x_addr)); } @@ -455,7 +455,7 @@ static int rkvdec_h264_start(struct rkvdec_ctx *ctx) if (!h264_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &h264_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -481,7 +481,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, h264_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, h264_ctx->priv_tbl.size, h264_ctx->priv_tbl.cpu, h264_ctx->priv_tbl.dma); kfree(h264_ctx); } @@ -489,7 +489,7 @@ static void rkvdec_h264_stop(struct rkvdec_ctx *ctx) static int rkvdec_h264_run(struct rkvdec_ctx *ctx) { struct v4l2_h264_reflist_builder reflist_builder; - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_h264_ctx *h264_ctx =3D ctx->priv; struct rkvdec_h264_run run; struct rkvdec_h264_priv_tbl *tbl =3D h264_ctx->priv_tbl.cpu; @@ -514,12 +514,12 @@ static int rkvdec_h264_run(struct rkvdec_ctx *ctx) rkvdec_run_postamble(ctx, &run.base); =20 timeout_threshold =3D h264_ctx->regs.common.reg013_core_timeout_threshold; - rkvdec_schedule_watchdog(rkvdec, timeout_threshold); + rkvdec_schedule_watchdog(core, timeout_threshold); =20 /* Start decoding! */ - writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD); - writel(0, rkvdec->link + VDPU383_LINK_IP_ENABLE); - writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE); + writel(timeout_threshold, core->link + VDPU383_LINK_TIMEOUT_THRESHOLD); + writel(0, core->link + VDPU383_LINK_IP_ENABLE); + writel(VDPU383_DEC_E_BIT, core->link + VDPU383_LINK_DEC_ENABLE); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c b= /drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c index 96d938ee70b0..5170ca35fd90 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vdpu383-hevc.c @@ -381,19 +381,19 @@ static void assemble_hw_pps(struct rkvdec_ctx *ctx, =20 static void rkvdec_write_regs(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_hevc_ctx *h265_ctx =3D ctx->priv; =20 - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_REGS, &h265_ctx->regs.common, sizeof(h265_ctx->regs.common)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_COMMON_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_COMMON_ADDR_REGS, &h265_ctx->regs.common_addr, sizeof(h265_ctx->regs.common_addr)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_PARAMS_REGS, &h265_ctx->regs.h26x_params, sizeof(h265_ctx->regs.h26x_params)); - rkvdec_memcpy_toio(rkvdec->regs + VDPU383_OFFSET_CODEC_ADDR_REGS, + rkvdec_memcpy_toio(core->regs + VDPU383_OFFSET_CODEC_ADDR_REGS, &h265_ctx->regs.h26x_addr, sizeof(h265_ctx->regs.h26x_addr)); } @@ -563,7 +563,7 @@ static int rkvdec_hevc_start(struct rkvdec_ctx *ctx) if (!hevc_ctx) return -ENOMEM; =20 - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &hevc_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -588,14 +588,14 @@ static void rkvdec_hevc_stop(struct rkvdec_ctx *ctx) struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, hevc_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, hevc_ctx->priv_tbl.size, hevc_ctx->priv_tbl.cpu, hevc_ctx->priv_tbl.dma); kfree(hevc_ctx); } =20 static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_hevc_run run; struct rkvdec_hevc_ctx *hevc_ctx =3D ctx->priv; struct rkvdec_hevc_priv_tbl *tbl =3D hevc_ctx->priv_tbl.cpu; @@ -610,7 +610,7 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) */ if ((!ctx->has_sps_lt_rps && run.sps->num_long_term_ref_pics_sps) || (!ctx->has_sps_st_rps && run.sps->num_short_term_ref_pic_sets)) { - dev_err_ratelimited(rkvdec->dev, "Long and short term RPS not set\n"); + dev_err_ratelimited(core->dev, "Long and short term RPS not set\n"); return -EINVAL; } =20 @@ -624,12 +624,12 @@ static int rkvdec_hevc_run(struct rkvdec_ctx *ctx) rkvdec_run_postamble(ctx, &run.base); =20 timeout_threshold =3D hevc_ctx->regs.common.reg013_core_timeout_threshold; - rkvdec_schedule_watchdog(rkvdec, timeout_threshold); + rkvdec_schedule_watchdog(core, timeout_threshold); =20 /* Start decoding! */ - writel(timeout_threshold, rkvdec->link + VDPU383_LINK_TIMEOUT_THRESHOLD); - writel(VDPU383_IP_CRU_MODE, rkvdec->link + VDPU383_LINK_IP_ENABLE); - writel(VDPU383_DEC_E_BIT, rkvdec->link + VDPU383_LINK_DEC_ENABLE); + writel(timeout_threshold, core->link + VDPU383_LINK_TIMEOUT_THRESHOLD); + writel(VDPU383_IP_CRU_MODE, core->link + VDPU383_LINK_IP_ENABLE); + writel(VDPU383_DEC_E_BIT, core->link + VDPU383_LINK_DEC_ENABLE); =20 return 0; } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c b/drivers/= media/platform/rockchip/rkvdec/rkvdec-vp9.c index 2751f5396ee8..0b7d6b29bcfa 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec-vp9.c @@ -482,6 +482,7 @@ static void config_registers(struct rkvdec_ctx *ctx, struct rkvdec_vp9_ctx *vp9_ctx =3D ctx->priv; struct rkvdec_regs *regs =3D &vp9_ctx->regs; const struct v4l2_vp9_segmentation *seg; + struct rkvdec_core *core =3D ctx->core; struct rkvdec_dev *rkvdec =3D ctx->dev; dma_addr_t addr; bool intra_only; @@ -657,18 +658,19 @@ static void config_registers(struct rkvdec_ctx *ctx, =20 regs->vp9.reg44.strmd_error_e =3D 0xe; =20 - rkvdec_memcpy_toio(rkvdec->regs, regs, + rkvdec_memcpy_toio(core->regs, regs, MIN(sizeof(*regs), sizeof(u32) * rkvdec->variant->num_regs)); } =20 static int validate_dec_params(struct rkvdec_ctx *ctx, const struct v4l2_ctrl_vp9_frame *dec_params) { + struct rkvdec_core *core =3D ctx->core; unsigned int aligned_width, aligned_height; =20 /* We only support profile 0. */ if (dec_params->profile !=3D 0) { - dev_err(ctx->dev->dev, "unsupported profile %d\n", + dev_err(core->dev, "unsupported profile %d\n", dec_params->profile); return -EINVAL; } @@ -682,7 +684,7 @@ static int validate_dec_params(struct rkvdec_ctx *ctx, */ if (aligned_width !=3D ctx->decoded_fmt.fmt.pix_mp.width || aligned_height !=3D ctx->decoded_fmt.fmt.pix_mp.height) { - dev_err(ctx->dev->dev, + dev_err(core->dev, "unexpected bitstream resolution %dx%d\n", dec_params->frame_width_minus_1 + 1, dec_params->frame_height_minus_1 + 1); @@ -768,6 +770,7 @@ static int rkvdec_vp9_run_preamble(struct rkvdec_ctx *c= tx, =20 static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) { + struct rkvdec_core *core =3D ctx->core; struct rkvdec_dev *rkvdec =3D ctx->dev; struct rkvdec_vp9_run run =3D { }; int ret; @@ -786,10 +789,10 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) =20 rkvdec_run_postamble(ctx, &run.base); =20 - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(2000)); + schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(2000)); =20 - writel(1, rkvdec->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); - writel(1, rkvdec->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_LUMA_CACHE_COMMAND); + writel(1, core->regs + RKVDEC_REG_PREF_CHR_CACHE_COMMAND); =20 if (rkvdec->variant->quirks & RKVDEC_QUIRK_DISABLE_QOS) rkvdec_quirks_disable_qos(ctx); @@ -797,7 +800,7 @@ static int rkvdec_vp9_run(struct rkvdec_ctx *ctx) /* Start decoding! */ writel(RKVDEC_INTERRUPT_DEC_E | RKVDEC_CONFIG_DEC_CLK_GATE_E | RKVDEC_TIMEOUT_E | RKVDEC_BUF_EMPTY_E, - rkvdec->regs + RKVDEC_REG_INTERRUPT); + core->regs + RKVDEC_REG_INTERRUPT); =20 return 0; } @@ -979,7 +982,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) ctx->priv =3D vp9_ctx; =20 BUILD_BUG_ON(sizeof(priv_tbl->probs) % 16); /* ensure probs size is 128-b= it aligned */ - priv_tbl =3D dma_alloc_coherent(rkvdec->dev, sizeof(*priv_tbl), + priv_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, sizeof(*priv_tbl), &vp9_ctx->priv_tbl.dma, GFP_KERNEL); if (!priv_tbl) { ret =3D -ENOMEM; @@ -989,7 +992,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) vp9_ctx->priv_tbl.size =3D sizeof(*priv_tbl); vp9_ctx->priv_tbl.cpu =3D priv_tbl; =20 - count_tbl =3D dma_alloc_coherent(rkvdec->dev, RKVDEC_VP9_COUNT_SIZE, + count_tbl =3D dma_alloc_coherent(rkvdec->main_core->dev, RKVDEC_VP9_COUNT= _SIZE, &vp9_ctx->count_tbl.dma, GFP_KERNEL); if (!count_tbl) { ret =3D -ENOMEM; @@ -1003,7 +1006,7 @@ static int rkvdec_vp9_start(struct rkvdec_ctx *ctx) return 0; =20 err_free_priv_tbl: - dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->priv_tbl.size, vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); =20 err_free_ctx: @@ -1016,9 +1019,9 @@ static void rkvdec_vp9_stop(struct rkvdec_ctx *ctx) struct rkvdec_vp9_ctx *vp9_ctx =3D ctx->priv; struct rkvdec_dev *rkvdec =3D ctx->dev; =20 - dma_free_coherent(rkvdec->dev, vp9_ctx->count_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->count_tbl.size, vp9_ctx->count_tbl.cpu, vp9_ctx->count_tbl.dma); - dma_free_coherent(rkvdec->dev, vp9_ctx->priv_tbl.size, + dma_free_coherent(rkvdec->main_core->dev, vp9_ctx->priv_tbl.size, vp9_ctx->priv_tbl.cpu, vp9_ctx->priv_tbl.dma); kfree(vp9_ctx); } diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.c index db2731af06cf..5667d625f016 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -655,11 +656,11 @@ static int rkvdec_querycap(struct file *file, void *p= riv, struct rkvdec_dev *rkvdec =3D video_drvdata(file); struct video_device *vdev =3D video_devdata(file); =20 - strscpy(cap->driver, rkvdec->dev->driver->name, + strscpy(cap->driver, rkvdec->main_core->dev->driver->name, sizeof(cap->driver)); strscpy(cap->card, vdev->name, sizeof(cap->card)); snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s", - rkvdec->dev->driver->name); + rkvdec->main_core->dev->driver->name); return 0; } =20 @@ -1026,8 +1027,6 @@ static void rkvdec_stop_streaming(struct vb2_queue *q) =20 if (desc->ops->stop) desc->ops->stop(ctx); - - rkvdec_free_rcb(ctx); } =20 rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR); @@ -1061,28 +1060,66 @@ static const struct media_device_ops rkvdec_media_o= ps =3D { .req_queue =3D v4l2_m2m_request_queue, }; =20 -static void rkvdec_job_finish_no_pm(struct rkvdec_ctx *ctx, - enum vb2_buffer_state result) +/** + * Return a core that is available for decoding or null if no core is foun= d. + * The caller should make sure to call release_core() when the core is no = longer needed. + */ +static struct rkvdec_core *acquire_core(struct rkvdec_dev *rkvdec, struct = rkvdec_ctx *ctx) +{ + struct rkvdec_core *core =3D NULL; + + guard(spinlock_irqsave)(&rkvdec->cores_lock); + + if (rkvdec->available_core_count) { + core =3D rkvdec->available_cores[--rkvdec->available_core_count]; + + // Set the current core's ctx to this ctx + core->curr_ctx =3D ctx; + } + + return core; +} + +/** + * Release the core to make it available for a next job. + */ +static void release_core(struct rkvdec_dev *rkvdec, struct rkvdec_core *co= re) +{ + guard(spinlock_irqsave)(&rkvdec->cores_lock); + + core->curr_ctx =3D NULL; + rkvdec->available_cores[rkvdec->available_core_count++] =3D core; +} + +static void rkvdec_buf_done_no_pm(struct rkvdec_ctx *ctx, + enum vb2_buffer_state result) { + struct v4l2_m2m_ctx *m2m_ctx =3D ctx->fh.m2m_ctx; + struct v4l2_m2m_dev *m2m_dev =3D m2m_ctx->m2m_dev; + if (ctx->coded_fmt_desc->ops->done) { struct vb2_v4l2_buffer *src_buf, *dst_buf; =20 - src_buf =3D v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx); - dst_buf =3D v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx); + src_buf =3D v4l2_m2m_next_src_buf(m2m_ctx); + dst_buf =3D v4l2_m2m_next_dst_buf(m2m_ctx); ctx->coded_fmt_desc->ops->done(ctx, src_buf, dst_buf, result); } =20 - v4l2_m2m_buf_done_and_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx, - result); + v4l2_m2m_buf_done_manual(m2m_dev, m2m_ctx, result); + + if (ctx->core) { + release_core(ctx->dev, ctx->core); + v4l2_m2m_try_schedule(m2m_ctx); + } } =20 -static void rkvdec_job_finish(struct rkvdec_ctx *ctx, - enum vb2_buffer_state result) +static void rkvdec_buf_done(struct rkvdec_ctx *ctx, + enum vb2_buffer_state result) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + pm_runtime_mark_last_busy(ctx->core->dev); + pm_runtime_put_autosuspend(ctx->core->dev); =20 - pm_runtime_put_autosuspend(rkvdec->dev); - rkvdec_job_finish_no_pm(ctx, result); + rkvdec_buf_done_no_pm(ctx, result); } =20 void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run) @@ -1112,14 +1149,14 @@ void rkvdec_run_postamble(struct rkvdec_ctx *ctx, s= truct rkvdec_run *run) =20 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; u32 reg; =20 /* Set undocumented swreg_block_gating_e field */ - reg =3D readl(rkvdec->regs + RKVDEC_REG_QOS_CTRL); + reg =3D readl(core->regs + RKVDEC_REG_QOS_CTRL); reg &=3D GENMASK(31, 16); reg |=3D 0xEFFF; - writel(reg, rkvdec->regs + RKVDEC_REG_QOS_CTRL); + writel(reg, core->regs + RKVDEC_REG_QOS_CTRL); } =20 void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len) @@ -1131,57 +1168,81 @@ void rkvdec_memcpy_toio(void __iomem *dst, void *sr= c, size_t len) #endif } =20 -void rkvdec_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_thres= hold) +void rkvdec_schedule_watchdog(struct rkvdec_core *core, u32 timeout_thresh= old) { /* Set watchdog at 2 times the hardware timeout threshold */ u32 watchdog_time; - unsigned long axi_rate =3D clk_get_rate(rkvdec->axi_clk); + unsigned long axi_rate =3D clk_get_rate(core->axi_clk); =20 if (axi_rate) watchdog_time =3D 2 * div_u64(1000 * (u64)timeout_threshold, axi_rate); else watchdog_time =3D 2000; =20 - schedule_delayed_work(&rkvdec->watchdog_work, msecs_to_jiffies(watchdog_t= ime)); + schedule_delayed_work(&core->watchdog_work, msecs_to_jiffies(watchdog_tim= e)); } =20 static void rkvdec_device_run(void *priv) { struct rkvdec_ctx *ctx =3D priv; - struct rkvdec_dev *rkvdec =3D ctx->dev; const struct rkvdec_coded_fmt_desc *desc =3D ctx->coded_fmt_desc; int ret; =20 if (WARN_ON(!desc)) - return; + goto finish; =20 - ret =3D pm_runtime_resume_and_get(rkvdec->dev); + ctx->core =3D acquire_core(ctx->dev, ctx); + if (!ctx->core) + goto finish; + + ret =3D pm_runtime_resume_and_get(ctx->core->dev); if (ret < 0) { - rkvdec_job_finish_no_pm(ctx, VB2_BUF_STATE_ERROR); - return; + rkvdec_buf_done_no_pm(ctx, VB2_BUF_STATE_ERROR); + goto finish; } =20 if (!rkvdec_rcb_buf_validate_size(ctx)) { - rkvdec_free_rcb(ctx); + rkvdec_free_rcb(ctx->core); =20 - ret =3D rkvdec_allocate_rcb(ctx, + ret =3D rkvdec_allocate_rcb(ctx->core, ctx->decoded_fmt.fmt.pix_mp.width, ctx->decoded_fmt.fmt.pix_mp.height, ctx->dev->variant->rcb_sizes, ctx->dev->variant->num_rcb_sizes); if (ret) { - rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); - return; + rkvdec_buf_done(ctx, VB2_BUF_STATE_ERROR); + goto finish; } } =20 ret =3D desc->ops->run(ctx); - if (ret) - rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); + if (ret) { + rkvdec_buf_done(ctx, VB2_BUF_STATE_ERROR); + goto finish; + } + +finish: + v4l2_m2m_job_finish(ctx->dev->m2m_dev, ctx->fh.m2m_ctx); +} + +static int rkvdec_job_ready(void *priv) +{ + struct rkvdec_ctx *ctx =3D priv; + struct rkvdec_dev *rkvdec =3D ctx->dev; + + guard(spinlock_irqsave)(&rkvdec->cores_lock); + + for (int i =3D 0; i < rkvdec->core_count; i++) { + if (rkvdec->cores[i].curr_ctx =3D=3D ctx) + return 0; + } + + return 1; } =20 static const struct v4l2_m2m_ops rkvdec_m2m_ops =3D { .device_run =3D rkvdec_device_run, + .job_ready =3D rkvdec_job_ready, }; =20 static int rkvdec_queue_init(void *priv, @@ -1340,10 +1401,11 @@ static const struct v4l2_file_operations rkvdec_fop= s =3D { static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec) { int ret; + struct device *dev =3D rkvdec->main_core->dev; =20 - ret =3D v4l2_device_register(rkvdec->dev, &rkvdec->v4l2_dev); + ret =3D v4l2_device_register(dev, &rkvdec->v4l2_dev); if (ret) { - dev_err(rkvdec->dev, "Failed to register V4L2 device\n"); + dev_err(dev, "Failed to register V4L2 device\n"); return ret; } =20 @@ -1354,7 +1416,7 @@ static int rkvdec_v4l2_init(struct rkvdec_dev *rkvdec) goto err_unregister_v4l2; } =20 - rkvdec->mdev.dev =3D rkvdec->dev; + rkvdec->mdev.dev =3D dev; strscpy(rkvdec->mdev.model, "rkvdec", sizeof(rkvdec->mdev.model)); strscpy(rkvdec->mdev.bus_info, "platform:rkvdec", sizeof(rkvdec->mdev.bus_info)); @@ -1420,9 +1482,9 @@ static void rkvdec_v4l2_cleanup(struct rkvdec_dev *rk= vdec) v4l2_device_unregister(&rkvdec->v4l2_dev); } =20 -static void rkvdec_iommu_restore(struct rkvdec_dev *rkvdec) +static void rkvdec_iommu_restore(struct rkvdec_core *core) { - if (rkvdec->empty_domain) { + if (core->empty_domain) { /* * To rewrite mapping into the attached IOMMU core, attach a new empty d= omain that * will program an empty table, then detach it to restore the default do= main and @@ -1430,42 +1492,42 @@ static void rkvdec_iommu_restore(struct rkvdec_dev = *rkvdec) * 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(rkvdec->empty_domain, rkvdec->dev); - iommu_detach_device(rkvdec->empty_domain, rkvdec->dev); + iommu_attach_device(core->empty_domain, core->dev); + iommu_detach_device(core->empty_domain, core->dev); } } =20 static irqreturn_t rk3399_irq_handler(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; enum vb2_buffer_state state; u32 status; =20 - status =3D readl(rkvdec->regs + RKVDEC_REG_INTERRUPT); - writel(0, rkvdec->regs + RKVDEC_REG_INTERRUPT); + status =3D readl(core->regs + RKVDEC_REG_INTERRUPT); + writel(0, core->regs + RKVDEC_REG_INTERRUPT); =20 if (status & RKVDEC_RDY_STA) { state =3D VB2_BUF_STATE_DONE; } else { state =3D VB2_BUF_STATE_ERROR; if (status & RKVDEC_SOFTRESET_RDY) - rkvdec_iommu_restore(rkvdec); + rkvdec_iommu_restore(core); } =20 - if (cancel_delayed_work(&rkvdec->watchdog_work)) - rkvdec_job_finish(ctx, state); + if (cancel_delayed_work(&core->watchdog_work)) + rkvdec_buf_done(ctx, state); =20 return IRQ_HANDLED; } =20 static irqreturn_t vdpu381_irq_handler(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; enum vb2_buffer_state state; u32 status; =20 - status =3D readl(rkvdec->regs + VDPU381_REG_STA_INT); - writel(0, rkvdec->regs + VDPU381_REG_STA_INT); + status =3D readl(core->regs + VDPU381_REG_STA_INT); + writel(0, core->regs + VDPU381_REG_STA_INT); =20 if (status & VDPU381_STA_INT_DEC_RDY_STA) { state =3D VB2_BUF_STATE_DONE; @@ -1474,47 +1536,50 @@ static irqreturn_t vdpu381_irq_handler(struct rkvde= c_ctx *ctx) if (status & (VDPU381_STA_INT_SOFTRESET_RDY | VDPU381_STA_INT_TIMEOUT | VDPU381_STA_INT_ERROR)) - rkvdec_iommu_restore(rkvdec); + rkvdec_iommu_restore(core); } =20 - if (cancel_delayed_work(&rkvdec->watchdog_work)) - rkvdec_job_finish(ctx, state); + if (cancel_delayed_work(&core->watchdog_work)) + rkvdec_buf_done(ctx, state); =20 return IRQ_HANDLED; } =20 static irqreturn_t vdpu383_irq_handler(struct rkvdec_ctx *ctx) { - struct rkvdec_dev *rkvdec =3D ctx->dev; + struct rkvdec_core *core =3D ctx->core; enum vb2_buffer_state state; u32 status; =20 - status =3D readl(rkvdec->link + VDPU383_LINK_STA_INT); - writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), rkvdec->link + VDPU383_LI= NK_STA_INT); + status =3D readl(core->link + VDPU383_LINK_STA_INT); + writel(FIELD_PREP_WM16(VDPU383_STA_INT_ALL, 0), core->link + VDPU383_LINK= _STA_INT); /* On vdpu383, the interrupts must be disabled */ writel(FIELD_PREP_WM16(VDPU383_INT_EN_IRQ | VDPU383_INT_EN_LINE_IRQ, 0), - rkvdec->link + VDPU383_LINK_INT_EN); + core->link + VDPU383_LINK_INT_EN); =20 if (status & VDPU383_STA_INT_DEC_RDY_STA) { state =3D VB2_BUF_STATE_DONE; } else { state =3D VB2_BUF_STATE_ERROR; - rkvdec_iommu_restore(rkvdec); + rkvdec_iommu_restore(core); } =20 - if (cancel_delayed_work(&rkvdec->watchdog_work)) - rkvdec_job_finish(ctx, state); + if (cancel_delayed_work(&core->watchdog_work)) + rkvdec_buf_done(ctx, state); =20 return IRQ_HANDLED; } =20 static irqreturn_t rkvdec_irq_handler(int irq, void *priv) { - struct rkvdec_dev *rkvdec =3D priv; - struct rkvdec_ctx *ctx =3D v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); - const struct rkvdec_variant *variant =3D rkvdec->variant; + irqreturn_t ret; + struct rkvdec_core *core =3D priv; + struct rkvdec_ctx *ctx =3D core->curr_ctx; + const struct rkvdec_variant *variant =3D ctx->dev->variant; + + ret =3D variant->ops->irq_handler(ctx); =20 - return variant->ops->irq_handler(ctx); + return ret; } =20 /* @@ -1591,62 +1656,19 @@ static void vdpu383_flatten_matrices(u8 *output, co= nst u8 *input, int matrices, =20 static void rkvdec_watchdog_func(struct work_struct *work) { - struct rkvdec_dev *rkvdec; + struct rkvdec_core *core; struct rkvdec_ctx *ctx; =20 - rkvdec =3D container_of(to_delayed_work(work), struct rkvdec_dev, + core =3D container_of(to_delayed_work(work), struct rkvdec_core, watchdog_work); - ctx =3D v4l2_m2m_get_curr_priv(rkvdec->m2m_dev); + ctx =3D core->curr_ctx; if (ctx) { - dev_err(rkvdec->dev, "Frame processing timed out!\n"); - writel(RKVDEC_IRQ_DIS, rkvdec->regs + RKVDEC_REG_INTERRUPT); - rkvdec_job_finish(ctx, VB2_BUF_STATE_ERROR); + dev_err(core->dev, "Frame processing timed out!\n"); + writel(RKVDEC_IRQ_DIS, core->regs + RKVDEC_REG_INTERRUPT); + rkvdec_buf_done(ctx, VB2_BUF_STATE_ERROR); } } =20 -/* - * Some SoCs, like RK3588 have multiple identical VDPU cores, but the - * kernel is currently missing support for multi-core handling. Exposing - * separate devices for each core to userspace is bad, since that does - * not allow scheduling tasks properly (and creates ABI). With this workar= ound - * the driver will only probe for the first core and early exit for the ot= her - * cores. Once the driver gains multi-core support, the same technique - * for detecting the first core can be used to cluster all cores together. - */ -static int rkvdec_disable_multicore(struct rkvdec_dev *rkvdec) -{ - struct device_node *node =3D NULL; - const char *compatible; - bool is_first_core; - int ret; - - /* Intentionally ignores the fallback strings */ - ret =3D of_property_read_string(rkvdec->dev->of_node, "compatible", &comp= atible); - if (ret) - return ret; - - /* The first compatible and available node found is considered the main c= ore */ - do { - node =3D of_find_compatible_node(node, NULL, compatible); - if (of_device_is_available(node)) - break; - } while (node); - - if (!node) - return -EINVAL; - - is_first_core =3D (rkvdec->dev->of_node =3D=3D node); - - of_node_put(node); - - if (!is_first_core) { - dev_info(rkvdec->dev, "missing multi-core support, ignoring this instanc= e\n"); - return -ENODEV; - } - - return 0; -} - static const struct rkvdec_variant_ops rk3399_variant_ops =3D { .irq_handler =3D rk3399_irq_handler, .colmv_size =3D rkvdec_colmv_size, @@ -1757,49 +1779,114 @@ static const struct of_device_id of_rkvdec_match[]= =3D { }; MODULE_DEVICE_TABLE(of, of_rkvdec_match); =20 +static struct rkvdec_dev *device_node_to_rkvdec(struct device_node *node) +{ + struct platform_device *pdev =3D of_find_device_by_node(node); + struct rkvdec_dev *rkvdec =3D NULL; + + if (!pdev) + return NULL; + + rkvdec =3D platform_get_drvdata(pdev); + + platform_device_put(pdev); + + return rkvdec; +} + +/* + * Probe a new core based on the given device. + * If it is the first probed core of the same compatible, a new rkvdec ins= tance is + * created and the core is added to it. + * If not, the core is added to the existing rkvdec instance. + */ +static struct rkvdec_dev *rkvdec_probe_get_first(struct device *dev) +{ + struct device_node *first_node =3D NULL; + struct rkvdec_dev *rkvdec =3D NULL; + const char *compatible; + bool is_first_core; + int ret =3D 0; + + /* Intentionally ignores the fallback strings */ + ret =3D of_property_read_string(dev->of_node, "compatible", &compatible); + if (ret) + return ERR_PTR(-EINVAL); + + /* The first compatible and available node found is considered the main c= ore */ + do { + first_node =3D of_find_compatible_node(first_node, NULL, compatible); + if (of_device_is_available(first_node)) + break; + } while (first_node); + + if (!first_node) + return ERR_PTR(-EINVAL); + + is_first_core =3D (dev->of_node =3D=3D first_node); + + if (is_first_core) { + of_node_put(first_node); + + rkvdec =3D devm_kzalloc(dev, sizeof(*rkvdec), GFP_KERNEL); + if (!rkvdec) + return ERR_PTR(-ENOMEM); + + rkvdec->variant =3D of_device_get_match_data(dev); + + mutex_init(&rkvdec->vdev_lock); + spin_lock_init(&rkvdec->cores_lock); + } else { + rkvdec =3D device_node_to_rkvdec(first_node); + of_node_put(first_node); + } + + return rkvdec; +} + static int rkvdec_probe(struct platform_device *pdev) { - const struct rkvdec_variant *variant; struct rkvdec_dev *rkvdec; + struct rkvdec_core *core; int ret, irq; =20 - variant =3D of_device_get_match_data(&pdev->dev); - if (!variant) - return -EINVAL; + rkvdec =3D rkvdec_probe_get_first(&pdev->dev); + if (IS_ERR(rkvdec)) + return PTR_ERR(rkvdec); =20 - rkvdec =3D devm_kzalloc(&pdev->dev, sizeof(*rkvdec), GFP_KERNEL); - if (!rkvdec) - return -ENOMEM; + core =3D &rkvdec->cores[rkvdec->core_count++]; =20 platform_set_drvdata(pdev, rkvdec); - rkvdec->dev =3D &pdev->dev; - rkvdec->variant =3D variant; - mutex_init(&rkvdec->vdev_lock); - INIT_DELAYED_WORK(&rkvdec->watchdog_work, rkvdec_watchdog_func); - - ret =3D rkvdec_disable_multicore(rkvdec); - if (ret) - return ret; + core->dev =3D &pdev->dev; + INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func); =20 - ret =3D devm_clk_bulk_get_all_enabled(&pdev->dev, &rkvdec->clocks); + ret =3D devm_clk_bulk_get_all_enabled(&pdev->dev, &core->clocks); if (ret < 0) return ret; =20 - rkvdec->num_clocks =3D ret; - rkvdec->axi_clk =3D devm_clk_get(&pdev->dev, "axi"); + core->num_clocks =3D ret; + core->axi_clk =3D devm_clk_get(&pdev->dev, "axi"); =20 if (rkvdec->variant->has_single_reg_region) { - rkvdec->regs =3D devm_platform_ioremap_resource(pdev, 0); - if (IS_ERR(rkvdec->regs)) - return PTR_ERR(rkvdec->regs); + core->regs =3D devm_platform_ioremap_resource(pdev, 0); + if (IS_ERR(core->regs)) + return PTR_ERR(core->regs); } else { - rkvdec->regs =3D devm_platform_ioremap_resource_byname(pdev, "function"); - if (IS_ERR(rkvdec->regs)) - return PTR_ERR(rkvdec->regs); + core->regs =3D devm_platform_ioremap_resource_byname(pdev, "function"); + if (IS_ERR(core->regs)) + return PTR_ERR(core->regs); + + core->link =3D devm_platform_ioremap_resource_byname(pdev, "link"); + if (IS_ERR(core->link)) + return PTR_ERR(core->link); + } =20 - rkvdec->link =3D devm_platform_ioremap_resource_byname(pdev, "link"); - if (IS_ERR(rkvdec->link)) - return PTR_ERR(rkvdec->link); + core->iommu_domain =3D iommu_get_domain_for_dev(&pdev->dev); + if (core->iommu_domain) { + core->empty_domain =3D iommu_paging_domain_alloc(core->dev); + + if (!core->empty_domain) + dev_warn(core->dev, "cannot alloc new empty domain\n"); } =20 ret =3D dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); @@ -1816,42 +1903,41 @@ static int rkvdec_probe(struct platform_device *pde= v) =20 ret =3D devm_request_threaded_irq(&pdev->dev, irq, NULL, rkvdec_irq_handler, IRQF_ONESHOT, - dev_name(&pdev->dev), rkvdec); + dev_name(&pdev->dev), core); if (ret) { - dev_err(&pdev->dev, "Could not request vdec IRQ\n"); + dev_err(&pdev->dev, "Could not request core IRQ\n"); return ret; } =20 - rkvdec->sram_pool =3D of_gen_pool_get(pdev->dev.of_node, "sram", 0); - if (!rkvdec->sram_pool && rkvdec->variant->num_rcb_sizes > 0) + core->sram_pool =3D of_gen_pool_get(pdev->dev.of_node, "sram", 0); + if (!core->sram_pool && rkvdec->variant->num_rcb_sizes > 0) dev_info(&pdev->dev, "No sram node, RCB will be stored in RAM\n"); =20 pm_runtime_set_autosuspend_delay(&pdev->dev, 100); pm_runtime_use_autosuspend(&pdev->dev); pm_runtime_enable(&pdev->dev); =20 - ret =3D rkvdec_v4l2_init(rkvdec); - if (ret) - goto err_disable_runtime_pm; - - rkvdec->iommu_domain =3D iommu_get_domain_for_dev(&pdev->dev); - if (rkvdec->iommu_domain) { - rkvdec->empty_domain =3D iommu_paging_domain_alloc(rkvdec->dev); + /* Only init v4l2 for the first (main) core. */ + if (rkvdec->core_count =3D=3D 1) { + rkvdec->main_core =3D core; =20 - if (IS_ERR(rkvdec->empty_domain)) { - rkvdec->empty_domain =3D NULL; - dev_warn(rkvdec->dev, "cannot alloc new empty domain\n"); - } + ret =3D rkvdec_v4l2_init(rkvdec); + if (ret) + goto err_disable_runtime_pm; } =20 + release_core(rkvdec, core); + + dev_info(core->dev, "Registered core %d\n", core->id); + return 0; =20 err_disable_runtime_pm: pm_runtime_dont_use_autosuspend(&pdev->dev); pm_runtime_disable(&pdev->dev); =20 - if (rkvdec->sram_pool) - gen_pool_destroy(rkvdec->sram_pool); + if (core->sram_pool) + gen_pool_destroy(core->sram_pool); =20 return ret; } @@ -1859,30 +1945,50 @@ static int rkvdec_probe(struct platform_device *pde= v) static void rkvdec_remove(struct platform_device *pdev) { struct rkvdec_dev *rkvdec =3D platform_get_drvdata(pdev); + int i; =20 - cancel_delayed_work_sync(&rkvdec->watchdog_work); + for (i =3D 0; i < rkvdec->core_count; i++) + cancel_delayed_work_sync(&rkvdec->cores[i].watchdog_work); =20 rkvdec_v4l2_cleanup(rkvdec); - pm_runtime_disable(&pdev->dev); - pm_runtime_dont_use_autosuspend(&pdev->dev); =20 - if (rkvdec->empty_domain) - iommu_domain_free(rkvdec->empty_domain); + for (i =3D 0; i < rkvdec->core_count; i++) { + pm_runtime_disable(rkvdec->cores[i].dev); + pm_runtime_dont_use_autosuspend(rkvdec->cores[i].dev); + + if (rkvdec->cores[i].empty_domain) + iommu_domain_free(rkvdec->cores[i].empty_domain); + + rkvdec_free_rcb(&rkvdec->cores[i]); + } } =20 #ifdef CONFIG_PM static int rkvdec_runtime_resume(struct device *dev) { struct rkvdec_dev *rkvdec =3D dev_get_drvdata(dev); + int i, ret; =20 - return clk_bulk_prepare_enable(rkvdec->num_clocks, rkvdec->clocks); + for (i =3D 0; i < rkvdec->core_count; i++) { + ret =3D clk_bulk_prepare_enable(rkvdec->cores[i].num_clocks, + rkvdec->cores[i].clocks); + if (ret) + return ret; + } + + return 0; } =20 static int rkvdec_runtime_suspend(struct device *dev) { struct rkvdec_dev *rkvdec =3D dev_get_drvdata(dev); + int i; + + for (i =3D 0; i < rkvdec->core_count; i++) { + clk_bulk_disable_unprepare(rkvdec->cores[i].num_clocks, + rkvdec->cores[i].clocks); + } =20 - clk_bulk_disable_unprepare(rkvdec->num_clocks, rkvdec->clocks); return 0; } #endif diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.h index a24be6638b6b..4f042a367dc0 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.h +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.h @@ -15,6 +15,7 @@ #include #include #include +#include =20 #include #include @@ -125,23 +126,35 @@ struct rkvdec_coded_fmt_desc { u32 subsystem_flags; }; =20 -struct rkvdec_dev { - struct v4l2_device v4l2_dev; - struct media_device mdev; - struct video_device vdev; - struct v4l2_m2m_dev *m2m_dev; +struct rkvdec_core { struct device *dev; struct clk_bulk_data *clocks; unsigned int num_clocks; struct clk *axi_clk; void __iomem *regs; void __iomem *link; - struct mutex vdev_lock; /* serializes ioctls */ 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; + int id; +}; + +struct rkvdec_dev { + struct v4l2_device v4l2_dev; + struct media_device mdev; + struct video_device vdev; + struct v4l2_m2m_dev *m2m_dev; + struct mutex vdev_lock; /* serializes ioctls */ const struct rkvdec_variant *variant; + struct rkvdec_core cores[2]; + int core_count; + struct rkvdec_core *available_cores[2]; + unsigned int available_core_count; + spinlock_t cores_lock; /* serializes core list access */ + struct rkvdec_core *main_core; }; =20 struct rkvdec_ctx { @@ -152,8 +165,8 @@ struct rkvdec_ctx { struct v4l2_ctrl_handler ctrl_hdl; struct rkvdec_dev *dev; enum rkvdec_image_fmt image_fmt; - struct rkvdec_rcb_config *rcb_config; u32 colmv_offset; + struct rkvdec_core *core; void *priv; u8 has_sps_st_rps: 1; u8 has_sps_lt_rps: 1; @@ -179,7 +192,7 @@ struct rkvdec_aux_buf { void rkvdec_run_preamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); void rkvdec_run_postamble(struct rkvdec_ctx *ctx, struct rkvdec_run *run); void rkvdec_memcpy_toio(void __iomem *dst, void *src, size_t len); -void rkvdec_schedule_watchdog(struct rkvdec_dev *rkvdec, u32 timeout_thres= hold); +void rkvdec_schedule_watchdog(struct rkvdec_core *core, u32 timeout_thresh= old); =20 void rkvdec_quirks_disable_qos(struct rkvdec_ctx *ctx); =20 --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 9690B3D6CC5; Thu, 9 Apr 2026 13:51:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742703; cv=none; b=bQnQdALNtMeyHR3MF6g5l28X8pUye/53N2gLOuBoVV5uW4uejn04pc7cKxUnan5m+09BIMnhKlCW+6d6m0OxyVEbeNaqQOPJHxB1If0u5gJDy6o66bTBDgrVevKarxBtQa9u7FLdG1tHsJUMCunPrMs8OGfk3PIBSPtx+CoOozs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742703; c=relaxed/simple; bh=DMIweKgSOV3fIxZqhTvgTz9sRtOIz37xELaVKWgzSTk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=V6r3ibzKJyFxJm7y67gyRiHhaJy5uRSdXIlSDk+PVS06nRVu8j23ABFEFeQA0VOb80aUFy8OQYMbo/l6imtajv4hG33boRzldVvqBP/UpYEfAqHaU8EI3WaTGuaxpse7h+jOF3zSgyDYCSx9QAbeevyCi3YpeaqgZwvAe+o/OiE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=Ve14zFZ9; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="Ve14zFZ9" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742700; bh=DMIweKgSOV3fIxZqhTvgTz9sRtOIz37xELaVKWgzSTk=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=Ve14zFZ9i+yeRKHWwgsEz5P+v66JA7tDwkhMXZ8Aalp5WOttwW2F5W0TQZZewlpoJ t/kLOh5SFVIq5WxxuSXqVbF6yXe6HQBr0OOJQeJyxtMMZj95KtJlJQhy7j3KjXm7DA sGOp9IFCYRPFY0fbpcko5kapedROjNDeC1OzcGP1l8i/XQd/3maQ1+ECYIJtoCeRwn YQ+y3EkW+q36PQcIVx7+/Q0fP4EIITjFc0n+ojtaREikctWPozUstChODtV5+ALBRy KpkGnHQet7Phb9FTqzaju4OmfzE89sRE22rA1fkEHR0ZRjMKAMUkYlhNmsc0YJUx/q 3zgblwtSl+oJA== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id A9F4417E1380; Thu, 9 Apr 2026 15:51:38 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:41 -0400 Subject: [PATCH 6/7] media: rkvdec: Wait for all buffers before stop_streaming Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-6-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 Because the jobs are marked as finished before the buffer are marked as done, the stop_streaming callback can be called while the decoder is still running. This could even go further and deallocate buffers that are still being used by the hardware. Fortunately, to avoid that, the vb2_wait_for_all_buffers() function can be used at the beginning of the stop_streaming callback to make sure that cleanup functions are called after the last buffer has been returned to the queue. Signed-off-by: Detlev Casanova --- drivers/media/platform/rockchip/rkvdec/rkvdec.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.c b/drivers/medi= a/platform/rockchip/rkvdec/rkvdec.c index 5667d625f016..c2818f1575ef 100644 --- a/drivers/media/platform/rockchip/rkvdec/rkvdec.c +++ b/drivers/media/platform/rockchip/rkvdec/rkvdec.c @@ -1027,6 +1027,8 @@ static void rkvdec_stop_streaming(struct vb2_queue *q) =20 if (desc->ops->stop) desc->ops->stop(ctx); + + vb2_wait_for_all_buffers(q); } =20 rkvdec_queue_cleanup(q, VB2_BUF_STATE_ERROR); --=20 2.53.0 From nobody Sat Jun 20 23:07:24 2026 Received: from bali.collaboradmins.com (bali.collaboradmins.com [148.251.105.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 19A8136494C; Thu, 9 Apr 2026 13:51:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=148.251.105.195 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742709; cv=none; b=nRna39a1qJjmOmuf+72AchyC7rfxS9MWEF/f3nqphAIqdIm16u7e4J2p55v9DxAHmR3F9+Ov+QypyEE3mCdyG7dHw7sL3uoiFgOpNg4lHv39VJUlRdDsLBEfhatwu/H97E4kbmXtSnA/q6wffTDCd103xQaisyfdFDTC8nXtm8g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775742709; c=relaxed/simple; bh=MF7T/Jpkt7WSkcB4j1vMJJa1MuRvCoF8Hv7YRWQJ6sY=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=cKCT13/Gx+OQP8/zBUjlho4XAWAjG/yIdJebaxTlsl6vO8IVygyFiOZVepe3dqQctJaVVyIRYLY4hBOD/qQQBvg6T1aVo+9fS/4GZPzRTe4Vu6zO1d+MXOJXKwjyIUCLV5tlkBNhrGO4rHt8WORbn4kXZmUBd14kMNjekWM4TQ8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com; spf=pass smtp.mailfrom=collabora.com; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b=AkAW4qi0; arc=none smtp.client-ip=148.251.105.195 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=collabora.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=collabora.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=collabora.com header.i=@collabora.com header.b="AkAW4qi0" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=collabora.com; s=mail; t=1775742702; bh=MF7T/Jpkt7WSkcB4j1vMJJa1MuRvCoF8Hv7YRWQJ6sY=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=AkAW4qi0+/to1+Q3rWnzbjE1xvSl8XY/WbKSEGQIk7Up3CO6+JgEQ6phLN4ETzu1T 1vLM9B8MXBL7QYKQdu4JFvtVZ6b2SKdnzIPigiVxmYovseOlYrFaSlSqk4AyRpKvDo fzY7+L3QyJBMtd6MC0hvdyOCL9WXg7qIaiYDooQjia9013fgAmysoOkPtrHewvoTCX vPjdoLak+KNatg8/pkjzPgZ5t2Ynmc/YpM7uE7QIhTdOcuyS5ttRmPlH24CmAQtjTn UAtJlmpKewlEa1sK6DYgh5Znpuc9jQZgRJWtXZlbnS8QxzVrTxZHz+i/5tiNWW/dzY 4j9QcoaBhX//Q== Received: from [192.168.0.15] (unknown [100.64.0.170]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) (Authenticated sender: detlev) by bali.collaboradmins.com (Postfix) with ESMTPSA id 7A5FD17E138B; Thu, 9 Apr 2026 15:51:40 +0200 (CEST) From: Detlev Casanova Date: Thu, 09 Apr 2026 09:50:42 -0400 Subject: [PATCH 7/7] media: rkvdec: Add multicore IOMMU support Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20260409-rkvdec-multicore-v1-7-62b316abf0f7@collabora.com> References: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> In-Reply-To: <20260409-rkvdec-multicore-v1-0-62b316abf0f7@collabora.com> To: Mauro Carvalho Chehab , Ezequiel Garcia , Heiko Stuebner , Nicolas Dufresne , Hans Verkuil , Jonas Karlman 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 X-Mailer: b4 0.15.1 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 --- .../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; } =20 -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 =3D 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 =3D (unsigned long)cfg->rcb_bufs[i].cpu; =20 - 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 =3D NULL; } =20 -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height, +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *cor= e, + 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 w= idth, u32 height, =20 /* Try allocating an SRAM buffer */ if (core->sram_pool) { - if (core->iommu_domain) + if (rkvdec->iommu_global_domain) rcb_size =3D ALIGN(rcb_size, SZ_4K); =20 cpu =3D gen_pool_dma_zalloc_align(core->sram_pool, @@ -142,11 +143,11 @@ int rkvdec_allocate_rcb(struct rkvdec_core *core, u32= width, u32 height, } =20 /* 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 =3D (unsigned long)cpu; phys_addr_t phys_addr =3D dma; =20 - ret =3D iommu_map(core->iommu_domain, virt_addr, phys_addr, + ret =3D 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 w= idth, u32 height, ram_fallback: /* Fallback to RAM */ if (!cpu) { - cpu =3D dma_alloc_coherent(core->dev, + cpu =3D 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 w= idth, u32 height, return 0; =20 err_alloc: - rkvdec_free_rcb(core); + rkvdec_free_rcb(rkvdec, core); =20 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 @@ =20 #include =20 +struct rkvdec_dev; struct rkvdec_ctx; struct rkvdec_core; =20 @@ -21,11 +22,12 @@ struct rcb_size_info { enum rcb_axis axis; }; =20 -int rkvdec_allocate_rcb(struct rkvdec_core *core, u32 width, u32 height, +int rkvdec_allocate_rcb(struct rkvdec_dev *rkvdec, struct rkvdec_core *cor= e, + 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/medi= a/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) } =20 if (!rkvdec_rcb_buf_validate_size(ctx)) { - rkvdec_free_rcb(ctx->core); + rkvdec_free_rcb(ctx->dev, ctx->core); =20 - ret =3D rkvdec_allocate_rcb(ctx->core, + ret =3D 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 *rk= vdec) =20 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 d= omain 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 =3D 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 =3D iommu_attach_device(core->curr_ctx->dev->iommu_global_domain, co= re->dev); + if (ret) + dev_warn(core->dev, "Cannot attach global domain: %d\n", ret); } } =20 @@ -1858,6 +1865,8 @@ static int rkvdec_probe(struct platform_device *pdev) =20 core =3D &rkvdec->cores[rkvdec->core_count++]; =20 + core->id =3D rkvdec->core_count - 1; + platform_set_drvdata(pdev, rkvdec); core->dev =3D &pdev->dev; INIT_DELAYED_WORK(&core->watchdog_work, rkvdec_watchdog_func); @@ -1883,12 +1892,24 @@ static int rkvdec_probe(struct platform_device *pde= v) return PTR_ERR(core->link); } =20 - core->iommu_domain =3D iommu_get_domain_for_dev(&pdev->dev); - if (core->iommu_domain) { + if (iommu_get_domain_for_dev(&pdev->dev)) { core->empty_domain =3D iommu_paging_domain_alloc(core->dev); =20 - 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 =3D iommu_get_domain_for_dev(core->dev); + + if (IS_ERR(rkvdec->iommu_global_domain)) { + rkvdec->iommu_global_domain =3D NULL; + dev_warn_once(core->dev, "cannot alloc new global domain\n"); + } + } + + ret =3D iommu_attach_device(rkvdec->iommu_global_domain, core->dev); + if (ret) + dev_warn(core->dev, "cannot attach global domain to core %d\n", core->i= d); } =20 ret =3D dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32)); @@ -1961,7 +1982,7 @@ static void rkvdec_remove(struct platform_device *pde= v) if (rkvdec->cores[i].empty_domain) iommu_domain_free(rkvdec->cores[i].empty_domain); =20 - rkvdec_free_rcb(&rkvdec->cores[i]); + rkvdec_free_rcb(rkvdec, &rkvdec->cores[i]); } } =20 diff --git a/drivers/media/platform/rockchip/rkvdec/rkvdec.h b/drivers/medi= a/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; }; =20 struct rkvdec_ctx { --=20 2.53.0