Devicetree
 help / color / mirror / Atom feed
From: sashiko-bot@kernel.org
To: "Elson Serrao" <elson.serrao@oss.qualcomm.com>
Cc: conor+dt@kernel.org, robh@kernel.org, devicetree@vger.kernel.org
Subject: Re: [PATCH v7 6/8] usb: misc: qcom_eud: add role-based EUD control
Date: Mon, 31 Aug 2026 03:13:08 +0000	[thread overview]
Message-ID: <20260831031308.CECA01F000E9@smtp.kernel.org> (raw)
In-Reply-To: <20260831030147.1500616-7-elson.serrao@oss.qualcomm.com>

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] Missing `state_lock` acquisition in `port_store` and `eud_remove` introduces data races that can corrupt port state and leave hardware incorrectly enabled.
- [Medium] Missing error rollback in `eud_role_switch_set` leaves EUD hardware incorrectly enabled if the USB controller fails to switch roles.
--

commit 73436063bf4c0e29764237d75663c476d5f5b246
Author: Elson Serrao <elson.serrao@oss.qualcomm.com>

usb: misc: qcom_eud: add role-based EUD control

EUD functions by presenting itself as a USB device to the host PC and is
therefore only applicable when the port operates in device role. Keeping
EUD enabled in other roles provides no benefit and unnecessarily keeps
the associated PHY resources enabled. Furthermore, enabling EUD in host
role can cause the USB controller to misbehave because the EUD hub
supports only a single upstream-facing port.

> diff --git a/drivers/usb/misc/qcom_eud.c b/drivers/usb/misc/qcom_eud.c
> index 07522225a8f89..549c0d852bbba 100644
> --- a/drivers/usb/misc/qcom_eud.c
> +++ b/drivers/usb/misc/qcom_eud.c
[ ... ]
> @@ -156,17 +159,33 @@ static ssize_t enable_store(struct device *dev,
>  		const char *buf, size_t count)
>  {
>  	struct eud_chip *chip = dev_get_drvdata(dev);
> +	struct eud_path *path;
>  	bool enable;
>  	int ret;
>  
>  	if (kstrtobool(buf, &enable))
>  		return -EINVAL;
>  
> +	guard(mutex)(&chip->state_lock);
> +
>  	/* Skip operation if already in desired state */
>  	if (chip->enabled == enable)
>  		return count;
>  
>  	if (enable) {
> +		path = chip->paths[chip->port_idx];
> +
> +		/*
> +		 * If not yet in device role, honor the userspace request and defer
> +		 * EUD enablement until the port transitions to device role in the
> +		 * set_role callback.
> +		 */
> +		if (path->curr_role != USB_ROLE_DEVICE) {

[Severity: High]
Does this code race with port_store() and eud_remove() which do not take the
newly introduced state_lock?

Looking at port_store():

drivers/usb/misc/qcom_eud.c:port_store() {
    ...
	/* Port selection must be done before enabling EUD */
	if (chip->enabled)
		return -EBUSY;

	writel(port, chip->base + EUD_REG_PORT_SEL);
	chip->port_idx = port;
    ...
}

If a concurrent sysfs write to the port attribute changes chip->port_idx
after enable_store() has acquired state_lock and cached the path, wouldn't
enable_store() validate the role for the old port, but call enable_eud() which
will use the new port index locklessly updated by port_store()? This could
power on the PHY for the newly selected port regardless of its role.

Similarly, eud_remove() manipulates hardware state without the state_lock:

drivers/usb/misc/qcom_eud.c:eud_remove() {
    ...
	if (chip->enabled)
		disable_eud(chip);
    ...
}

Could this teardown logic race with ongoing concurrent role-switch operations
and unbalanced PHY power management on module removal?

> +			dev_info(chip->dev, "Deferring EUD enable until port enters device mode\n");
> +			chip->enabled = enable;
> +			return count;
> +		}
> +
>  		ret = enable_eud(chip);
>  		if (ret) {
>  			dev_err(chip->dev, "failed to enable eud\n");
[ ... ]
> @@ -304,7 +323,30 @@ static irqreturn_t handle_eud_irq_thread(int irq, void *data)
>  static int eud_role_switch_set(struct usb_role_switch *sw, enum usb_role role)
>  {
>  	struct eud_path *path = usb_role_switch_get_drvdata(sw);
> -	int ret;
> +	struct eud_chip *chip = path->chip;
> +	int ret = 0;
> +
> +	guard(mutex)(&chip->state_lock);
> +
> +	/*
> +	 * EUD is usable only in device role. Power it down for every other
> +	 * role to avoid keeping an unusable module 'ON'. chip->enabled
> +	 * preserves user's sysfs configuration and is not modified across
> +	 * role transitions.
> +	 */
> +	if (chip->enabled && path->num == chip->port_idx && role != path->curr_role) {
> +		if (role == USB_ROLE_DEVICE)
> +			ret = enable_eud(chip);
> +		else if (path->curr_role == USB_ROLE_DEVICE)
> +			ret = disable_eud(chip);
> +

[Severity: Medium]
If hardware state changes are made here before calling
usb_role_switch_set_role(), what happens if the controller transition fails
below?

> +		if (ret) {
> +			dev_err(chip->dev, "failed to %s EUD for role %s: %d\n",
> +				str_enable_disable(role == USB_ROLE_DEVICE),
> +				usb_role_string(role), ret);
> +			return ret;
> +		}
> +	}
>  
>  	/* Forward the role request to the USB controller */
>  	ret = usb_role_switch_set_role(path->controller_sw, role);
> +	if (ret) {
> +		dev_err(path->chip->dev, "failed to set role %s for port %u: %d\n",
> +			usb_role_string(role), path->num, ret);
> +		return ret;
> +	}

If usb_role_switch_set_role() fails, this returns the error immediately without
rolling back the physical state changes made earlier and without updating
path->curr_role.

If a transition to USB_ROLE_DEVICE enabled the EUD, but the controller switch
failed, wouldn't a subsequent switch back to USB_ROLE_HOST skip disabling the
EUD because path->curr_role never became USB_ROLE_DEVICE? Could this permanently
leave the EUD active in host mode, triggering controller misbehavior and leaking
the PHY power?

> +
> +	path->curr_role = role;
> +
> +	return 0;
> +}

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260831030147.1500616-1-elson.serrao@oss.qualcomm.com?part=6

  reply	other threads:[~2026-08-31  3:13 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-08-31  3:01 [PATCH v7 0/8] Improve Qualcomm EUD driver and platform support Elson Serrao
2026-08-31  3:01 ` [PATCH v7 1/8] dt-bindings: soc: qcom: eud: Add per-path child nodes for UTMI routing Elson Serrao
2026-08-31  3:09   ` sashiko-bot
2026-08-31 22:39   ` Bjorn Andersson
2026-08-31  3:01 ` [PATCH v7 2/8] usb: misc: qcom_eud: add sysfs attribute for port selection Elson Serrao
2026-08-31  3:12   ` sashiko-bot
2026-08-31  3:01 ` [PATCH v7 3/8] usb: misc: qcom_eud: add per-path High-Speed PHY control Elson Serrao
2026-08-31  3:15   ` sashiko-bot
2026-08-31  3:01 ` [PATCH v7 4/8] usb: misc: qcom_eud: add per-path role switch support Elson Serrao
2026-08-31  3:17   ` sashiko-bot
2026-08-31  3:01 ` [PATCH v7 5/8] usb: misc: qcom_eud: improve enable_store API Elson Serrao
2026-08-31  3:13   ` sashiko-bot
2026-08-31  3:01 ` [PATCH v7 6/8] usb: misc: qcom_eud: add role-based EUD control Elson Serrao
2026-08-31  3:13   ` sashiko-bot [this message]
2026-09-01 11:36   ` Konrad Dybcio
2026-08-31  3:01 ` [PATCH v7 7/8] usb: misc: qcom_eud: fix virtual attach/detach event handling Elson Serrao
2026-08-31  3:17   ` sashiko-bot
2026-08-31  3:01 ` [PATCH v7 8/8] arm64: dts: qcom: kodiak: Desribe EUD UTMI routing and connector mapping Elson Serrao

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=20260831031308.CECA01F000E9@smtp.kernel.org \
    --to=sashiko-bot@kernel.org \
    --cc=conor+dt@kernel.org \
    --cc=devicetree@vger.kernel.org \
    --cc=elson.serrao@oss.qualcomm.com \
    --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