From: sashiko-bot@kernel.org
To: ukrainer8 <kolomiiec@gmail.com>, dri-devel@lists.freedesktop.org
Subject: Re: [PATCH v2] drm/radeon: retry UVD v1 init on failure after resume
Date: Tue, 20 Oct 2026 08:03:22 +0000 [thread overview]
Message-ID: <sashiko-outbox-178472@kernel.org> (raw)
In-Reply-To: <20261019144916.108589-1-kolomiiec@gmail.com>
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] drm/radeon: unclocked UVD MMIO in uvd_v1_0_init() when warm-up clocks fail
- [Medium] drm/radeon: excessive busy-wait and redundant unguarded warm-up in uvd_v1_0_init()
--
commit 6ca2d05b74a007ba26b71ef0af031a5857a4aa3e
Author: ukrainer8 <kolomiiec@gmail.com>
drm/radeon: retry UVD v1 init on failure after resume
This patch adds an unconditional warm-up cycle and a 3-attempt retry loop to
uvd_v1_0_init(), and increases the polling timeout in uvd_v1_0_ring_test() to
2 seconds to recover from UVD initialization failures after system resume.
Link: https://gitlab.freedesktop.org/drm/amd/-/issues/1867
Link: https://bugs.launchpad.net/bugs/1865130
> diff --git a/drivers/gpu/drm/radeon/uvd_v1_0.c b/drivers/gpu/drm/radeon/uvd_v1_0.c
> index 5e6607e16244b..79d3b8cd32388 100644
> --- a/drivers/gpu/drm/radeon/uvd_v1_0.c
> +++ b/drivers/gpu/drm/radeon/uvd_v1_0.c
> @@ -158,24 +158,58 @@ int uvd_v1_0_init(struct radeon_device *rdev)
> {
> struct radeon_ring *ring = &rdev->ring[R600_RING_TYPE_UVD_INDEX];
> uint32_t tmp;
> - int r;
> + int r, retry, clk_err;
>
> - /* raise clocks while booting up the VCPU */
> + /* warm-up: silently cycle the engine once (like the Windows driver),
> + * the first ring instance after resume is dead functionally */
> if (rdev->family < CHIP_RV740)
> radeon_set_uvd_clocks(rdev, 10000, 10000);
> else
> radeon_set_uvd_clocks(rdev, 53300, 40000);
> + uvd_v1_0_start(rdev);
> + uvd_v1_0_stop(rdev);
> + mdelay(20);
[Severity: High]
What happens in uvd_v1_0_init() if radeon_set_uvd_clocks() fails during this
warm-up block?
In the retry loop right below, the return value of radeon_set_uvd_clocks() is
saved in clk_err, and both uvd_v1_0_start() and uvd_v1_0_stop() are guarded by
!clk_err because MMIO accesses to an unclocked UVD block can cause a PCI bus
master abort and hard-hang the system.
Here in the warm-up block, the return value of radeon_set_uvd_clocks() is
ignored (for example, if radeon_uvd_send_upll_ctlreq(), sumo_set_uvd_clock(),
or cik_set_uvd_clock() returns -ETIMEDOUT, or radeon_uvd_calc_upll_dividers()
returns -EINVAL), and uvd_v1_0_start() and uvd_v1_0_stop() are called
unconditionally. Won't that immediately perform MMIO reads and writes to the
unclocked UVD registers (such as UVD_CGC_GATE, UVD_MASTINT_EN, UVD_LMI_CTRL2,
UVD_RB_ARB_CTRL, UVD_SOFT_RESET, and UVD_STATUS) before the guarded retry loop
is ever reached?
In addition, is this unconditional warm-up cycle necessary given that the
3-attempt retry loop below already stops UVD, delays 20 ms, and retries from
scratch when a failure occurs? Running the warm-up unconditionally on every
cold boot and healthy resume across all R600 through CIK GPUs adds ~200 ms of
busy-wait mdelay() overhead (programming UPLL, starting and stopping the VCPU,
waiting 20 ms, and then immediately reprogramming UPLL a second time on the
first retry iteration while clocks are already raised), and if the VCPU is
unresponsive, uvd_v1_0_start() busy-waits for ~10.2 seconds of mdelay() in
the warm-up before repeating it 3 more times in the retry loop (~40.8 seconds
total).
> +
> + /* after resume the first ring test can race with the hardware; retry */
> + for (retry = 0; retry < 3; retry++) {
> + /* raise clocks while booting up the VCPU */
> + if (rdev->family < CHIP_RV740)
> + clk_err = radeon_set_uvd_clocks(rdev, 10000, 10000);
> + else
> + clk_err = radeon_set_uvd_clocks(rdev, 53300, 40000);
> + r = clk_err;
> + if (r)
> + drm_warn(&rdev->ddev, "radeon: raising UVD clocks failed (%d), attempt %d\n",
> + r, retry + 1);
> +
> + if (!r) {
> + r = uvd_v1_0_start(rdev);
> + if (r)
> + drm_warn(&rdev->ddev, "radeon: starting UVD failed (%d), attempt %d\n",
> + r, retry + 1);
> + }
>
> - r = uvd_v1_0_start(rdev);
> - if (r)
> - goto done;
> + if (!r) {
> + ring->ready = true;
> + r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
> + if (r) {
> + ring->ready = false;
> + drm_warn(&rdev->ddev, "radeon: UVD ring test failed (%d), attempt %d\n",
> + r, retry + 1);
> + }
> + }
>
> - ring->ready = true;
> - r = radeon_ring_test(rdev, R600_RING_TYPE_UVD_INDEX, ring);
> - if (r) {
> - ring->ready = false;
> - goto done;
> + if (!r)
> + break;
> +
> + /* MMIO is only safe when the block is actually clocked */
> + if (!clk_err)
> + uvd_v1_0_stop(rdev);
> + if (retry < 2)
> + mdelay(20);
> }
> + if (r)
> + goto done;
>
> r = radeon_ring_lock(rdev, ring, 10);
> if (r) {
> @@ -421,7 +455,8 @@ void uvd_v1_0_stop(struct radeon_device *rdev)
> int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
> {
> uint32_t tmp = 0;
> - unsigned i;
> + /* after resume the ring buffer controller needs ~1.5-2s to settle */
> + unsigned i, timeout = 2000000;
> int r;
>
> WREG32(UVD_CONTEXT_ID, 0xCAFEDEAD);
> @@ -434,14 +469,14 @@ int uvd_v1_0_ring_test(struct radeon_device *rdev, struct radeon_ring *ring)
> radeon_ring_write(ring, PACKET0(UVD_CONTEXT_ID, 0));
> radeon_ring_write(ring, 0xDEADBEEF);
> radeon_ring_unlock_commit(rdev, ring, false);
> - for (i = 0; i < rdev->usec_timeout; i++) {
> + for (i = 0; i < timeout; i++) {
> tmp = RREG32(UVD_CONTEXT_ID);
> if (tmp == 0xDEADBEEF)
> break;
> udelay(1);
> }
[Severity: Medium]
Could replacing rdev->usec_timeout (100,000 usec) with a hardcoded timeout of
2,000,000 iterations in uvd_v1_0_ring_test() stall a CPU core for several
seconds per failed attempt?
Because uvd_v1_0_ring_test() has no early-exit condition on failure and only
fails after exhausting all loop iterations, any failed ring test attempt will
execute 2,000,000 iterations of synchronous PCIe MMIO RREG32(UVD_CONTEXT_ID)
plus udelay(1) in a non-sleeping busy-wait loop. Across 3 failed attempts in
uvd_v1_0_init(), this will busy-wait for 6 to 15+ seconds during boot, system
resume, or GPU reset.
Also, the comment here states that the ring buffer controller needs ~1.5-2s to
settle after resume, whereas the commit message states that the first ring
instance after resume is dead functionally, not by timeout, and only a full
stop+init cycle revives the engine. If a stop+init cycle is what revives the
engine, is widening the busy-wait poll window from 100 ms to 2000 ms needed?
>
> - if (i < rdev->usec_timeout) {
> + if (i < timeout) {
> drm_info(&rdev->ddev, "ring test on %d succeeded in %d usecs\n",
> ring->idx, i);
> } else {
့
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019144916.108589-1-kolomiiec@gmail.com?part=1
next prev parent reply other threads:[~2026-10-20 8:03 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 14:49 [PATCH v2] drm/radeon: retry UVD v1 init on failure after resume ukrainer8
2026-10-20 8:03 ` sashiko-bot [this message]
2026-10-21 13:29 ` Alex Deucher
2026-10-21 14:28 ` Christian König
2026-10-21 21:47 ` О К
2026-10-22 12:50 ` Christian König
2026-10-22 15:11 ` Alex Deucher
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-178472@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=kolomiiec@gmail.com \
--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