From nobody Mon Jun 15 03:54:53 2026 Received: from mx0a-0031df01.pphosted.com (mx0a-0031df01.pphosted.com [205.220.168.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 3D7E133E351 for ; Tue, 7 Apr 2026 23:24:13 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=205.220.168.131 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775604255; cv=none; b=mDw/GXVk7gQAJetyU79tjnbPi7WKI4AxS6tgtL+IdVySk5U5F/UoZKHKy7463Mux1Tzp4LE7/yNj3JOJoUoLNYrak6V3xiRqcFxodet98J8llrX9jjNV43P52akrcGN7OubBvxLmeQYPCXx67jmduuMmpdYJEZi6WDL9rOo41Lc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1775604255; c=relaxed/simple; bh=mhhSE0DTLHfssa/4rIrRQJ+BLeOe07efczXWZJwE7K4=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=szLYZ0UUNLfxMxexMyThcSY5vGIkQw7Ay/yIhdwOjbFOV+NsJPjdnpX2FhvMGwpd/OBJPj281MG8d/EjatAOlbH6oKbthSN4NkpDSPo/EiZjn8G16UyKenQereyO6xR6eDUlc/i9GhkfVsVz+lZKnoQx1ChpwSU9OQFwwGgOTkM= 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=lU1eIr1v; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=VrpL0DYn; arc=none smtp.client-ip=205.220.168.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="lU1eIr1v"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="VrpL0DYn" Received: from pps.filterd (m0279867.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 637KOBEc249520 for ; Tue, 7 Apr 2026 23:24:13 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=Vify/tSNNfOxujkABv2RqFXr1fdKkM70W8x YgfSuU6E=; b=lU1eIr1vVGYAWUosjZiWxfBacBoY03+SygJTiJmD7/evry65Sud n6STw007Fn15oJoDBxxisMzerObytiTI0Ri0eX3KrLfKpplWtJUkpaFkLJguT7tG hqfBD03imgV+ENyvOdTeCuB1MXtepF0TH3LGBa74t4i7Maye5Y54VFgJypBV+eiL AkA2c6ELY6ZwQIO+5gHGV8RoSsQ4YrwzQYBt4MvGfQrKP3Fi1b41PFBwRoyXQeF6 2x8cmtnbyvL/yO5XTWnR2ehNjNugiPLHNuwvwCp1HH5mHrYTi5E3AsTx+9r7Z33i 8UpVtduuiLh4CLHALX2JApBPPG28ssOtPSQ== Received: from mail-dl1-f72.google.com (mail-dl1-f72.google.com [74.125.82.72]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4dd8x98e9u-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 07 Apr 2026 23:24:13 +0000 (GMT) Received: by mail-dl1-f72.google.com with SMTP id a92af1059eb24-1279caef718so8783161c88.1 for ; Tue, 07 Apr 2026 16:24:13 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1775604253; x=1776209053; 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=Vify/tSNNfOxujkABv2RqFXr1fdKkM70W8xYgfSuU6E=; b=VrpL0DYnqJaSO/am2wJb37e1L2AZCZcVEhbQXoPe5oCJ65pxkW11rkCl6bpEKT1CIq tbEavQCup+h1D6XH5HjjLlrixBJyxf5vJVPZUPEvjX8PA+eFxAfYe4UpPQSYzWrDSZU9 1uUVnq2+VIwL2Xdev3Bkg/DWldodJwTNq7qDeoz98jCqHFU8J9qe7bF9xjCpK5p8ofQu rUJ0Yb081BtV65DmR1D2OB1ZcH2b5qIpn1+Dffdk5QncMrIowMmCqYSFaBr80RgzKzn1 +FKpZ+jEtukA4+K9FCed5MG0BeD1HVFmBluCeHG2V6dpFf1wszOWKr9VFdXh+g8gLzcR VGPg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1775604253; x=1776209053; 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=Vify/tSNNfOxujkABv2RqFXr1fdKkM70W8xYgfSuU6E=; b=hHPbQ+ylc/QINqAJmeakTfc0gpCNpXgGipCQXv31A0C9S6W79pCUapEJZJrz8y9M2q aXnx28e+0lnGUL3S6uEGRlY2Hy8/drUMcSh6vMRwllMjZnuFqh5e1MCfIunP1qG6JAbA u8tQ022+kS/sIoNrfNsm4/HX8M21HI7wAM4xHYD7fRDgQLb/MNDBDWGHfy18wqP7ytHZ 0EsrSV4kfXpMfGlc0We4oON27/1xpAFq3uYCOMSUSV8K98Wk4co9uh1OJ+SvdqOl31ca j0DBH16J6hSZu51e8+n8MalmR8b/dI1S5wm9fUamZcVa/h4cAGoc5fsIM3edigYV1lM9 fafA== X-Forwarded-Encrypted: i=1; AJvYcCX59v1m+mo0SZro4JGzYOzecOAL5wuLpxWzusByVABI5pLDuX0vt0CBDV5kHofIzO/0FGHi8Gr9Ix5Go3g=@vger.kernel.org X-Gm-Message-State: AOJu0YzCXi2SHwvlQaR1gvo+TQLXdhcl7K3V/sKzabob9jrZf2RUSrkK 7D04rrCNgvgLZM7S77iADZtaweA/T78ne9r0AdQiYAIco8ofHdhOGeLT8S+itK4uF2DUYeviBap GnqbTIcDa86x0Tzo1/bz18Vo1aea1tmz8QmGm9B7anNPWJqPORIaOdmjmP/0kAhi/rA0= X-Gm-Gg: AeBDieuhDJ1P+x78u0v3AMC86R4emI1l8ocovqGuzQThUo9ribkZiDTevSdDMSqiqIL YxHB/Owr6n9kSwzACOu2/C1ZfU/e2KL7U+agFl6iuYamnoCfwD5ruMAnnql77e0l/wAYP5k3bYk R4RTqDFx5+NSoHQesh5m6MzMH7QgsxPj38nFG36vqgpRZXSKInKPNzCkIu3+l4ag1A8kw6o8bpi qXfUK0MYnY9v90c+3pQMTLKhIiWodSHh4PnFIhyWpd5r38ifW/F61ODjivQiF7rxsVE3S8Ep1NW D5YokQKhfocQ0vzOS1IKILpFhgeNYI6yDoIen+Bd43OlyaU+ZIQftmoDGgELVSNU/AkRKCcLC4S e5vIZNfwb32RwNl9+yKbaIdErfbUBAdL8+q5FY3cOnoMkmgBH0TuYEANKc9grbR2tfFQpKty1gc E= X-Received: by 2002:a05:7022:6629:b0:12a:6b99:1ad4 with SMTP id a92af1059eb24-12bfb6fb392mr9954153c88.11.1775604252533; Tue, 07 Apr 2026 16:24:12 -0700 (PDT) X-Received: by 2002:a05:7022:6629:b0:12a:6b99:1ad4 with SMTP id a92af1059eb24-12bfb6fb392mr9954137c88.11.1775604251965; Tue, 07 Apr 2026 16:24:11 -0700 (PDT) Received: from hu-eserrao-lv.qualcomm.com (Global_NAT1.qualcomm.com. [129.46.96.20]) by smtp.gmail.com with ESMTPSA id a92af1059eb24-12bede545e8sm16163393c88.11.2026.04.07.16.24.11 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 07 Apr 2026 16:24:11 -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] usb: dwc3: avoid probe deferral when USB power supply is not available Date: Tue, 7 Apr 2026 16:24:10 -0700 Message-Id: <20260407232410.4101455-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-Authority-Analysis: v=2.4 cv=Rr716imK c=1 sm=1 tr=0 ts=69d5921d cx=c_pps a=bS7HVuBVfinNPG3f6cIo3Q==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=A5OVakUREuEA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=eoimf2acIAo5FJnRuUoq:22 a=EUspDBNiAAAA:8 a=SXPYzt1XaJ2lArBJve4A:9 a=vBUdepa8ALXHeOFLBtFW:22 X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNDA3MDIxNCBTYWx0ZWRfX881xGUQd6c3S fkqsPyLi6t16PufO/zcXpaQURvHKL82oJUyKNQmn4hdDbPdKw3+S4BPTq6V22kZ6w1DzZ1j742N z6h9UfrMfyUTgHxwXjHhLGv0m6H0w6MKzdVExWBP5z4SFaju6d3PT3wD1zx/5JaXh303GpLk+1T R/SufP1HXX3MfbizT/pk3T/PrNT06kZCAuzW4TLEHGXM5iK0ECej94ErS+K1QP/mzoZfbADW8DJ 4c9GfidbzK5VX5RsrNEwxPWrDWGaufXKXNvWsX22k+AtY0oi/ei7X5q4AF0mt1ClcDbL2Zsndyq b7mhJV/g32GAtE2pk4QavnknJ7ggPZqbgWDkLY3ZMHS/8BA+MUpQN4Mqm4EJtslT3IyHiEk2y5O poyI8VVhXi0y1NjkZqwOXBKzb5jVMeQ3/CTLQzS3B27Nvdcw2dL0IS+ygEwkHb+2imu+DhPg2HM QfRVk8/OP4aCe9F5fEQ== X-Proofpoint-ORIG-GUID: UuY6REXL5M2hFqZcP_5fmWRsN-Mi8mFw X-Proofpoint-GUID: UuY6REXL5M2hFqZcP_5fmWRsN-Mi8mFw X-Proofpoint-Virus-Version: vendor=baseguard engine=ICAP:2.0.293,Aquarius:18.0.1143,Hydra:6.1.51,FMLib:17.12.100.49 definitions=2026-04-07_05,2026-04-07_05,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 priorityscore=1501 suspectscore=0 malwarescore=0 clxscore=1015 bulkscore=0 phishscore=0 adultscore=0 spamscore=0 lowpriorityscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2604010000 definitions=main-2604070214 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 --- drivers/usb/dwc3/core.c | 82 ++++++++++++++++++++++++++++++++------- drivers/usb/dwc3/core.h | 4 ++ drivers/usb/dwc3/gadget.c | 10 ++++- 3 files changed, 80 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 161a4d58b2ce..20df0b287623 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -2167,24 +2167,72 @@ static void dwc3_vbus_draw_work(struct work_struct = *work) if (ret < 0) dev_dbg(dwc->dev, "Error (%d) setting vbus draw (%d mA)\n", ret, dwc->current_limit); + + /* Unregister the psy notifier now that we have the power_supply referenc= e */ + if (dwc->psy_nb.notifier_call) { + power_supply_unreg_notifier(&dwc->psy_nb); + dwc->psy_nb.notifier_call =3D NULL; + } } =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 dwc3 *dwc =3D container_of(nb, struct dwc3, psy_nb); + struct power_supply *psy =3D data; + unsigned long flags; + + 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 UINT_MAX) + 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 *usb_psy; - const char *usb_psy_name; 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->usb_psy =3D power_supply_get_by_name(dwc->usb_psy_name); + if (!dwc->usb_psy) { + dwc->current_limit =3D UINT_MAX; + 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; + } + } } =20 int dwc3_core_probe(const struct dwc3_probe_data *data) @@ -2232,9 +2280,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); @@ -2286,7 +2334,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); @@ -2354,6 +2401,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 @@ -2410,6 +2459,11 @@ 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); + dwc->psy_nb.notifier_call =3D NULL; + } + 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 a35b3db1f9f3..68171629c7bf 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1058,6 +1058,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 @@ -1246,6 +1248,8 @@ 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 diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index 0a688904ce8c..4717c251596d 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -3124,15 +3124,21 @@ 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) + spin_lock_irqsave(&dwc->lock, flags); + dwc->current_limit =3D mA; + if (!dwc->usb_psy) { + spin_unlock_irqrestore(&dwc->lock, flags); + dev_dbg(dwc->dev, "Stored VBUS draw: %u mA (power supply not ready)\n", = mA); return -EOPNOTSUPP; + } =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