From: sashiko-bot@kernel.org
To: "Arun Iyengar" <aiyengar1990@gmail.com>
Cc: devicetree@vger.kernel.org, robh@kernel.org, conor+dt@kernel.org,
media-ci@linuxtv.org
Subject: Re: [PATCH 4/5] media: verisilicon: Reinitialize the IOMMU after a timeout
Date: Tue, 10 Nov 2026 08:37:52 +0000 [thread overview]
Message-ID: <sashiko-outbox-206639@kernel.org> (raw)
In-Reply-To: <20261110-hantro-robust-v1-4-6b6269c05bfa@gmail.com>
Thank you for your contribution! Sashiko AI review found 6 potential
issues to consider:
- [High] media: verisilicon: failed attach in hantro_iommu_restore()
detaches IOMMU
- [High] media: verisilicon: race in hantro_iommu_restore() with
vsi_iommu_flush_tlb()
- [Medium] media: verisilicon: unconditional IOMMU domain swap in
hantro_iommu_restore()
- [Medium] media: verisilicon: hantro_watchdog() restores IOMMU without
stopping AV1 core
- [Medium] media: verisilicon: hantro_iommu_restore() fails with -EBUSY
on ARM32
- [Medium] media: verisilicon: check iommu_is_dma_domain() in
hantro_alloc_empty_domain()
--
commit 61759d53b32f194a0a0f3fec45e34dc338e8cad9
Author: Arun Iyengar <aiyengar1990@gmail.com>
media: verisilicon: Reinitialize the IOMMU after a timeout
This commit allocates an empty IOMMU paging domain at probe and attaches
and detaches it in hantro_watchdog() after a job timeout to reinitialize
the VPU IOMMU.
> diff --git a/drivers/media/platform/verisilicon/hantro_drv.c b/drivers/media/platform/verisilicon/hantro_drv.c
> index 702d878c7b509..c85c8f07db34d 100644
> --- a/drivers/media/platform/verisilicon/hantro_drv.c
> +++ b/drivers/media/platform/verisilicon/hantro_drv.c
[ ... ]
> @@ -112,6 +113,31 @@ void hantro_irq_done(struct hantro_dev *vpu,
> }
> }
>
> +/*
> + * A job that timed out can leave the IOMMU stalled, for instance on a page
> + * fault the core never recovered from, and a hardware reset of the core can
> + * leave the IOMMU state out of sync with its driver. Attach the empty domain
> + * and detach it again to return to the default DMA domain: the IOMMU driver
> + * then disables and fully reinitializes the IOMMU, which keeps all the
> + * mappings of the default domain.
> + */
> +static void hantro_iommu_restore(struct hantro_dev *vpu)
> +{
> + int ret;
> +
> + if (!vpu->empty_domain)
> + return;
> +
> + ret = iommu_attach_device(vpu->empty_domain, vpu->dev);
> + if (ret) {
> + dev_warn(vpu->dev, "Failed to attach the empty IOMMU domain: %d\n",
> + ret);
> + return;
> + }
[Severity: High]
Can a failed iommu_attach_device() here leave the Rockchip IOMMU
permanently detached from its default DMA domain?
Most Rockchip VPU device tree nodes lack reset lines and the decoder reset
callbacks only write registers, so a wedged core can keep AXI transactions
pending and cause rk_iommu_enable() to fail when attaching
vpu->empty_domain:
drivers/iommu/rockchip-iommu.c:rk_iommu_attach_device() {
...
ret = rk_iommu_identity_attach(&rk_identity_domain, dev, old);
if (ret)
return ret;
iommu->domain = domain;
...
ret = rk_iommu_enable(iommu);
if (ret) {
WARN_ON(rk_iommu_identity_attach(&rk_identity_domain, dev,
iommu->domain));
}
...
}
Because rk_iommu_attach_device() falls back to &rk_identity_domain while
__iommu_group_set_domain_internal() leaves group->domain as default_domain
without re-attaching the single group device, rk_iommu_resume() skips
rk_iommu_enable() on subsequent runtime PM cycles and the IOMMU stays in
identity bypass while DMA buffers still use default_domain IOVAs.
> +
> + iommu_detach_device(vpu->empty_domain, vpu->dev);
> +}
[Severity: High]
Can attaching and detaching vpu->empty_domain in hantro_iommu_restore()
race with concurrent DMA mappings on the RK3588 AV1 decoder and corrupt
list traversal in vsi_iommu_flush_tlb()?
hantro_watchdog() runs without vpu_mutex while V4L2 buffer ioctls (such as
VIDIOC_REQBUFS or VIDIOC_QBUF) map or unmap buffers on default_domain. On
rockchip,rk3588-av1-vpu (which sits behind verisilicon,iommu-1.2),
vsi_iommu_attach_device() moves iommu->node from default_domain->iommus to
empty_domain->iommus under empty_domain->lock without taking
default_domain->lock, while vsi_iommu_flush_tlb() drops iommu->lock before
advancing to the next entry:
CPU0 (hantro_watchdog) CPU1 (V4L2 buffer map/unmap)
hantro_iommu_restore() vsi_iommu_map()
lock(&default_domain->lock)
vsi_iommu_flush_tlb(default_domain)
list_for_each_entry(iommu,
&default_domain->iommus, node)
lock(&iommu->lock)
...
unlock(&iommu->lock)
iommu_attach_device(empty_domain)
vsi_iommu_attach_device()
lock(&empty_domain->lock)
lock(&iommu->lock)
list_del_init(&iommu->node)
list_add_tail(&iommu->node,
&empty_domain->iommus)
unlock(&iommu->lock)
unlock(&empty_domain->lock)
pm_runtime_put_autosuspend()
/* follows node.next into
* &empty_domain->iommus */
<-- out-of-bounds dereference
vsi_iommu_flush_tlb() misses the &default_domain->iommus loop termination
check and dereferences container_of(&empty_domain->iommus, struct
vsi_iommu, node) out of bounds.
>
> void hantro_watchdog(struct work_struct *work)
> {
> struct hantro_dev *vpu;
> @@ -124,6 +150,7 @@ void hantro_watchdog(struct work_struct *work)
> vpu_err("frame processing timed out!\n");
> if (ctx->codec_ops->reset)
> ctx->codec_ops->reset(ctx);
> + hantro_iommu_restore(vpu);
> hantro_job_finish(ctx, VB2_BUF_STATE_ERROR);
> }
> }
[Severity: Medium]
Does calling hantro_iommu_restore() when ctx->codec_ops->reset is NULL
switch the IOMMU to an empty page table while the RK3588 AV1 decoder core
is still running?
rk3588_vpu981_codec_ops[HANTRO_MODE_AV1_DEC] defines no .reset callback,
so on a timeout the AV1 core is neither stopped nor reset before
vsi_iommu_attach_device() programs an empty page table and flushes the TLB
while the core may still be issuing DMA transactions.
> @@ -1085,6 +1112,32 @@ static void hantro_reset_assert(struct hantro_dev *vpu)
> reset_control_assert(vpu->resets);
> }
>
> +static void hantro_free_empty_domain(void *data)
> +{
> + iommu_domain_free(data);
> +}
> +
> +static int hantro_alloc_empty_domain(struct hantro_dev *vpu)
> +{
> + struct iommu_domain *domain;
> +
> + if (!iommu_get_domain_for_dev(vpu->dev))
> + return 0;
> +
> + domain = iommu_paging_domain_alloc(vpu->dev);
[Severity: Medium]
Does allocating vpu->empty_domain for every Hantro device with an IOMMU
domain leak DMA mappings and clock enable references on Allwinner H6?
allwinner,sun50i-h6-vpu-g2 uses sun50i-iommu, where
sun50i_iommu_domain_alloc_paging() initializes sun50i_domain->refcnt to 1
and sun50i_iommu_attach_device() increments it to 2 before calling
sun50i_iommu_identity_attach():
drivers/iommu/sun50i-iommu.c:sun50i_iommu_attach_device() {
...
refcount_inc(&sun50i_domain->refcnt);
if (iommu->domain == domain)
return 0;
sun50i_iommu_identity_attach(&sun50i_iommu_identity_domain, dev, old);
sun50i_iommu_attach_domain(iommu, sun50i_domain);
return 0;
}
Because sun50i_iommu_identity_attach() only decrements refcnt from 2 to 1,
it never calls sun50i_iommu_detach_domain(), so each attach/detach cycle
in hantro_iommu_restore() calls sun50i_iommu_enable() twice without
disabling, leaking two dma_map_single() mappings and two
clk_prepare_enable() references per timeout (or failing with -EINVAL when
sibling devices share the singleton generic_single_device_group).
[Severity: Medium]
On 32-bit ARM platforms such as RK3288, does allocating vpu->empty_domain
cause iommu_attach_device() in hantro_iommu_restore() to fail with -EBUSY
on every timeout?
CONFIG_ROCKCHIP_IOMMU selects CONFIG_ARM_DMA_USE_IOMMU on 32-bit ARM,
where group->default_domain is forced to IOMMU_DOMAIN_IDENTITY while
arm_setup_iommu_dma_ops() attaches an unmanaged mapping->domain to
group->domain, causing __iommu_attach_group() to reject
iommu_attach_device(vpu->empty_domain, vpu->dev) with -EBUSY because
group->domain != group->default_domain.
[Severity: Medium]
What happens in hantro_iommu_restore() when the VPU is attached to an
IOMMU_DOMAIN_IDENTITY passthrough domain?
iommu_get_domain_for_dev() is still non-NULL in passthrough mode, so
hantro_iommu_restore() transiently enables empty paging on a device doing
direct DMA and then detaches back to group->default_domain; on RK3588 AV1,
that re-attaches the standalone static struct iommu_domain
vsi_identity_domain via vsi_iommu_identity_attach(), which passes it to
to_vsi_domain() and takes spin_lock_irqsave(&vsi_domain->lock, flags) on
out-of-bounds memory. Checking iommu_is_dma_domain() on the domain
returned by iommu_get_domain_for_dev(vpu->dev) in
hantro_alloc_empty_domain() would avoid allocating empty_domain for
identity and unmanaged ARM32 domains.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261110-hantro-robust-v1-0-6b6269c05bfa@gmail.com?part=4
next prev parent reply other threads:[~2026-11-10 8:37 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-10 7:17 [PATCH 0/5] media: verisilicon: Recover the Rockchip VPUs from faults and timeouts Arun Iyengar via B4 Relay
2026-11-10 7:17 ` [PATCH 1/5] dt-bindings: media: rockchip,rk3568-vepu: Add the reset lines Arun Iyengar via B4 Relay
2026-11-10 7:17 ` [PATCH 2/5] media: verisilicon: Don't hold a VPU behind an IOMMU in reset after remove Arun Iyengar via B4 Relay
2026-11-10 7:50 ` sashiko-bot
2026-11-10 7:17 ` [PATCH 3/5] media: verisilicon: Reset the Rockchip encoder cores on timeout Arun Iyengar via B4 Relay
2026-11-10 8:11 ` sashiko-bot
2026-11-10 7:17 ` [PATCH 4/5] media: verisilicon: Reinitialize the IOMMU after a timeout Arun Iyengar via B4 Relay
2026-11-10 8:37 ` sashiko-bot [this message]
2026-11-10 7:17 ` [PATCH 5/5] arm64: dts: rockchip: Add the reset lines of the RK3588 VEPU121 cores Arun Iyengar via B4 Relay
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-206639@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=aiyengar1990@gmail.com \
--cc=conor+dt@kernel.org \
--cc=devicetree@vger.kernel.org \
--cc=media-ci@linuxtv.org \
--cc=robh@kernel.org \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox