Re: [PATCH v6] drm/omap: dsi: avoid sending bta sync all the time in writes

[email protected] Tue, 04 Aug 2026 08:52:32 +0000
Newsgroups org.freedesktop.lists.dri-devel
Message-ID <[email protected]>
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:

New issues:
- [High] Missing error interrupt registration causes a 500ms hang on transmission errors and leaves uncleared error state that corrupts subsequent transfers.

Pre-existing issues:
- [Critical] On-stack completion variable is vulnerable to a stack use-after-free because `dsi_unregister_isr_vc` does not synchronize with the lockless IRQ handler.
- [High] A TOCTOU race condition exists between the completion handler waking up the thread and the IRQ handler recording the hardware error, causing missed errors.
- [High] Integer overflow in the payload length check in `dsi_vc_send_long` allows bypassing FIFO size limits, leading to out-of-bounds memory reads.
--

--- Patch [1]: [PATCH v6] drm/omap: dsi: avoid sending bta sync all the time in writes ---
commit 22196015575a94cb0f42ab30e98b88108820f40e
Author: Andreas Kemnade <[email protected]>

drm/omap: dsi: avoid sending bta sync all the time in writes

Some chips need configuration commands to be sent first, before they can
send data. This patch avoids sending bta sync during writes if no acks
are requested, instead waiting for the packet to be sent.

Link: https://patch.msgid.link/[email protected]
Link: https://patch.msgid.link/[email protected]
Link: https://patch.msgid.link/[email protected]
Link: https://lore.gitlab.freedesktop.org/drm-ai-reviews/[email protected]/
Link: https://patch.msgid.link/[email protected]

> --- a/drivers/gpu/drm/omapdrm/dss/dsi.c
> +++ b/drivers/gpu/drm/omapdrm/dss/dsi.c
[ ... ]
> @@ -2194,28 +2191,45 @@ static int dsi_vc_send_null(struct dsi_data *dsi, int vc, int channel)
>  static int dsi_vc_write_common(struct omap_dss_device *dssdev, int vc,
>  			       const struct mipi_dsi_msg *msg)
>  {
> +	DECLARE_COMPLETION_ONSTACK(completion);
>  	struct dsi_data *dsi = to_dsi_data(dssdev);
> +	u32 err;
>  	int r;
>  
> +	/* wait for IRQ for packet transmission confirmation */
> +	r = dsi_register_isr_vc(dsi, vc, dsi_completion_handler,
> +				&completion, DSI_VC_IRQ_PACKET_SENT);
> +	if (r)
> +		return r;
> +
>  	if (mipi_dsi_packet_format_is_short(msg->type))
>  		r = dsi_vc_send_short(dsi, vc, msg);
>  	else
>  		r = dsi_vc_send_long(dsi, vc, msg);

[Severity: High]
This isn't a bug introduced by this patch, but does the payload length
check in dsi_vc_send_long() properly handle integer overflow?

In dsi_vc_send_long():

    if (dsi->vc[vc].tx_fifo_size * 32 * 4 < msg->tx_len + 4) {

If msg->tx_len is very large (e.g., near SIZE_MAX), msg->tx_len + 4 could
wrap around to a small number, evaluating the condition to false and
bypassing the safety check. Could this lead to out-of-bounds memory reads
from msg->tx_buf when the function iterates msg->tx_len >> 2 times?

>  
> -	if (r < 0)
> +	if ((!r) && wait_for_completion_timeout(&completion,
> +				msecs_to_jiffies(500)) == 0)
> +		r = -EIO;
> +
> +	dsi_unregister_isr_vc(dsi, vc, dsi_completion_handler,
> +			      &completion, DSI_VC_IRQ_PACKET_SENT);

[Severity: Critical]
This is a pre-existing issue, but does unregistering the ISR here leave us
vulnerable to a stack use-after-free?

If wait_for_completion_timeout() expires, the function proceeds to unregister
the ISR and return, which destroys the stack frame containing the completion
variable.

However, dsi_unregister_isr_vc() only removes the handler under a spinlock.
Concurrently, omap_dsi_irq_handler() creates a lockless copy:

omap_dsi_irq_handler()
    dsi_handle_isrs(&dsi->isr_tables_copy, ...);

If the interrupt fires just as the timeout expires, could the IRQ handler
execute dsi_completion_handler from its local copy and call complete() on
the now-dangling completion pointer?

> +	if (r)
>  		return r;

[Severity: High]
Is there a missing error interrupt registration for this new wait block?

When registering the ISR earlier in this function, only DSI_VC_IRQ_PACKET_SENT
is used, omitting DSI_IRQ_ERROR_MASK. If a hardware transmission error occurs
(e.g., sync lost), the packet is not sent and the PACKET_SENT interrupt never
fires.

Will this cause the thread to hang for 500ms and return -EIO early here?
Since it returns early, the new dsi_get_errors() cleanup block below is
bypassed. The global IRQ handler might still record the error in dsi->errors,
leaving it uncleared and falsely failing the next successful transfer.

>  
> -	/*
> -	 * TODO: we do not always have to do the BTA sync, for example
> -	 * we can improve performance by setting the update window
> -	 * information without sending BTA sync between the commands.
> -	 * In that case we can return early.
> -	 */
> +	/* TODO: find out if more needs to be done for MIPI_DSI_MSG_REQ_ACK */
>  
> -	r = dsi_vc_send_bta_sync(dssdev, vc);
> -	if (r) {
> -		DSSERR("bta sync failed\n");
> -		return r;
> +	if (msg->flags & MIPI_DSI_MSG_REQ_ACK) {
> +		r = dsi_vc_send_bta_sync(dssdev, vc);
> +		if (r) {
> +			DSSERR("bta sync failed\n");
> +			return r;
> +		}
> +	} else {
> +		err = dsi_get_errors(dsi);

[Severity: High]
This is a pre-existing issue, but is there a race condition between the
completion handler and the error state update?

If a packet completes but an error is simultaneously reported in the same IRQ,
omap_dsi_irq_handler() executes the ISRs before updating the global error
state:

omap_dsi_irq_handler()
    dsi_handle_isrs(...); // Calls complete(), waking the thread
    dsi_handle_irq_errors(...); // Updates dsi->errors

Can the awakened thread resume and read dsi->errors before the IRQ handler
updates it? This would cause dsi_get_errors() to read 0, missing the hardware
error, which might then falsely fail the next transmission.

-- 
Sashiko AI review ยท https://sashiko.dev/#/patchset/[email protected]?part=1