Devicetree
 help / color / mirror / Atom feed
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

  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