From nobody Mon Jun 8 20:42:20 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 A07C240960B for ; Tue, 26 May 2026 18:30:20 +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=1779820222; cv=none; b=lHKlPRpbJqRZ7LjeZjzN8HYtaFErsESyUpJFdhWpCXgcCNpRdJRgI6Ik6UtbF+R4SvcwPOZwhA4YKxrlf4iORSbgATjVUj6MxlhH/NiuceSjcUQ7e+e7C7OPK4PETLmA3+IUoKWNJA/xm/+0eXknZ2bQEjGunJV28Yq0FHvjugo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1779820222; c=relaxed/simple; bh=AnERR3aYBMShlbG8W01rgjvYAZLp4HueE8R5yBYjsQY=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=YE8mZ476znLsEKvFMwnBBXs7wyTh3ak1X7C47YcPbEdj42Ihcay1B6eJH7typS6t8caJtZqYupRfQEr6pSsL3AxySC5gNIaVq/kgW5np1RwOJOx0Q08YBn8SAk1yVQ3zkG45CTBmw5yrLJ0zOKAw9a1iFwc2GEJyjNy/VOugJRw= 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=E6s6i0Nx; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=WvQrpNxB; 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="E6s6i0Nx"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="WvQrpNxB" 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 64QH12vi1752093 for ; Tue, 26 May 2026 18:30:19 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=TEi2Tq0xC1zN1d24vzrJg3IDr3nxq28YoQs nHTaOUJw=; b=E6s6i0NxphHx2lXQdZnGor8QMoy/RQSJ5BuvhZ4AaZGFLy7YJGj GLE/aeVYkRDHeyr3BhnmvgpaqSSsMdEUiU+ADKEie8FwpHcs+l8os5jvbRGXa9CK yzlVqrIdGji1Pfl3z9a7xsuk+LnTFvDeeGM3xh04xn1B1/gNfdkUrV4+tmNvRAfI toSic01aLnAgMukYB604BEh7Pf5BtlWMbc2OmySHBt/4kuSuvUv58t4FND1FrvlO GWDDEcFsKDGCTbM4OUp63ABFxx9rFQPbOFN1TvK1qonugpbih9cVQ5dlFuKfMBGr UOO6qrqo+pITRg0pIkA6iRDgkxqKcgQz+fw== 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 4edd5nh5we-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Tue, 26 May 2026 18:30:19 +0000 (GMT) Received: by mail-dy1-f199.google.com with SMTP id 5a478bee46e88-3048abb847eso1156502eec.0 for ; Tue, 26 May 2026 11:30:19 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1779820218; x=1780425018; 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=TEi2Tq0xC1zN1d24vzrJg3IDr3nxq28YoQsnHTaOUJw=; b=WvQrpNxB8DU71DpOcqIZyjrvOWTV53sTXUqGbFtMS4WiDe5Gu+fYCvCeV8/7A5hN9T alzvnd0Seub1wRQglEL216/94EMqpGCE7qhDd8FnueJkQLOEBFmy+qGvHJPZ95W9iwKS 26JZIOFYHLHfU3XMNE9dqkXw7l9lSEypbhvAm86qjPart9VsgPSQIa2FjqcUQs8Qgs9b fXR1Z/G3WH/7YW409rdy+S+U0ta0TOKn03e3oDFd+CaWjlGVxliQ7pUpD2ArnGfv6uvT N9R/dSrE96nRvI1MBiuTm2t1100qmQ8UhIMhrKCEZctxBYhGQRkNXgu2bFol10QrJ0jP VX+Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1779820218; x=1780425018; 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=TEi2Tq0xC1zN1d24vzrJg3IDr3nxq28YoQsnHTaOUJw=; b=cBml65WyEZrjtT9y3ZTiE/IkGrtcxSzPqeEzuwW1aS3N3BU2ONFSeyYC04bM32LmH9 xgttULN2nz/QdldBeYJvXCjXJVRKoavFz+LSNlvJjq638cGWQ4bGKS3rkeKwKs2BxNPS EG1XNDuIIo8jYeZqJ4pdkLQ9EMP79CXKOAU3f2aGSO81rX65I9UI/HRnO1JYGzcOBLmQ lUZK3BZKYW1NMhanWju4b7orxCBZq7hlRnvuxkx4GXh4+Y99OHQSkH3Gj9PxJwpFBrgu GlFYcXQ/HIWYpQ2+05oeLLiF7nC2KN7kJ1GYkrbiHwucSUFNzH1AzdAsJ1aISFB/aMvr Wj6g== X-Forwarded-Encrypted: i=1; AFNElJ/IqloLqF5Gzwug2CnpYZPHMM9i+Ksyu7qSiuHaP+TYmbI/GRBWbsb0gwardfyVYSogOpoumUv7FyJO0+E=@vger.kernel.org X-Gm-Message-State: AOJu0YyxJvpbrdgj/2kt/3wkt2Q7m/bS5ltEScIUGvfcztFYFEZgU7rL 8Kvx8jo9foDZuBN54r67+Ls1AIBL1vbpLhihUmSYZL8MJX9tjaLVth4F/GbnQl+z4Ays0VVUmXQ +DxrsNRrXNgNGIxFWLGNB78tIbmQkS04GrylDL/bTf2RUgL4zmizwxnKCmm+2qmwhaF0= X-Gm-Gg: Acq92OHMFZEavP2b/UrPqtOagCwXw/Zdi+ara5ZLCZ7Qpi9l/7DPUiKHhffCOvALck7 6DyVqgFrfVjTYcJluv2MCFI7KKNhlBTtpDfedEWbYPt8wYPQYmj6aXPS8RiB7udNZ4Cf2H/6D5p f3Y3/fTLrlFvXN+o/UA7D3mlD20Fb/PClHJehyKzXr7fT1Sym2o2/GQfT/PMRLN//yLwqL+s5q2 m4zQD4DpaTysl2lD57BgkM1QC4VuGh/6OZKmsvSZWni3MGoRvGakqfRYUUaXvyK5Drz446hAjp9 rCUsiktXfGlhZj+wBoY3JlZDagN+6fmn7DVKoQnxvfooI+fvqwlrVe9/rTgRfjKcOfuVwj4jbKH C/Lo0XAwur138y6byikqarxrLoWngF+q44880H+2aOtulb2363iNF4dXngy0UEPEJWWxvw1xnBe M= X-Received: by 2002:a05:7022:3d12:b0:135:3983:2131 with SMTP id a92af1059eb24-136341c8b21mr7896445c88.21.1779820218352; Tue, 26 May 2026 11:30:18 -0700 (PDT) X-Received: by 2002:a05:7022:3d12:b0:135:3983:2131 with SMTP id a92af1059eb24-136341c8b21mr7896429c88.21.1779820217669; Tue, 26 May 2026 11:30:17 -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-1366a4011d9sm9045003c88.6.2026.05.26.11.30.17 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 26 May 2026 11:30:17 -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 v2] usb: dwc3: avoid probe deferral when USB power supply is not available Date: Tue, 26 May 2026 11:30:16 -0700 Message-Id: <20260526183016.3501307-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-GUID: FX-QQcRvotx_ShtcX_ML7BYPZVXOTjNx X-Authority-Analysis: v=2.4 cv=TZ+mcxQh c=1 sm=1 tr=0 ts=6a15e6bb cx=c_pps a=cFYjgdjTJScbgFmBucgdfQ==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=NGcC8JguVDcA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=_glEPmIy2e8OvE2BGh3C:22 a=VwQbUJbxAAAA:8 a=EUspDBNiAAAA:8 a=IQkDn3IUzkMpPxIPlJ0A:9 a=scEy_gLbYbu1JhEsrz4S:22 X-Proofpoint-ORIG-GUID: FX-QQcRvotx_ShtcX_ML7BYPZVXOTjNx X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNTI2MDE2MSBTYWx0ZWRfX862rI0hT8ITB Xycgw75PWQICTqlsamFIISKVELfJCP/cGVOVKygJTR03wPXVdupS69yK7OB5y293JOmdVYU9iyb +aIqmkn8qdprYDhRqVERq0/wXiiPtQy3va7/NoobGvY3l6bNTyBNtZqom80d/HTMoZloNPpjout SQIWrNZDqBNz3jR9o7cp7lACO/bsJdoCKwhpbZ9/JvmzsPm+vZNWbGOILPjvX4lzClzCoqfKf6B ZZwzRebxxMlvrV9GI3gVZi4gRHMO2jwM6be+XJDkqZsbC99S90UWjxdm0mQVMVvDRxFFTnyLGXz Nsrs0EamxNwI6+qiH89dNPAAmIzLq7kpqskXeLB4x7Pc5qO5PHY5RuN/9MuD/6yELN6jjJXMyW4 CX/U0u9xbAfJEc0Z+nahXA5M3iRXBYe0X6jxCz8fpH5LeQ7cjSbKI9mRQayo4e/uwv5jhmy8eLX hEmDvMsshj7Moh3Kv3Q== 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-05-26_04,2026-05-26_03,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 impostorscore=0 suspectscore=0 bulkscore=0 lowpriorityscore=0 clxscore=1015 priorityscore=1501 malwarescore=0 adultscore=0 spamscore=0 phishscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605130000 definitions=main-2605260161 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 --- 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 | 4 ++ drivers/usb/dwc3/gadget.c | 10 +++- 3 files changed, 97 insertions(+), 16 deletions(-) diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 65213896de99..c035b5fbfb2f 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 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 *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 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; + } + + 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..4854cfdbc64a 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,6 +1253,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 3d4ca68e584c..303598048e9a 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