From: sashiko-bot@kernel.org
To: "Ze Huang" <ze.huang@oss.qualcomm.com>
Cc: dri-devel@lists.freedesktop.org, imx@lists.linux.dev,
Frank.Li@kernel.org
Subject: Re: [PATCH 3/9] drm/imx: replace struct drm_simple_display_pipe with regular atomic helpers
Date: Sat, 04 Jul 2026 18:46:15 +0000 [thread overview]
Message-ID: <20260704184616.117DE1F00A3A@smtp.kernel.org> (raw)
In-Reply-To: <20260705-drm-simple-kms-removal-v1-3-b4e1ca053623@oss.qualcomm.com>
Thank you for your contribution! Sashiko AI review found 6 potential issue(s) to consider:
New issues:
- [High] CRTC disable operations fail unconditionally due to early mode validation.
- [High] Plane atomic check rejects offline plane updates, breaking display disabling.
- [High] Missing drm_crtc_vblank_on() and drm_crtc_vblank_off() calls break vblank synchronization.
- [High] Missing .enable_vblank hook in drm_crtc_funcs causes kernel warnings and breaks vblank.
Pre-existing issues:
- [High] Racy direct state access in atomic callbacks leading to potential use-after-free.
- [High] Unbounded clock reference count leak on CRTC disable cycles.
--
commit 404ed5ff8b68b90a5ba44e0c6a32b76744948691
Author: Ze Huang <ze.huang@oss.qualcomm.com>
drm/imx: replace struct drm_simple_display_pipe with regular atomic helpers
This commit converts the i.MX LCDC driver to use explicit primary plane,
CRTC, and encoder objects instead of the simple display pipe helpers. It
retains the no-scaling plane checks and GEM framebuffer prepare callbacks,
adjusting hardware state only when a framebuffer is present.
> diff --git a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
> index c67fe80b8115e..f0c4c19f91166 100644
> --- a/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
> +++ b/drivers/gpu/drm/imx/lcdc/imx-lcdc.c
[ ... ]
> -static void imx_lcdc_update_hw_registers(struct drm_simple_display_pipe *pipe,
> +static void imx_lcdc_update_hw_registers(struct drm_crtc *crtc,
> struct drm_plane_state *old_state,
> bool mode_set)
> {
> - struct drm_crtc *crtc = &pipe->crtc;
> - struct drm_plane_state *new_state = pipe->plane.state;
> + struct drm_plane_state *new_state = crtc->primary->state;
[Severity: High]
This is a pre-existing issue, but does this direct state access create a race
condition?
In non-blocking atomic commits, the DRM core synchronously swaps these object
pointers before the asynchronous worker executes. If multiple commits are
queued, we might retrieve the state for a future commit instead of the
current one, which could lead to programming hardware with an unpinned or
incorrect framebuffer.
[ ... ]
> @@ -230,34 +231,34 @@ static void imx_lcdc_pipe_enable(struct drm_simple_display_pipe *pipe,
[ ... ]
> imx_lcdc_update_hw_registers(crtc, NULL, true);
>
> /* Enable VBLANK Interrupt */
> writel(INTR_EOF, lcdc->base + IMX21LCDC_LIER);
> }
[Severity: High]
Should drm_crtc_vblank_on() be called here?
Without notifying the DRM core that the hardware vblank interrupt is enabled,
the core might consider the vblank state as off. This causes vblank waits to
fail unconditionally, forcing the plane atomic update to immediately send page
flip events to userspace rather than waiting for vsync.
[ ... ]
> -static void imx_lcdc_pipe_disable(struct drm_simple_display_pipe *pipe)
> +static void imx_lcdc_crtc_helper_atomic_disable(struct drm_crtc *crtc,
> + struct drm_atomic_commit *state)
> {
> - struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(pipe->crtc.dev);
> - struct drm_crtc *crtc = &lcdc->pipe.crtc;
> + struct imx_lcdc *lcdc = imx_lcdc_from_drmdev(crtc->dev);
> struct drm_pending_vblank_event *event;
>
> clk_disable_unprepare(lcdc->clk_ahb);
> clk_disable_unprepare(lcdc->clk_ipg);
>
> - if (pipe->crtc.enabled)
> + if (crtc->enabled)
> clk_disable_unprepare(lcdc->clk_per);
[Severity: High]
This is a pre-existing issue, but does this leak a clock reference?
The atomic_disable callback runs after the DRM core updates legacy state
variables, so crtc->enabled is guaranteed to be false here. This means the
clock might never be disabled during a DPMS cycle.
[ ... ]
> spin_unlock_irq(&lcdc->drm.event_lock);
>
> /* Disable VBLANK Interrupt */
> writel(0, lcdc->base + IMX21LCDC_LIER);
> }
[Severity: High]
Is a call to drm_crtc_vblank_off() needed here to synchronously disable vblank
processing in the DRM core when shutting down the hardware interrupt?
[ ... ]
> -static int imx_lcdc_pipe_check(struct drm_simple_display_pipe *pipe,
> - struct drm_plane_state *plane_state,
> - struct drm_crtc_state *crtc_state)
> +static int imx_lcdc_crtc_helper_atomic_check(struct drm_crtc *crtc,
> + struct drm_atomic_commit *state)
> {
> + struct drm_crtc_state *crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> const struct drm_display_mode *mode = &crtc_state->mode;
> - const struct drm_display_mode *old_mode = &pipe->crtc.state->mode;
> + const struct drm_display_mode *old_mode = &crtc->state->mode;
> + int ret;
>
> if (mode->hdisplay < LCDC_MIN_XRES || mode->hdisplay > LCDC_MAX_XRES ||
> mode->vdisplay < LCDC_MIN_YRES || mode->vdisplay > LCDC_MAX_YRES ||
> mode->hdisplay % 0x10) { /* must be multiple of 16 */
[Severity: High]
Will this cause CRTC disable operations to fail?
When userspace disables the CRTC (like via DPMS OFF), crtc_state->enable is
false and the display mode might be zeroed out. Validating the mode dimensions
before checking crtc_state->enable could cause this check to return -EINVAL
unconditionally.
[ ... ]
> -static void imx_lcdc_pipe_update(struct drm_simple_display_pipe *pipe,
> - struct drm_plane_state *old_state)
> +static void imx_lcdc_plane_helper_atomic_update(struct drm_plane *plane,
> + struct drm_atomic_commit *state)
> {
> - struct drm_crtc *crtc = &pipe->crtc;
> - struct drm_pending_vblank_event *event = crtc->state->event;
> - struct drm_plane_state *new_state = pipe->plane.state;
> + struct drm_plane_state *old_state = drm_atomic_get_old_plane_state(state, plane);
> + struct drm_plane_state *new_state = plane->state;
[Severity: High]
This is a pre-existing issue, but does assigning new_state directly from
plane->state risk a race condition?
For non-blocking commits, fetching the new plane state from the
drm_atomic_commit object avoids reading state from a potentially concurrent
future commit.
[ ... ]
> +static int imx_lcdc_plane_helper_atomic_check(struct drm_plane *plane,
> + struct drm_atomic_commit *state)
> +{
> + struct drm_plane_state *plane_state = drm_atomic_get_new_plane_state(state, plane);
> + struct drm_crtc *crtc = plane_state->crtc;
> + struct drm_crtc_state *crtc_state = NULL;
> + int ret;
> +
> + if (crtc)
> + crtc_state = drm_atomic_get_new_crtc_state(state, crtc);
> +
> + ret = drm_atomic_helper_check_plane_state(plane_state, crtc_state,
> + DRM_PLANE_NO_SCALING,
> + DRM_PLANE_NO_SCALING,
> + false, false);
[Severity: High]
Does passing false for the can_update_disabled parameter reject offline plane
updates?
If userspace tries to disable the CRTC without detaching the framebuffer, the
helper will see a plane on a disabled CRTC and return -EINVAL, which breaks
display disabling.
[ ... ]
> +static const struct drm_crtc_funcs imx_lcdc_crtc_funcs = {
> + .reset = drm_atomic_helper_crtc_reset,
> + .destroy = drm_crtc_cleanup,
> + .set_config = drm_atomic_helper_set_config,
> + .page_flip = drm_atomic_helper_page_flip,
> + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
[Severity: High]
Should this struct include implementations for .enable_vblank and
.disable_vblank?
When drm_vblank_get() is called to wait for vsync, the DRM core requires the
enable_vblank hook. Omitting these causes a kernel warning and makes the wait
return -EINVAL.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260705-drm-simple-kms-removal-v1-0-b4e1ca053623@oss.qualcomm.com?part=3
next prev parent reply other threads:[~2026-07-04 18:46 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-04 18:31 [PATCH 0/9] drm: replace simple display pipe users with atomic helpers Ze Huang
2026-07-04 18:31 ` [PATCH 1/9] drm/arcpgu: replace struct drm_simple_display_pipe with regular " Ze Huang
2026-07-04 18:43 ` sashiko-bot
2026-07-06 7:43 ` Thomas Zimmermann
2026-07-06 8:01 ` Thomas Zimmermann
2026-07-06 13:26 ` Ze Huang
2026-07-04 18:31 ` [PATCH 2/9] drm/aspeed: " Ze Huang
2026-07-04 18:52 ` sashiko-bot
2026-07-06 8:31 ` Thomas Zimmermann
2026-07-04 18:31 ` [PATCH 3/9] drm/imx: " Ze Huang
2026-07-04 18:46 ` sashiko-bot [this message]
2026-07-04 18:31 ` [PATCH 4/9] drm/mcde: " Ze Huang
2026-07-04 18:44 ` sashiko-bot
2026-07-04 18:31 ` [PATCH 5/9] drm/pl111: " Ze Huang
2026-07-04 18:45 ` sashiko-bot
2026-07-04 18:31 ` [PATCH 6/9] drm/gm12u320: " Ze Huang
2026-07-04 18:45 ` sashiko-bot
2026-07-04 18:31 ` [PATCH 7/9] drm/repaper: " Ze Huang
2026-07-04 18:31 ` [PATCH 8/9] drm/tve200: " Ze Huang
2026-07-04 18:46 ` sashiko-bot
2026-07-04 18:31 ` [PATCH 9/9] drm/xen: " Ze Huang
2026-07-04 18:53 ` sashiko-bot
2026-07-06 7:27 ` [PATCH 0/9] drm: replace simple display pipe users with " Thomas Zimmermann
2026-07-06 8:22 ` Ze Huang
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=20260704184616.117DE1F00A3A@smtp.kernel.org \
--to=sashiko-bot@kernel.org \
--cc=Frank.Li@kernel.org \
--cc=dri-devel@lists.freedesktop.org \
--cc=imx@lists.linux.dev \
--cc=sashiko-reviews@lists.linux.dev \
--cc=ze.huang@oss.qualcomm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox