From: sashiko-bot@kernel.org
To: "Devarsh Thakkar" <devarsht@ti.com>
Cc: dri-devel@lists.freedesktop.org, devicetree@vger.kernel.org,
robh@kernel.org, conor+dt@kernel.org
Subject: Re: [PATCH v3 10/14] drm/solomon: ssd16xx: Expose session management as plane properties
Date: Mon, 19 Oct 2026 21:58:21 +0000 [thread overview]
Message-ID: <sashiko-outbox-178284@kernel.org> (raw)
In-Reply-To: <20261019213726.4145532-11-devarsht@ti.com>
Thank you for your contribution! Sashiko AI review found 5 potential issue(s) to consider:
- [High] drm/solomon: ssd16xx: lock inversion between device->lock and drm_dev_enter()
- [Medium] drm/solomon: ssd16xx: session properties not synced on disable or idle commits
- [Medium] drm/solomon: ssd16xx: disabling refresh_mode_init sets refresh_mode to -1
- [Medium] drm/solomon: ssd16xx: fast LUT preload missed or clobbered by session modes
- [Medium] drm/solomon: ssd16xx: runtime PM calls outside device->lock race with master_drop()
--
commit 96a2ccec634e73c5b82d2f3b3b5d2292c57d3429
Author: Devarsh Thakkar <devarsht@ti.com>
drm/solomon: ssd16xx: Expose session management as plane properties
This commit exposes the clear_on_init, clear_on_close, clear_on_disable, and
refresh_mode_init session management settings as DRM plane enum properties. It
also introduces a device mutex to serialize session state and panel access
between atomic commits and DRM master callbacks.
> diff --git a/drivers/gpu/drm/solomon/ssd16xx.c b/drivers/gpu/drm/solomon/ssd16xx.c
> index 6037717635a48..13bd825bf3f17 100644
> --- a/drivers/gpu/drm/solomon/ssd16xx.c
> +++ b/drivers/gpu/drm/solomon/ssd16xx.c
[ ... ]
> @@ -1576,6 +1664,24 @@ static int ssd16xx_plane_atomic_check(struct drm_plane *plane,
> false, false);
> }
>
> +/*
> + * Copy the session properties of a plane state into the device. Called from
> + * both crtc_atomic_enable() and plane_atomic_update(): the former runs first
> + * in a commit, so it must not rely on values only synced by the latter.
> + */
> +static void ssd16xx_sync_session_props(struct ssd16xx_device *device,
> + const struct ssd16xx_plane_state *ssd_state)
> +{
> + lockdep_assert_held(&device->lock);
> +
> + device->refresh_mode = ssd_state->refresh_mode;
> + device->color_mode = ssd_state->color_mode;
> + device->clear_on_init = ssd_state->clear_on_init;
> + device->clear_on_close = ssd_state->clear_on_close;
> + device->clear_on_disable = ssd_state->clear_on_disable;
> + device->refresh_mode_init = ssd_state->refresh_mode_init;
> +}
> +
> static void ssd16xx_plane_atomic_update(struct drm_plane *plane,
> struct drm_atomic_commit *state)
> {
> @@ -1619,6 +1725,8 @@ static void ssd16xx_plane_atomic_update(struct drm_plane *plane,
> drm_dbg(&device->drm, "plane_atomic_update: calling fb_dirty rect=(%d,%d)-(%d,%d)\n",
> rect.x1, rect.y1, rect.x2, rect.y2);
>
> + mutex_lock(&device->lock);
> +
> /* Diff refresh_mode against the plane's own previous state to see
> * whether fast LUT preload is needed.
> */
> @@ -1635,8 +1743,7 @@ static void ssd16xx_plane_atomic_update(struct drm_plane *plane,
> device->fast_lut_pending = false;
> }
>
> - device->refresh_mode = new_ssd->refresh_mode;
> - device->color_mode = new_ssd->color_mode;
> + ssd16xx_sync_session_props(device, new_ssd);
[Severity: Medium]
Can session property updates be missed when a commit has no framebuffer
damage, detaches the framebuffer, or occurs while the CRTC is inactive?
In ssd16xx_plane_atomic_update(), ssd16xx_sync_session_props() is called
after the early exits for a NULL framebuffer and empty damage:
if (!fb)
goto out_exit;
/* Nothing to draw: don't wake the panel up. */
if (!drm_atomic_helper_damage_merged(old_state, new_state, &rect))
goto out_exit;
In addition, drm_atomic_helper_commit_tail_rpm() passes
DRM_PLANE_COMMIT_ACTIVE_ONLY to drm_atomic_helper_commit_planes(), which
skips ssd16xx_plane_atomic_update() whenever the CRTC is inactive.
If userspace updates clear_on_close or clear_on_disable in a property-only
commit with no damage, while fb is NULL, or while the CRTC is disabled, will
ssd16xx_device retain the stale values when ssd16xx_drm_master_drop() or
ssd16xx_crtc_atomic_disable() later runs?
[Severity: Medium]
Does fast_lut_pending account for refresh_mode_init and the clear_on_*
session modes?
In ssd16xx_plane_atomic_update(), device->fast_lut_pending is computed from
old_ssd->refresh_mode and new_ssd->refresh_mode before device->refresh_mode
is overridden by device->refresh_mode_init:
if (old_ssd->refresh_mode != new_ssd->refresh_mode) {
if (new_ssd->refresh_mode == SSD16XX_REFRESH_FAST &&
old_ssd->refresh_mode != SSD16XX_REFRESH_FULL)
device->fast_lut_pending = true;
else
device->fast_lut_pending = false;
}
ssd16xx_sync_session_props(device, new_ssd);
saved_mode = device->refresh_mode;
saved_border_waveform_idx = device->border_waveform_update_idx;
if (device->init_refresh_pending) {
device->refresh_mode = device->refresh_mode_init;
device->border_waveform_update_idx = device->border_waveform_init_idx;
}
if (device->fast_lut_pending) {
ret = ssd16xx_preload_fast_lut(device);
...
device->fast_lut_pending = false;
}
If new_ssd->refresh_mode is SSD16XX_REFRESH_PARTIAL and refresh_mode_init is
set to fast, fast_lut_pending remains false and the first frame runs a fast
refresh (0xC7) without preloading the fast LUT. Conversely, if
new_ssd->refresh_mode transitions to SSD16XX_REFRESH_FAST while
refresh_mode_init is set to partial, ssd16xx_preload_fast_lut() runs and
clears fast_lut_pending before the init frame, which then runs a partial
refresh (0xFF) that overwrites the LUT in the controller, leaving subsequent
fast frames without the fast LUT.
Similarly, if clear_on_init, clear_on_disable, or clear_on_close is set to
fast, ssd16xx_clear_display() sends SSD1683_CTRL2_FAST_REFRESH without
preloading the fast LUT, and if clear_on_init is set to partial while
refresh_mode is fast, ssd16xx_clear_display_on_init() overwrites the LUT
loaded by ssd16xx_hw_init() without re-arming fast_lut_pending.
>
> /*
> * When refresh_mode_init was set, use the specified mode for this first
> @@ -1693,6 +1800,8 @@ static void ssd16xx_plane_atomic_update(struct drm_plane *plane,
> device->border_waveform_pending = true;
> }
>
> + mutex_unlock(&device->lock);
> +
> pm_runtime_mark_last_busy(device->drm.dev);
> pm_runtime_put_autosuspend(device->drm.dev);
>
> @@ -1754,6 +1863,8 @@ static void ssd16xx_crtc_atomic_disable(struct drm_crtc *crtc,
> if (!drm_dev_enter(&device->drm, &idx))
> return;
>
> + mutex_lock(&device->lock);
> +
> if (device->clear_on_disable < 0 || device->cleared_on_disable)
> goto out;
[Severity: Medium]
Should ssd16xx_crtc_atomic_disable() also sync the session properties from
the commit's new primary plane state before checking
device->clear_on_disable?
Because the driver uses drm_atomic_helper_commit_tail_rpm(),
drm_atomic_helper_commit_modeset_disables() runs
ssd16xx_crtc_atomic_disable() before drm_atomic_helper_commit_planes(), and
drm_atomic_helper_commit_planes() skips disabled CRTCs due to
DRM_PLANE_COMMIT_ACTIVE_ONLY. If userspace sets clear_on_disable or
clear_on_close in the same atomic commit that disables the CRTC,
ssd16xx_crtc_atomic_disable() and ssd16xx_drm_master_drop() will not see the
updated plane state.
>
> @@ -1775,6 +1886,7 @@ static void ssd16xx_crtc_atomic_disable(struct drm_crtc *crtc,
> device->cleared_on_disable = true;
> pm_runtime_put_sync_suspend(device->drm.dev);
> out:
> + mutex_unlock(&device->lock);
> drm_dev_exit(idx);
> }
>
> @@ -1782,6 +1894,8 @@ static void ssd16xx_crtc_atomic_enable(struct drm_crtc *crtc,
> struct drm_atomic_commit *state)
> {
> struct ssd16xx_device *device = crtc_to_ssd16xx_device(crtc);
> + struct drm_plane_state *new_plane_state =
> + drm_atomic_get_new_plane_state(state, &device->primary_plane);
> int ret, idx;
>
> if (!drm_dev_enter(&device->drm, &idx))
> @@ -1797,16 +1911,28 @@ static void ssd16xx_crtc_atomic_enable(struct drm_crtc *crtc,
> drm_dbg(&device->drm, "atomic_enable: %dx%d orientation=%u°\n",
> device->width, device->height, device->orientation);
>
> + /* Serialise hw_init and session-prop setup against master_drop(). */
> + mutex_lock(&device->lock);
> +
> if (!device->initialized) {
> ret = ssd16xx_hw_init(device);
> if (ret) {
> drm_err(&device->drm, "atomic_enable: hw_init failed: %d\n", ret);
> + mutex_unlock(&device->lock);
> pm_runtime_put_autosuspend(device->drm.dev);
> drm_dev_exit(idx);
> return;
> }
> device->initialized = true;
> }
> +
> + /*
> + * atomic_enable runs before plane_atomic_update, so pick up the session
> + * properties of this very commit instead of the previous one's.
> + */
> + if (new_plane_state)
> + ssd16xx_sync_session_props(device, to_ssd16xx_plane_state(new_plane_state));
[Severity: Medium]
Should ssd16xx_sync_session_props() be called before ssd16xx_hw_init() and
pm_runtime_resume_and_get()?
Inside ssd16xx_hw_init(), device->refresh_mode is checked to decide whether
to preload the fast LUT:
if (device->refresh_mode == SSD16XX_REFRESH_FAST) {
...
}
Because ssd16xx_hw_init() runs before ssd16xx_sync_session_props(), it reads
the previous commit's refresh_mode rather than the new plane state's
refresh_mode.
[Severity: Medium]
Additionally, in both ssd16xx_crtc_atomic_enable() and
ssd16xx_plane_atomic_update(), pm_runtime_resume_and_get() is called before
mutex_lock(&device->lock), and pm_runtime_put_autosuspend() is called after
mutex_unlock(&device->lock):
ret = pm_runtime_resume_and_get(device->drm.dev);
...
mutex_lock(&device->lock);
...
mutex_unlock(&device->lock);
pm_runtime_mark_last_busy(device->drm.dev);
pm_runtime_put_autosuspend(device->drm.dev);
When the panel is runtime-suspended, pm_runtime_resume_and_get()
synchronously runs ssd16xx_pm_runtime_resume() -> ssd16xx_hw_init() and sets
device->initialized = true without holding device->lock, racing with
ssd16xx_drm_master_drop(). Furthermore, if a nonblocking commit in
ssd16xx_plane_atomic_update() holds the runtime PM reference while waiting on
mutex_lock(&device->lock), ssd16xx_drm_master_drop()'s call to
pm_runtime_put_sync_suspend() will see usage_count > 0 and fail to suspend
the panel, and once ssd16xx_drm_master_drop() releases device->lock, the
unblocked ssd16xx_plane_atomic_update() will draw over the screen that
clear_on_close just cleared.
> +
> device->cleared_on_disable = false;
>
> /* Clear display on first app launch if configured */
> @@ -1826,6 +1952,8 @@ static void ssd16xx_crtc_atomic_enable(struct drm_crtc *crtc,
> device->init_refresh_pending = true;
> }
[Severity: Medium]
What happens when a client opens the DRM device and then sets the
refresh_mode_init plane property to disabled?
When the device is opened on a panel where refresh_mode_init >= 0 by default
(such as GDEY042T81, where default_refresh_mode_init is
SSD16XX_REFRESH_FULL), ssd16xx_drm_master_set() sets
device->init_refresh_pending = true before the client can change plane
properties:
if (device->refresh_mode_init >= 0)
device->init_refresh_pending = true;
If the client then sets refresh_mode_init to SSD16XX_SESSION_DISABLED (which
maps to internal value -1), ssd16xx_sync_session_props() sets
device->refresh_mode_init = -1, but neither ssd16xx_sync_session_props() nor
ssd16xx_crtc_atomic_enable() clears device->init_refresh_pending when
device->refresh_mode_init < 0.
When ssd16xx_plane_atomic_update() subsequently runs:
if (device->init_refresh_pending) {
device->refresh_mode = device->refresh_mode_init;
device->border_waveform_update_idx = device->border_waveform_init_idx;
}
device->refresh_mode is set to -1, causing ssd16xx_fb_dirty() to fall through
to the default partial refresh case with the init border waveform (and skip
3-color red buffer setup) instead of using the configured refresh_mode.
Conversely, if device->refresh_mode_init was -1 when ssd16xx_drm_master_set()
ran and the client enables refresh_mode_init in a plane update on an
already-active CRTC where ssd16xx_crtc_atomic_enable() does not run,
device->init_refresh_pending is never armed.
>
> + mutex_unlock(&device->lock);
> +
> pm_runtime_mark_last_busy(device->drm.dev);
> pm_runtime_put_autosuspend(device->drm.dev);
> drm_dev_exit(idx);
[ ... ]
> @@ -1963,6 +2140,12 @@ static void ssd16xx_drm_master_drop(struct drm_device *drm,
> struct ssd16xx_device *device = to_ssd16xx_device(drm);
> int ret, idx;
>
> + /*
> + * Not serialized against nonblocking commits by the DRM core (e.g. on
> + * DROP_MASTER), so hold the lock across the panel clear too.
> + */
> + guard(mutex)(&device->lock);
> +
> device->init_refresh_pending = false;
> device->first_clear_done = false;
[Severity: High]
Does acquiring device->lock before drm_dev_enter() in
ssd16xx_drm_master_drop() create a lock inversion with the atomic commit
callbacks?
In ssd16xx_drm_master_drop(), guard(mutex)(&device->lock) acquires
device->lock before calling drm_dev_enter(drm, &idx) (which acquires
drm_unplug_srcu):
guard(mutex)(&device->lock);
...
if (!drm_dev_enter(drm, &idx))
return;
However, ssd16xx_plane_atomic_update(), ssd16xx_crtc_atomic_disable(), and
ssd16xx_crtc_atomic_enable() all call drm_dev_enter(&device->drm, &idx)
before acquiring mutex_lock(&device->lock):
if (!drm_dev_enter(&device->drm, &idx))
return;
mutex_lock(&device->lock);
Will this reverse locking order between device->lock and drm_unplug_srcu
trigger a lockdep circular locking dependency warning when a client commits a
frame and then drops master with clear_on_close enabled?
>
[ ... ]
>
> --
> 2.34.1
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261019213726.4145532-1-devarsht@ti.com?part=10
next prev parent reply other threads:[~2026-10-19 21:58 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-19 21:37 [PATCH v3 00/14] Add DRM driver for Solomon SSD16xx e-paper display controllers Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 01/14] dt-bindings: vendor-prefixes: Add Dalian Good Display Co., Ltd Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 02/14] dt-bindings: display: Add Solomon SSD16xx e-paper controller Devarsh Thakkar
2026-10-20 8:34 ` Krzysztof Kozlowski
2026-10-19 21:37 ` [PATCH v3 03/14] dt-bindings: display: solomon,ssd16xx: Add Solomon SSD1677 controller Devarsh Thakkar
2026-10-19 21:44 ` sashiko-bot
2026-10-21 3:37 ` Rob Herring (Arm)
2026-10-19 21:37 ` [PATCH v3 04/14] drm/solomon: Add DRM driver for Solomon SSD16xx e-paper display controllers Devarsh Thakkar
2026-10-19 22:02 ` sashiko-bot
2026-10-19 21:37 ` [PATCH v3 05/14] drm/solomon: ssd16xx: Add clear_on_init/close/disable session management Devarsh Thakkar
2026-10-19 21:59 ` sashiko-bot
2026-10-19 21:37 ` [PATCH v3 06/14] drm/solomon: ssd16xx: Add support for Solomon SSD1677 controller Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 07/14] drm/solomon: ssd16xx: Add power management support Devarsh Thakkar
2026-10-19 21:57 ` sashiko-bot
2026-10-19 21:37 ` [PATCH v3 08/14] drm/solomon: ssd16xx: Expose refresh mode as plane property Devarsh Thakkar
2026-10-19 22:02 ` sashiko-bot
2026-10-19 21:37 ` [PATCH v3 09/14] drm/solomon: ssd16xx: Expose color " Devarsh Thakkar
2026-10-19 21:52 ` sashiko-bot
2026-10-19 21:37 ` [PATCH v3 10/14] drm/solomon: ssd16xx: Expose session management as plane properties Devarsh Thakkar
2026-10-19 21:58 ` sashiko-bot [this message]
2026-10-20 10:32 ` Markus Elfring
2026-10-19 21:37 ` [PATCH v3 11/14] drm/solomon: ssd16xx: support panels whose RAM X order is reversed Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 12/14] MAINTAINERS: Add entry for Solomon SSD16xx DRM driver Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 13/14] arm64: defconfig: Enable DRM_SSD16XX for AM62L3 EVM Devarsh Thakkar
2026-10-19 21:37 ` [PATCH v3 14/14] arm64: dts: ti: [DO_NOT_MERGE] Add AM62L3 EVM overlay for GDEY042T81 e-paper display Devarsh Thakkar
2026-10-19 21:59 ` sashiko-bot
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-178284@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=conor+dt@kernel.org \
--cc=devarsht@ti.com \
--cc=devicetree@vger.kernel.org \
--cc=dri-devel@lists.freedesktop.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