From nobody Mon Jun 8 20:54:37 2026 Received: from mx0b-0031df01.pphosted.com (mx0b-0031df01.pphosted.com [205.220.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7699536D9E7 for ; Mon, 8 Jun 2026 17:19:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.180.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780939199; cv=none; b=ZADbCN+JMkdEbxZenyDGkOvKFTJLhbDSCvGT71dDVv3cNiMnnaTjmgWCA+fFin5411gEZOXj0+8YEH4fDg/yU8P6Pc7P1h6Ng4fL+Rk9E6cjYczckW8pJqKQ8V6S0By70e5GMo6ggV/ZzRMZil3iNP5f7jzJc82f8MkJzUSOGwQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780939199; c=relaxed/simple; bh=djFonw/mmhMFAySEONiWbh/B7S7mxayto7PteHyKgqo=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=ozEuPFGWLIUMTUCp6YdcglgruqlEyViYa2vECt2oY2YhWaldk4fquzcdP3b7B+nk21yd2CK9BPOYGpnQ2PUgvvO8HIm+oW9lTDHZy5p1FLnC1wtTSI/+/fgnlKUKrvtRUpaWyR/rm+gpyhLUQQQdt2tR2jSRKvXEgjEGzhpO4ok= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com; spf=pass smtp.mailfrom=oss.qualcomm.com; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b=FK6xztuR; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=Fpu5D8Gw; arc=none smtp.client-ip=205.220.180.131 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=oss.qualcomm.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=qualcomm.com header.i=@qualcomm.com header.b="FK6xztuR"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="Fpu5D8Gw" Received: from pps.filterd (m0279869.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 658FKVFw4045877 for ; Mon, 8 Jun 2026 17:19:56 GMT DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qualcomm.com; h= cc:content-transfer-encoding:date:from:message-id:mime-version :subject:to; s=qcppdkim1; bh=Ncl8l46wVJCPO4E+pjD4fdmfWv/QlT7fHO+ gth+eQlU=; b=FK6xztuRK1vWV1TBT9Z2dufn/ftrlkMe5SWOeziuT23VcdPVDkr tzsXEYunq08TZEuHLI2pkluiUiwHHReJA4w8fxy/TQkPvn2GrTGXU1yY3SHwIbQz hcYHiXExXjnU4wm3jSljzaSbUg+nyeE9vZS53SmM3vsYFyvfIQWeCGjfMZCaBd3X 4PNIPoMwiY699pBn4D+akKbukvceiMTUo1ytkWxt+lIapzary8X84H52fyvhBLmf BwYv4znUViIP2wKRVct93c6j1O3Z3d5nBVniUIYVyD0w0A0ThzniWjm+ivG3wDUq V97r7av8g40C8Y7mJwjx8+uTnykOH1VqgMQ== Received: from mail-dy1-f199.google.com (mail-dy1-f199.google.com [74.125.82.199]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4enxee1952-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Mon, 08 Jun 2026 17:19:56 +0000 (GMT) Received: by mail-dy1-f199.google.com with SMTP id 5a478bee46e88-304b8d0ee63so6382026eec.0 for ; Mon, 08 Jun 2026 10:19:56 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1780939195; x=1781543995; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=Ncl8l46wVJCPO4E+pjD4fdmfWv/QlT7fHO+gth+eQlU=; b=Fpu5D8GwmclLoODJfNSxGW9lJCJbxS73qP1EspaedRbv1h9IQ+9I4rBDBO1dWc3AY4 C5uY4Nz8upIcRAEnYD3LW31vfNmk9raq+r4DrAKo2cMMe7dBGYJI5aGMFbNZeuM4Hgdg D5z0Q7Kz24maW+NnTmj4YaGYB1XTjPy1/3TcZFmypJTl6S94VR5c3077NMh/4k1Z8oRF uFS8TcjX7GkR5F3YSznyTTgHgQNmGG4B+CrY7sZvAIFF6mSDUqeUFbJPW7NCfm6gQA9v IuDp0UZKZtZ+h7VCOkdFoWLw7msDgjXQ7hGAdUBZBCX1EK2oEDnj2rVhtmYpMbykxXtq vBmA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780939195; x=1781543995; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-gg:x-gm-message-state:from:to:cc:subject:date :message-id:reply-to; bh=Ncl8l46wVJCPO4E+pjD4fdmfWv/QlT7fHO+gth+eQlU=; b=FgVBOW1T2lU2zxRoNjIZpn9vDLXKl6VdaqoGfC5mn62pLkYhU06w66Kxe6HNSKiPab Hdt0IST2lhVI8Q83JB7/uZOgacHZ53t9QYFozW5J2o9am3h1m4Dmn/iKKm7U/JX3uxW8 g1tdOmmgx90LGJhXw2eTBcvr8QCSaOAcS0mz4oEyRRArwJ9C+fQB7yhHb4XjvBENdWsN IVLH5zZb223IkBSfBFPnLV0ekojnzXbysN3sjcHY9PTdX6djVWjAtIW22n3+zcpgokzv Kb0XiNwUNWnf1uXmXCpXvl1Av9/Rjub6UDfcPStW5FYrpp2d44Ly+AfqCu9IKKyZUCd7 OIgQ== X-Forwarded-Encrypted: i=1; AFNElJ+EmNqm/sFJPDeohd7+8jv285VeT6cEJZqqF4sgipX5I1ulTx7V76uwlZbLNoSnwSVDMTRtZk2vJK8I+Pc=@vger.kernel.org X-Gm-Message-State: AOJu0YxZyHUrGiUZtmG67F7GOzuDmqV2Q0ESsUop4ntjfLYxlouUwjAR xGn458Qyg/afw7HfnY9NfY56YxLPlTvfVZK3mieLgsDiwP3o/Db0GIFTJcB5UkhkEeAphe87QVr Y+xdXpAGVBcIVo0bmL6IblgG2QZiNWvjR4WxWowyQlQurHY6ajgwSAOca0X6SeGHA1QU= X-Gm-Gg: Acq92OE+q7ZfD3dLp+76eQeIopuivGBRuF00ieplAO6wy45BmDfiQFAoOtpQyr9PeXk y0WP3MrQx7z+gLeabCgXF0++PdZIb4rQ+wLXT/8+KcbIAQx9qeahtaZq43AzyOvH/+EL2YoVl70 x4GkaY6uk/VkP+Z5ggbqVHvXFdpVvIuoz3x29i/3Bd5V42mPKWKYOmJuCWYroy5bg1TvXJ/Ml7k jGq7gGwTouU0Hhcw2DdtTxSU8Qd58DwbjnCLW4YPKb32RUpeK9X8MdSRcNSRqbWX0Opi9GcJL+c nskUpV8BVgj6gNh0haOxZ2fkuxOZfO1d9F/9w2YL6boTzFCgBqrCMJB8JmnoOu5995fgeWYnICf 1ir8ThMys/rI2hxldTcknTuYrAWXENZXzJfvf8m7fcPvIpIzzavJCLUiRqt11je4f0gzdltjD3I 7fvNWi3fptOA== X-Received: by 2002:a05:7301:2b07:b0:307:43ff:f32e with SMTP id 5a478bee46e88-3077b36f7b6mr8414286eec.32.1780939195200; Mon, 08 Jun 2026 10:19:55 -0700 (PDT) X-Received: by 2002:a05:7301:2b07:b0:307:43ff:f32e with SMTP id 5a478bee46e88-3077b36f7b6mr8414243eec.32.1780939194452; Mon, 08 Jun 2026 10:19:54 -0700 (PDT) Received: from hu-eserrao-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id 5a478bee46e88-3074dcb98aasm17284253eec.12.2026.06.08.10.19.53 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 08 Jun 2026 10:19:53 -0700 (PDT) From: Elson Serrao To: Thinh Nguyen , Greg Kroah-Hartman Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org, jack.pham@oss.qualcomm.com, wesley.cheng@oss.qualcomm.com Subject: [PATCH v4] usb: dwc3: avoid probe deferral when USB power supply is not available Date: Mon, 8 Jun 2026 10:19:53 -0700 Message-Id: <20260608171953.1717369-1-elson.serrao@oss.qualcomm.com> X-Mailer: git-send-email 2.34.1 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNjA4MDE2NCBTYWx0ZWRfX545RSGk3p1Jl YA5M+FcRxzg1ZJGAMh1M8Az1useqlj/4QL2sXZxKQvZiXVx+5HNa2ECwYYOuQ46LYXn6LNkAFEN CFNsAtd9YzHouZYgyyiDx0RTsB+OtkZOrurq/r7NYuSCD6U+tnA/Ualy9Ie27p1rnijQDoIsQLe AFJjtYkF7fzKOiSEpdg0ILjhesjVVXJUkLfqOhD4sFkw/N1Ijgpl/j2A6hQbI8rGwru6XmYZBaC lYAJn8wZdskyIbCBhSx4Ra2k28iOE2GJyvxU9SLdXxIARoZ/zPr1CSepfmFErjYvmESMYjR5WP9 WHAeUt7BQTyrQOjoLJCvEPwrICQRIisYy1QMUgtw7Ch81hZoft4l/jkCFzuUQyHcpyVfZLcjDqm 3xZgMo0I7YTHJc+bxmfFInorEugPHXGiOVfbe37N5s8mettvUc6z/oRN78GUkKifuDsRbJIgJ9t TKPTLpVeCqv1t7wrHZg== X-Authority-Analysis: v=2.4 cv=V6BNF+ni c=1 sm=1 tr=0 ts=6a26f9bc cx=c_pps a=cFYjgdjTJScbgFmBucgdfQ==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=FelO9ux0wxsA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=VwQbUJbxAAAA:8 a=EUspDBNiAAAA:8 a=jIQo8A4GAAAA:8 a=BnH1jSTHCRmwS-4C6JUA:9 a=scEy_gLbYbu1JhEsrz4S:22 X-Proofpoint-GUID: UjK7ZWiICQdk0_LAMaGGT3YBPPldG5yF X-Proofpoint-ORIG-GUID: UjK7ZWiICQdk0_LAMaGGT3YBPPldG5yF X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.125,FMLib:17.12.100.49 definitions=2026-06-08_04,2026-06-05_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 priorityscore=1501 adultscore=0 spamscore=0 malwarescore=0 clxscore=1015 lowpriorityscore=0 suspectscore=0 bulkscore=0 impostorscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2606080164 Content-Type: text/plain; charset="utf-8" The dwc3 driver currently defers probe if the USB power supply is not yet registered. On some platforms, even though charging and power supply functionality is available during normal operation, there may exist minimal booting modes (such as recovery or diagnostic environments) where the relevant USB power supply device is not registered. In such cases, probe deferral prevents USB gadget operation entirely. USB data functionality for basic operation does not inherently depend on the power supply framework, which is only required for enforcing VBUS current control. The configured VBUS current limit is typically enforced through the charger or PMIC power path. When charging functionality is unavailable, applying a current limit has no practical effect, reducing the benefit of strict probe-time enforcement in these environments. Instead of deferring probe, register a power supply notifier when the USB power supply is not yet available. Cache the requested VBUS current limit and apply it once the matching power supply becomes available, as notified through the registered callback. Signed-off-by: Elson Serrao Acked-by: Thinh Nguyen --- Changes in v4: - Moved DWC3_CURRENT_UNSPECIFIED macro definition to be placed right after the current_limit field in struct dwc3 for better code organization. - Link to v3: https://lore.kernel.org/all/20260605181142.1925832-1-elson.s= errao@oss.qualcomm.com/ Changes in v3: - Introduced DWC3_CURRENT_UNSPECIFIED macro to replace UINT_MAX for improved code readability. - Enhanced dwc3_gadget_vbus_draw() to return success when power supply is expected but not ready yet, and only return -EOPNOTSUPP when truly not supported. - Link to v2: https://lore.kernel.org/all/20260526183016.3501307-1-elson.s= errao@oss.qualcomm.com/ Changes in v2: - Removed notifier unregistration from the vbus_draw work function to avoid a race with remove callback. - Added an early psy registration check in the notifier callback. - Moved power supply registration check after notifier registration in dwc3_get_usb_power_supply() to address the race identified in v1. - Link to v1: https://lore.kernel.org/all/20260407232410.4101455-1-elson.s= errao@oss.qualcomm.com/ --- drivers/usb/dwc3/core.c | 99 +++++++++++++++++++++++++++++++++------ drivers/usb/dwc3/core.h | 6 +++ drivers/usb/dwc3/gadget.c | 15 +++++- 3 files changed, 104 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 65213896de99..9c750f90213a 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2192,22 +2192,89 @@ static void dwc3_vbus_draw_work(struct work_struct = *work) ret, dwc->current_limit); } =20 -static struct power_supply *dwc3_get_usb_power_supply(struct dwc3 *dwc) +static int dwc3_psy_notifier(struct notifier_block *nb, + unsigned long event, void *data) { - struct power_supply *usb_psy; - const char *usb_psy_name; + struct dwc3 *dwc =3D container_of(nb, struct dwc3, psy_nb); + struct power_supply *psy =3D data; + unsigned long flags; + + if (dwc->usb_psy) + return NOTIFY_DONE; + + if (strcmp(psy->desc->name, dwc->usb_psy_name) !=3D 0) + return NOTIFY_DONE; + + /* Explicitly get the reference for this psy */ + psy =3D power_supply_get_by_name(dwc->usb_psy_name); + if (!psy) + return NOTIFY_DONE; + + spin_lock_irqsave(&dwc->lock, flags); + /* + * The USB power_supply may already be set. This can happen if notifier + * callbacks for the USB power_supply race, or if a previous notifier + * callback has already successfully fetched and associated the instance. + * In such cases, release the newly acquired reference and ignore + * subsequent notifications until the notifier is unregistered. + */ + if (dwc->usb_psy) { + spin_unlock_irqrestore(&dwc->lock, flags); + power_supply_put(psy); + return NOTIFY_DONE; + } + + dwc->usb_psy =3D psy; + if (dwc->current_limit !=3D DWC3_CURRENT_UNSPECIFIED) + schedule_work(&dwc->vbus_draw_work); + spin_unlock_irqrestore(&dwc->lock, flags); + + return NOTIFY_OK; +} + +static void dwc3_get_usb_power_supply(struct dwc3 *dwc) +{ + struct power_supply *psy; + unsigned long flags; int ret; =20 - ret =3D device_property_read_string(dwc->dev, "usb-psy-name", &usb_psy_na= me); + ret =3D device_property_read_string(dwc->dev, "usb-psy-name", &dwc->usb_p= sy_name); if (ret < 0) - return NULL; - - usb_psy =3D power_supply_get_by_name(usb_psy_name); - if (!usb_psy) - return ERR_PTR(-EPROBE_DEFER); + return; =20 INIT_WORK(&dwc->vbus_draw_work, dwc3_vbus_draw_work); - return usb_psy; + + dwc->current_limit =3D DWC3_CURRENT_UNSPECIFIED; + dwc->psy_nb.notifier_call =3D dwc3_psy_notifier; + ret =3D power_supply_reg_notifier(&dwc->psy_nb); + if (ret) { + dev_err(dwc->dev, "Failed to register power supply notifier: %d\n", ret); + dwc->psy_nb.notifier_call =3D NULL; + return; + } + + psy =3D power_supply_get_by_name(dwc->usb_psy_name); + if (!psy) + return; + + /* Unregister the notifier now that we have the power supply */ + power_supply_unreg_notifier(&dwc->psy_nb); + dwc->psy_nb.notifier_call =3D NULL; + + spin_lock_irqsave(&dwc->lock, flags); + /* + * It is possible that the notifier callback ran before we reached here + * and successfully fetched the power supply. In that case we need to + * release the above reference. + */ + if (dwc->usb_psy) { + spin_unlock_irqrestore(&dwc->lock, flags); + power_supply_put(psy); + return; + } + + dwc->usb_psy =3D psy; + spin_unlock_irqrestore(&dwc->lock, flags); } =20 int dwc3_core_probe(const struct dwc3_probe_data *data) @@ -2255,9 +2322,9 @@ int dwc3_core_probe(const struct dwc3_probe_data *dat= a) =20 dwc3_get_software_properties(dwc, &data->properties); =20 - dwc->usb_psy =3D dwc3_get_usb_power_supply(dwc); - if (IS_ERR(dwc->usb_psy)) - return dev_err_probe(dev, PTR_ERR(dwc->usb_psy), "couldn't get usb power= supply\n"); + spin_lock_init(&dwc->lock); + + dwc3_get_usb_power_supply(dwc); =20 if (!data->ignore_clocks_and_resets) { dwc->reset =3D devm_reset_control_array_get_optional_shared(dev); @@ -2309,7 +2376,6 @@ int dwc3_core_probe(const struct dwc3_probe_data *dat= a) dwc->num_usb3_ports =3D 1; } =20 - spin_lock_init(&dwc->lock); mutex_init(&dwc->mutex); =20 pm_runtime_get_noresume(dev); @@ -2377,6 +2443,8 @@ int dwc3_core_probe(const struct dwc3_probe_data *dat= a) err_assert_reset: reset_control_assert(dwc->reset); err_put_psy: + if (dwc->psy_nb.notifier_call) + power_supply_unreg_notifier(&dwc->psy_nb); if (dwc->usb_psy) power_supply_put(dwc->usb_psy); =20 @@ -2433,6 +2501,9 @@ void dwc3_core_remove(struct dwc3 *dwc) =20 dwc3_free_event_buffers(dwc); =20 + if (dwc->psy_nb.notifier_call) + power_supply_unreg_notifier(&dwc->psy_nb); + if (dwc->usb_psy) { cancel_work_sync(&dwc->vbus_draw_work); power_supply_put(dwc->usb_psy); diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index e0dee9d28740..07e0e1b8e804 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1059,6 +1059,8 @@ struct dwc3_glue_ops { * @role_switch_default_mode: default operation mode of controller while * usb role is USB_ROLE_NONE. * @usb_psy: pointer to power supply interface. + * @usb_psy_name: name of the USB power supply + * @psy_nb: power supply notifier block * @vbus_draw_work: Work to set the vbus drawing limit * @current_limit: How much current to draw from vbus, in milliAmperes. * @usb2_phy: pointer to USB2 PHY @@ -1251,9 +1253,13 @@ struct dwc3 { enum usb_dr_mode role_switch_default_mode; =20 struct power_supply *usb_psy; + const char *usb_psy_name; + struct notifier_block psy_nb; struct work_struct vbus_draw_work; unsigned int current_limit; =20 +#define DWC3_CURRENT_UNSPECIFIED UINT_MAX + u32 fladj; u32 ref_clk_per; u32 irq_gadget; diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 3d4ca68e584c..c36d2a949231 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3124,15 +3124,26 @@ static void dwc3_gadget_set_ssp_rate(struct usb_gad= get *g, static int dwc3_gadget_vbus_draw(struct usb_gadget *g, unsigned int mA) { struct dwc3 *dwc =3D gadget_to_dwc(g); + unsigned long flags; =20 if (dwc->usb2_phy) return usb_phy_set_power(dwc->usb2_phy, mA); =20 - if (!dwc->usb_psy) - return -EOPNOTSUPP; + spin_lock_irqsave(&dwc->lock, flags); + if (!dwc->usb_psy) { + if (!dwc->psy_nb.notifier_call) { + spin_unlock_irqrestore(&dwc->lock, flags); + return -EOPNOTSUPP; + } + dwc->current_limit =3D mA; + spin_unlock_irqrestore(&dwc->lock, flags); + dev_dbg(dwc->dev, "Stored VBUS draw: %u mA (power supply not ready)\n", = mA); + return 0; + } =20 dwc->current_limit =3D mA; schedule_work(&dwc->vbus_draw_work); + spin_unlock_irqrestore(&dwc->lock, flags); =20 return 0; } --=20 2.34.1