Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Cody Kang" <codykang.hk@gmail.com>
Cc: vkoul@kernel.org, dri-devel@lists.freedesktop.org,
	conor+dt@kernel.org, devicetree@vger.kernel.org,
	olteanv@gmail.com, linux-phy@lists.infradead.org,
	neil.armstrong@linaro.org, robh@kernel.org
Subject: Re: [PATCH v2 10/17] drm/spacemit: add Saturn DPU KMS pipeline
Date: Sun, 09 Aug 2026 13:35:28 +0000	[thread overview]
Message-ID: <20260809133529.9A5571F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260809-k3-display-v2-10-327d7910bf71@gmail.com>

Thank you for your contribution! Sashiko AI review found 9 potential issue(s) to consider:
- [Critical] Early return in atomic_disable due to drm_dev_enter skips hardware teardown and timer cancellation.
- [Critical] Permanent physical memory leak due to unbalanced page pinning in spacemit_dmmu_map.
- [High] Sleeping functions called from atomic context in CRTC atomic_enable and atomic_disable callbacks.
- [High] Plane atomic_update callback invokes sleeping GEM helpers.
- [High] Interrupt storm due to unhandled IRQ during device bind.
- [High] Race condition between IRQ synchronization and clock gating.
- [High] Memory leak of DRM device on component unbind.
- [High] Unconditional interrupt enable via spin_unlock_irq in atomic context.
- [High] Ignored return value of get_cl_rdma_buf leads to Use-After-Free of command list registers.
--

--- Patch [10]: [PATCH v2 10/17] drm/spacemit: add Saturn DPU KMS pipeline ---
commit f9572a94b08eefdd84a13496054fbc00b42837b7
Author: Cody Kang <codykang.hk@gmail.com>
Subject: drm/spacemit: add Saturn DPU KMS pipeline

Add the atomic KMS implementation on top of the hardware backend: one
CRTC and one primary plane per DPU instance. atomic_check validates
the plane rectangle 1:1 against the mode and sizes the per-channel FBC
line buffer; atomic commit builds the cmdlist batches, maps the
framebuffer through the DMMU and arms the cfg-ready handshake, with
vblank events driven from the DPU interrupt.

> diff --git a/drivers/gpu/drm/spacemit/spacemit_crtc.c b/drivers/gpu/drm/spacemit/spacemit_crtc.c
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_crtc.c

[ ... ]

> @@ -96,25 +96,25 @@ static void spacemit_crtc_atomic_enable(struct drm_crtc *crtc,
> 					struct drm_atomic_commit *old_state)
> {

[ ... ]

> 	if (unlikely(a_crtc->first_modeset)) {
> 		ret = reset_control_bulk_assert(ARRAY_SIZE(priv->pipe_resets),
> 						priv->pipe_resets);
> 		if (ret)
> 			dev_warn(a_crtc->dev,
> 				 "failed to assert resets: %d\n", ret);
> 		usleep_range(10000, 20000);
> 		a_crtc->first_modeset = false;
> 	}
> 
> 	if (!a_crtc->clocks_on) {
> 		dpu_pm_resume(a_crtc->dev);
> 		a_crtc->clocks_on = true;
> 
> 		/*
> 		 * The DPU must settle after reset deassert or CFG_RDY races
> 		 * the flush.
> 		 */
> 		usleep_range(10000, 20000);
> 	}

[Severity: High]
Could the usleep_range() calls cause system instability?

The DRM subsystem requires CRTC atomic_enable and atomic_disable callbacks to
execute in atomic context, where sleeping is strictly forbidden.

Because usleep_range() sleeps, calling it directly here violates the atomic
context constraints.

[ ... ]

> @@ -131,23 +129,20 @@ static void spacemit_crtc_atomic_disable(struct drm_crtc *crtc,
> 					 struct drm_atomic_commit *old_state)
> {
> 	struct spacemit_crtc *a_crtc = to_spacemit_crtc(crtc);
> 	struct drm_device *drm = a_crtc->crtc.dev;
> 	int idx;
> 
> 	if (!drm_dev_enter(drm, &idx))
> 		return;

[Severity: Critical]
Does checking drm_dev_enter() here inadvertently skip hardware teardown
during unbind?

During driver unbind, spacemit_drm_master_unbind() calls drm_dev_unregister(),
which sets the unplugged flag. It then calls drm_atomic_helper_shutdown(),
which invokes spacemit_crtc_atomic_disable().

Because the device is already marked unplugged, drm_dev_enter() evaluates to
false. This causes an immediate return, bypassing the timer cancellation
(which leaves a pending timer pointing to freed memory) and the VBLANK event
signaling (which can stall the teardown commit).

[ ... ]

> 	/*
> 	 * MMIO on a clock-gated DPU stalls the bus, so an in-flight handler
> 	 * must finish its status reads before dpu_pm_suspend() gates the
> 	 * clocks.
> 	 */
> 	if (a_crtc->irq_online > 0)
> 		synchronize_irq(a_crtc->irq_online);

[Severity: High]
Is it safe to call synchronize_irq() in atomic context?

This function can sleep, which violates the requirement that atomic_disable
callbacks execute in atomic context without sleeping.

> 	/*
> 	 * Nothing else cancels the watchdog; it would fire against freed state.
> 	 */
> 	timer_delete_sync(&a_crtc->cfg_rdy_timer);
> 
> 	/* Close the ISR's MMIO gate before the clocks actually stop. */
> 	a_crtc->clocks_on = false;
> 	dpu_pm_suspend(a_crtc->dev);

[Severity: High]
Might this sequence allow a new interrupt to slip in?

If synchronize_irq() completes, it only guarantees that in-flight handlers
have finished. Because a_crtc->clocks_on is still true when it returns, a
newly triggered interrupt could immediately enter the ISR.

Meanwhile, this thread continues, setting a_crtc->clocks_on to false and
calling dpu_pm_suspend() to gate the clocks. If the racing ISR attempts
MMIO reads on the clock-gated hardware, it could stall the system bus.

Additionally, does dpu_pm_suspend() sleep in this atomic context? It
invokes usleep_range() internally, which would violate the atomic_disable
constraints.

> 	spin_lock_irq(&drm->event_lock);
> 	if (crtc->state->event) {
> 		drm_crtc_send_vblank_event(crtc, crtc->state->event);
> 		crtc->state->event = NULL;
> 	}
> 	spin_unlock_irq(&drm->event_lock);

[Severity: High]
Will this unconditionally re-enable local interrupts?

Because spacemit_crtc_atomic_disable() executes in atomic context, the caller
might have already disabled interrupts. Calling spin_unlock_irq() re-enables
them unconditionally.

Would it be better to use spin_unlock_irqrestore() to preserve the original
CPU interrupt state?

[ ... ]

> @@ -467,20 +465,19 @@ static int spacemit_drm_master_bind(struct device *dev)
> {

[ ... ]

> 	kms = devm_drm_dev_alloc(dev, &spacemit_drm_drv,
> 				 struct spacemit_kms, drm);
> 	if (IS_ERR(kms))
> 		return PTR_ERR(kms);

[Severity: High]
Will this leak the DRM device structure on component unbind?

The KMS structure is allocated with devm_drm_dev_alloc() inside
spacemit_drm_master_bind(). The devm_* lifecycle is tied to the platform
device's probe and remove cycle, not the component bind and unbind cycle.

When spacemit_drm_master_unbind() is called, the DRM device is unregistered
but never freed because the platform device is not removed. A subsequent
re-bind would allocate a new instance, permanently leaking the old one along
with all drmm_* managed allocations.

[ ... ]

> 	enable_irq(priv->irq_online);
> 
> 	ret = drm_dev_register(drm, 0);

[Severity: High]
Could enabling the IRQ here lead to an interrupt storm?

At this point during bind, the hardware might not be fully reset and
a_crtc->clocks_on is still false. If a bootloader left the display pipeline
active, the hardware will continuously assert the interrupt.

When the ISR fires, it sees !a_crtc->clocks_on and immediately returns
IRQ_NONE without clearing the hardware interrupt status. This causes the
interrupt to fire repeatedly, potentially hanging the system.

> diff --git a/drivers/gpu/drm/spacemit/spacemit_planes.c b/drivers/gpu/drm/spacemit/spacemit_planes.c
> --- /dev/null
> +++ b/drivers/gpu/drm/spacemit/spacemit_planes.c

[ ... ]

> @@ -170,25 +170,24 @@ static void spacemit_plane_atomic_update(struct drm_plane *plane,
> 					 struct drm_atomic_commit *state)
> {

[ ... ]

> 	hwdev->get_cl_rdma_buf(a_crtc);

[Severity: High]
What happens if hwdev->get_cl_rdma_buf() fails here?

If the return value is ignored and it fails to allocate, a_crtc->cl_rdma could
remain uninitialized or retain a dangling pointer from a previous iteration.

Later, free_cmdlist_regs(a_crtc->cl_rdma) frees the pointer but does not set
it to NULL. If a subsequent plane update fails its allocation, it would
double-free the old pointer.

> 	hwdev->plane_update_hw_channel(plane);
> 
> 	/* Solid-fill layers have no RDMA and no page table */
> 	if (rdma_id < hwdev->rdma_nums && spacemit_pstate->mmu_tbl.va) {
> 		u8 tbu_id = rdma_id * 2;
> 
> 		ret = spacemit_dmmu_map(plane->state->fb,
> 					&spacemit_pstate->mmu_tbl, tbu_id,
> 					a_crtc->cl_rdma, plane);

[Severity: High]
Does this path invoke sleeping functions from atomic context?

The spacemit_plane_atomic_update() callback executes in atomic context.
However, it calls spacemit_dmmu_map(), which subsequently calls
drm_gem_shmem_get_pages_sgt().

The drm_gem_shmem_get_pages_sgt() helper acquires the pages_lock mutex and
can block for disk I/O or GFP_KERNEL allocations, which is unsafe in
atomic context. Should this mapping be deferred to the prepare_fb phase?

[Severity: Critical]
Is there a missing unpin for the pages acquired inside the mapping function?

Calling drm_gem_shmem_get_pages_sgt() retrieves the scatter-gather table
and implicitly pins the backing physical pages by incrementing the object's
pages_use_count.

Since this occurs on every plane atomic update, and there appears to be no
matching drm_gem_shmem_put_pages() call during cleanup, the pages_use_count
will continually inflate. This prevents the GEM SHMEM core from releasing the
physical pages when the framebuffer is destroyed, leading to a permanent
memory leak.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260809-k3-display-v2-0-327d7910bf71@gmail.com?part=10

  reply	other threads:[~2026-08-09 13:35 UTC|newest]

Thread overview: 27+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-09 13:14 [PATCH v2 00/17] drm/spacemit: add SpacemiT K3 display support Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 01/17] dt-bindings: display: spacemit: add K3 Saturn DPU controller Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 02/17] dt-bindings: phy: add SpacemiT K3 Innosilicon DP PHY Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 03/17] dt-bindings: display: spacemit: add K3 Innosilicon DP/eDP controller Cody Kang via B4 Relay
2026-08-09 13:25   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 04/17] dt-bindings: soc: spacemit: allow eDP/DP PHY PLL pixel clocks on K3 APMU Cody Kang via B4 Relay
2026-08-09 20:57   ` Rob Herring (Arm)
2026-08-09 13:14 ` [PATCH v2 05/17] phy: spacemit: add Innosilicon DP TX PHY driver Cody Kang via B4 Relay
2026-08-09 13:26   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 06/17] clk: spacemit: k3: parent eDP/DP pixel clock to the PHY PLL Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 07/17] drm/spacemit: add Saturn DPU register model Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 08/17] drm/spacemit: add Saturn DPU core types, cmdlist and display MMU Cody Kang via B4 Relay
2026-08-09 13:32   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 09/17] drm/spacemit: add Saturn DPU hardware backend Cody Kang via B4 Relay
2026-08-09 13:31   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 10/17] drm/spacemit: add Saturn DPU KMS pipeline Cody Kang via B4 Relay
2026-08-09 13:35   ` sashiko-bot [this message]
2026-08-09 13:14 ` [PATCH v2 11/17] drm/spacemit: add Saturn DPU DRM device driver Cody Kang via B4 Relay
2026-08-09 13:35   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 12/17] drm/spacemit: add Innosilicon DP/eDP controller bridge driver Cody Kang via B4 Relay
2026-08-09 13:36   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 13/17] MAINTAINERS: add SpacemiT K3 display driver entry Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 14/17] riscv: dts: spacemit: k3: add display nodes Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 15/17] riscv: dts: spacemit: k3-pico-itx: enable the DisplayPort output Cody Kang via B4 Relay
2026-08-09 13:30   ` sashiko-bot
2026-08-09 13:14 ` [PATCH v2 16/17] riscv: dts: spacemit: k3-com260-ifx: " Cody Kang via B4 Relay
2026-08-09 13:14 ` [PATCH v2 17/17] riscv: defconfig: spacemit: k3: enable display driver Cody Kang 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=20260809133529.9A5571F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=codykang.hk@gmail.com \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=dri-devel@lists.freedesktop.org \
    --cc=linux-phy@lists.infradead.org \
    --cc=neil.armstrong@linaro.org \
    --cc=olteanv@gmail.com \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=vkoul@kernel.org \
    /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