Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Tomi Valkeinen" <tomi.valkeinen@ideasonboard.com>
Cc: robh@kernel.org, conor+dt@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH v3 12/15] drm/tidss: oldi: Convert OLDI to an aux driver
Date: Fri, 29 May 2026 10:01:09 +0000	[thread overview]
Message-ID: <20260529100109.A84571F00893@smtp.kernel.org> (raw)
In-Reply-To: <20260529-beagley-ai-display-v3-12-7fefdc5d1adf@ideasonboard.com>

Thank you for your contribution! Sashiko AI review found 7 potential issue(s) to consider:

New issues:
- [High] Hardware is left powered on due to cancellation of asynchronous suspend during device removal.
- [High] The auxiliary driver can be unbound via sysfs, freeing the DRM bridge while it is still attached.
- [High] `device_link_add()` fails unconditionally because the consumer device is not yet registered.
- [High] Ignoring `pm_runtime_get_sync()` failure leads to unsafe hardware access on unpowered registers.
- [Medium] Device tree node reference leak when `auxiliary_device_init()` fails.
- [Medium] Missing `pm_runtime_mark_last_busy()` before `pm_runtime_put_autosuspend()` causes immediate suspend.

Pre-existing issues:
- [High] Out-of-bounds write to `tidss->oldis` array due to missing bounds check.
--

commit 73c9b05b12dc4ef6e124725962ba5094aea8a043
Author: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Date:   Fri May 29 08:45:42 2026 +0000

drm/tidss: oldi: Convert OLDI to an aux driver

This patch converts the OLDI components from child devices parsed directly 
by tidss into auxiliary devices with their own auxiliary driver. This 
allows the driver framework to automatically manage the power domains 
associated with the OLDI nodes.

> diff --git a/drivers/gpu/drm/tidss/tidss_oldi.c b/drivers/gpu/drm/tidss/tidss_oldi.c
> index e925ddaa4fd6a..188f31b57c6a2 100644
> --- a/drivers/gpu/drm/tidss/tidss_oldi.c
> +++ b/drivers/gpu/drm/tidss/tidss_oldi.c

[ ... ]

> @@ -251,6 +259,8 @@ static void tidss_oldi_atomic_pre_enable(struct drm_bridge *bridge,
>  	if (oldi->link_type == OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK)
>  		return;
>  
> +	WARN_ON(pm_runtime_get_sync(oldi->dev) < 0);
> +

[Severity: High]
If pm_runtime_get_sync() fails and returns a negative error code, does this 
code continue without returning?

Proceeding to access hardware registers via tidss_oldi_config() on an 
unclocked or unpowered domain can cause bus timeouts or synchronous 
external aborts.

>  	connector = drm_atomic_get_new_connector_for_encoder(state,
>  							     bridge->encoder);
>  	if (WARN_ON(!connector))

[ ... ]

> @@ -296,6 +306,8 @@ static void tidss_oldi_atomic_post_disable(struct drm_bridge *bridge,
>  
>  	/* Clear OLDI Config */
>  	tidss_disable_oldi(oldi->tidss, oldi->parent_vp);
> +
> +	pm_runtime_put_autosuspend(oldi->dev);
>  }

[Severity: Medium]
Is pm_runtime_mark_last_busy() missing before the call to 
pm_runtime_put_autosuspend()?

Without updating the device's last busy timestamp, the PM core's autosuspend 
timer might see the time elapsed as greater than the 500ms delay and suspend 
the device immediately, bypassing the autosuspend window.

>  
>  #define MAX_INPUT_SEL_FORMATS	1

[ ... ]

> +static void tidss_oldi_remove(struct auxiliary_device *auxdev)
> +{
> +	struct tidss_oldi *oldi = auxiliary_get_drvdata(auxdev);
> +	struct tidss_device *tidss = oldi->tidss;
> +	struct device *dev = &auxdev->dev;
>  
> -	tidss->num_oldis = 0;
> +	pm_runtime_dont_use_autosuspend(dev);
> +	pm_runtime_disable(dev);

[Severity: High]
Does this leave the hardware powered on during unbind?

During driver unbind, tidss_remove() shuts down the display by calling 
drm_atomic_helper_shutdown(), which invokes tidss_oldi_atomic_post_disable() 
and schedules an asynchronous suspend via pm_runtime_put_autosuspend(). 

Immediately afterward, tidss_remove() triggers tidss_oldi_remove(), which 
calls pm_runtime_disable() here. The PM subsystem cancels pending 
asynchronous suspend work when pm_runtime_disable() is called, leaving the 
device indefinitely in the active state.

Would it be safer to flush the suspend work or use pm_runtime_put_sync() 
during shutdown?

> +
> +	if (oldi->link_type != OLDI_MODE_SECONDARY_DUAL_LINK) {
> +		drm_bridge_remove(&oldi->bridge);
> +
> +		tidss->is_ext_vp_clk[oldi->parent_vp] = false;
> +	}
> +
> +	clk_put(oldi->serial);
> +}
> +
> +static const struct auxiliary_device_id tidss_oldi_aux_id_table[] = {
> +	{ .name = "tidss.oldi" },
> +	{}
> +};
> +
> +static struct auxiliary_driver oldi_aux_driver = {
> +	.name = "oldi",
> +	.probe = tidss_oldi_probe,
> +	.remove = tidss_oldi_remove,
> +	.id_table = tidss_oldi_aux_id_table,
> +};

[Severity: High]
Can userspace independently unbind the auxiliary driver via sysfs and cause 
a use-after-free?

Unlike the main tidss driver, this auxiliary driver does not set 
suppress_bind_attrs = true on its driver struct. Unbinding the device through 
sysfs would trigger devres cleanup, freeing the struct tidss_oldi and the 
embedded drm_bridge.

Because the main tidss DRM device remains active, the KMS pipeline would 
retain pointers to the freed bridge, leading to memory corruption on the 
next atomic commit or teardown.

> +
> +static void tidss_oldi_aux_device_release(struct device *dev)
> +{

[ ... ]

> +	/*
> +	 * Create a device-link between the primary and the secondary, so that
> +	 * the secondary will be powered on when the primary is used.
> +	 */
> +	if (companion_auxdev) {
> +		link = device_link_add(&auxdev->dev, &companion_auxdev->dev,
> +				       DL_FLAG_PM_RUNTIME |
> +					       DL_FLAG_AUTOREMOVE_CONSUMER |
> +					       DL_FLAG_AUTOREMOVE_SUPPLIER);

[Severity: High]
Does this device_link_add() call unconditionally fail because the consumer 
device is not yet registered?

The device link core requires the consumer device to be registered with 
sysfs when the DL_FLAG_AUTOREMOVE_CONSUMER flag is used. At this point, 
auxdev has only been initialized via auxiliary_device_init(), and 
auxiliary_device_add() is not called until later in this function.

This would cause device_link_add() to return NULL, breaking dual-link OLDI 
setups.

> +		if (!link) {
> +			dev_err(tidss->dev,
> +				"device_link_add failed between primary and secondary OLDI\n");
> +			ret = -EINVAL;
> +			goto err_uninit_auxdev;
>  		}
> +	}
>  
> -		oldi->parent_vp = parent_vp;
> -		oldi->oldi_instance = oldi_instance;
> -		oldi->companion_instance = companion_instance;
> -		oldi->link_type = link_type;
> -		oldi->dev = tidss->dev;
> -		oldi->next_bridge = bridge;
> +	ret = auxiliary_device_add(auxdev);
> +	if (ret) {
> +		dev_err(tidss->dev, "OLDI auxiliary_device_add failed: %d\n",
> +			ret);
> +		goto err_link_del;
> +	}
>  
> -		/*
> -		 * Only the primary OLDI needs to reference the io-ctrl system
> -		 * registers, and the serial clock.
> -		 * We don't require a check for secondary OLDI in dual-link mode
> -		 * because the driver will not create a drm_bridge instance.
> -		 * But the driver will need to create a drm_bridge instance,
> -		 * for secondary OLDI in clone mode (once it is supported).
> -		 */
> -		if (link_type != OLDI_MODE_SECONDARY_CLONE_SINGLE_LINK) {
> -			oldi->io_ctrl = syscon_regmap_lookup_by_phandle(child,
> -									"ti,oldi-io-ctrl");
> -			if (IS_ERR(oldi->io_ctrl)) {
> -				ret = dev_err_probe(oldi->dev, PTR_ERR(oldi->io_ctrl),
> -						    "OLDI%u: syscon_regmap_lookup_by_phandle failed.\n",
> -						    oldi_instance);
> -				goto err_put_node;
> -			}
> +	tidss->oldis[tidss->num_oldis++] = auxdev;

[Severity: High]
This is a pre-existing issue, but can this cause an out-of-bounds write to 
the tidss->oldis array?

The oldis array in struct tidss_device has a fixed size of 
TIDSS_MAX_OLDI_TXES (2). The devices are appended here without a bounds 
check. If a malformed device tree provides more than two OLDI transmitter 
nodes, this could overwrite adjacent members like irq and irq_lock.

>  
> -		/* Register the bridge. */
> -		oldi->bridge.of_node = child;
> -		oldi->bridge.driver_private = oldi;
> +	return auxdev;
>  
> -		tidss->oldis[tidss->num_oldis++] = oldi;
> -		tidss->is_ext_vp_clk[oldi->parent_vp] = true;
> -		oldi->tidss = tidss;
> +err_link_del:
> +	if (link)
> +		device_link_del(link);
> +err_uninit_auxdev:
> +	auxiliary_device_uninit(auxdev);
> +	/* return here, as the rest are done in auxdev's release */
> +	return ERR_PTR(ret);
>  
> -		drm_bridge_add(&oldi->bridge);
> +err_free_auxdev:
> +	kfree(auxdev);
> +err_free_pdata:
> +	kfree(oldi_pdata);
> +err_free_ida:
> +	ida_free(&tidss_oldi_ida, oldi_aux_id);
>  
> -	of_node_put(child);
> -	of_node_put(oldi_parent);
> +	return ERR_PTR(ret);
> +}

[Severity: Medium]
Does this error path leak the OF node reference?

Earlier in this function, an OF node reference is explicitly acquired and 
assigned to auxdev->dev.of_node:

    .of_node = of_node_get(oldi_tx),

If auxiliary_device_init(auxdev) fails, the err_free_auxdev path frees the 
auxdev structure but does not call of_node_put(), permanently leaking the 
reference.

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260529-beagley-ai-display-v3-0-7fefdc5d1adf@ideasonboard.com?part=12

  reply	other threads:[~2026-05-29 10:01 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-29  8:45 [PATCH v3 00/15] drm/tidss: Add BeagleY-AI display support (and some more) Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 01/15] dt-bindings: display: ti: Move ti,am62l-dss binding to a new binding file Tomi Valkeinen
2026-05-29  8:59   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 02/15] dt-bindings: display: ti,am65x-dss: Simplify binding Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 03/15] dt-bindings: display: ti,am625-oldi: Add optional power-domain for OLDI Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 04/15] dt-bindings: display: ti,am65x-dss: Add ti,dpi-io-ctrl Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 05/15] dt-bindings: display: ti,am65x-dss: Add AM62P DSS Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 06/15] drm/tidss: Remove extra pm_runtime_mark_last_busy Tomi Valkeinen
2026-05-29  9:11   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 07/15] drm/tidss: oldi: Remove define for unused register OLDI_LB_CTRL Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 08/15] drm/tidss: Add mechanism to detect DPI output Tomi Valkeinen
2026-05-29  9:28   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 09/15] drm/tidss: Add external data and sync signal edge configuration Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 10/15] drm/tidss: Add support for DPIENABLE bit Tomi Valkeinen
2026-05-29  9:30   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 11/15] drm/tidss: oldi: Fix OLDI signal polarities Tomi Valkeinen
2026-05-29  9:37   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 12/15] drm/tidss: oldi: Convert OLDI to an aux driver Tomi Valkeinen
2026-05-29 10:01   ` sashiko-bot [this message]
2026-05-29  8:45 ` [PATCH v3 13/15] drm/tidss: Add support for AM62P display subsystem Tomi Valkeinen
2026-05-29  8:45 ` [PATCH v3 14/15] arm64: dts: ti: k3-am62p-j722s-common-main: Add support for DSS Tomi Valkeinen
2026-05-29  9:54   ` sashiko-bot
2026-05-29  8:45 ` [PATCH v3 15/15] arm64: dts: ti: beagley-ai: Enable HDMI display and audio Tomi Valkeinen

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=20260529100109.A84571F00893@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=robh@kernel.org \
    --cc=sashiko-reviews@lists.linux.dev \
    --cc=tomi.valkeinen@ideasonboard.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