From nobody Mon Jun 8 05:26:21 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 9C3233955DC for ; Fri, 5 Jun 2026 18:11:47 +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=1780683109; cv=none; b=iXWLUhxWzjnyMfaoHxNiXhKZFRzFq8NnFjlydBAs6MGb5CHxsz9h+rzlFIqioi+Eja3gkOubcO3zIXHlmJ3PcLEdIGsl6jJtWjX3OM718flcRX7LWQPnwmBYYrmvrDuA5nPlN5is30hjLQeINd+Tfvb3KIl2APn6hJAFE8POxW4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1780683109; c=relaxed/simple; bh=uqCubVytNSJo5ucLjzvCp/VptxWJjDUsQJvFp3Cckto=; h=From:To:Cc:Subject:Date:Message-Id:MIME-Version; b=pRpkt96Z36oR4m92H6ViiO8lxxXx/yckreVqcS2bIXEGrXVFATPxrXCb/wt0UZON/ZEGiVLnv0HPeuEac2GzyT8nPPccoQolfV3/hEfQqz+4qZ2jKZRQpHEQiu7r7/w2xusdcvK2GVdVC1mQdmVPs23cCzegJ3Htjm0lRojTTSQ= 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=TTiQiyPk; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b=WID9igZa; 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="TTiQiyPk"; dkim=pass (2048-bit key) header.d=oss.qualcomm.com header.i=@oss.qualcomm.com header.b="WID9igZa" Received: from pps.filterd (m0279863.ppops.net [127.0.0.1]) by mx0a-0031df01.pphosted.com (8.18.1.11/8.18.1.11) with ESMTP id 655CLvkC2428829 for ; Fri, 5 Jun 2026 18:11:47 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=tcO0JdaFdNA9IU7ARKvD88x76KWxgb2z07Z nvg3U3P0=; b=TTiQiyPkqGN3f+LrB9CiXQgH+Uoqeap/LiLx3mEtXFmbK8pjMBF F9NU7m5Yw3OHxVURbQnvmKkNnrmXFXCtuBe/TFOl+QabqJTxUHkP+s2A8yuEmp61 RmiK1Cj3bsOcn2n9ZCYBosgsNnfXPsh1rhFXzAsHMWKVRaOg6R/BMNCSdixO9/d3 z3JjaU32xaySA7nP+ri363Jbq8Wr5F5GbqYQz6G/AQ+fmC8IpmvYUYCRVySWEHaK du2szutPVLYSp0TEKJGtnXBv6ZrzRy3JUIUPIJDa9iZS6ISLIPz5oSE2hxM0Odcq D6bQ4YbmHIn0A7nbWxbgYZT8lOsgAr7d+9Q== Received: from mail-dy1-f200.google.com (mail-dy1-f200.google.com [74.125.82.200]) by mx0a-0031df01.pphosted.com (PPS) with ESMTPS id 4ekrphk9tp-1 (version=TLSv1.3 cipher=TLS_AES_128_GCM_SHA256 bits=128 verify=NOT) for ; Fri, 05 Jun 2026 18:11:46 +0000 (GMT) Received: by mail-dy1-f200.google.com with SMTP id 5a478bee46e88-304dd917645so2142734eec.1 for ; Fri, 05 Jun 2026 11:11:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=oss.qualcomm.com; s=google; t=1780683106; x=1781287906; 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=tcO0JdaFdNA9IU7ARKvD88x76KWxgb2z07Znvg3U3P0=; b=WID9igZaqUhleR/tuDzUjn6VqWbIYifrYa8CBK8H+7yJ8k3tqS43MPxzAHwUP/2wtT nX8/sSTNeeNJnFygkPLK+kcvJ8xa4qfvLQVcuScvy256yDsqTbJYp1el2YCXZ4upAQU2 cO/Q+zY2Uxy5mTq+RQWo3sbFvFdDnZlwt4tWytalbj/cTqb1N0f6a6N3pcBY32DxlmmY IG1JzUPF6GOdPrV/hX5QDPXufVN7ymPcp4VJRi55Mv6oTbmVKvejwRnU3sgSx3VOYO6t KrSbsr3SVYNoLOZP9GHCnur5V6xKB6bsi+XagmGiNmZhxgrmpQExlhGd1H+YbjEawiy4 vpcA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1780683106; x=1781287906; 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=tcO0JdaFdNA9IU7ARKvD88x76KWxgb2z07Znvg3U3P0=; b=k9DUxVhsuemDmVeJnzT3OxUexngtR93aOyqDIt6RMEiPLcGpiEMNCji8l8GIZ4CZui 5hsODwQypP9ncgj9504mMFJqeb2JAvoRmWc5KSPcI3jaDLrqIC8a8p4zjIFv81KluLGS EK9D5DvGC1ZqZAiXuvSmhhum5sILXiOBbNAAIfwIc/0fzsUPGH5PKbWQkf5WCq4btbKp fVbcNB89ZhRP49Z8BwDc4F35FpHkjVdQwcGZD8lo8Q5S4+ljZjMr/EY2BVpyNQeFYJxX UKLXM88auA3wNUYW3nbsNfTnsv8JJHiXuWoWhIPjSFu4E16jQnaqLXee9ha+ZOICHN60 MldA== X-Forwarded-Encrypted: i=1; AFNElJ+3nuCZAbczNkQVMD1uks2MwF+6zHr74/vCCJ+wRO0ZOzo/zKN6J8gbJ2efPzMdBorcxwRJ7i6wcbjma8o=@vger.kernel.org X-Gm-Message-State: AOJu0Yz7WTsnzEJobv/VYQmX2HNp0zPim2Yn0fUZIjAccZyJ3kJOaILH KW/MicyDT/7elRBivsJWQZnVjyXwmF/7V/MTZC733jSezARpGt2gJItekgVKojqkOhq99+6LKlv 21DyGYEZ7CHZ3H86yyRNDE20luqqf0bgACP0nanadC5xsKihgBnSaLmCfjxpsw+W8BFJaztMn1u s= X-Gm-Gg: Acq92OFqslrCqPmRDmdmC0zy0U+1dTtC+eddXpo0+a2RUyHo5A4SFSq8JVu+zfkU7u0 w+6rMXuxjT+342m8+Bc/z4QGm/ftjnpP8b5m/7zCNwfyh76/yNFBDYbbs2jogDOF7Gv7tSCG7B2 opbqKGCVO4PRKUZ/nHi/NIFEpoZHj3zs0F0zq1uSJ9aWcFipXqWbts8wBoKcptri12MKhLR90HU d+XK3Ver2mP8HZJTc9pKTU82vliZEucdfJZuFrx5GfcNMcFjR+0EF9Cllm4CGvnj5NkwUpmUZXm y6ldFYeE6cpb4S4C+bJph49dtFwG4YgUdE5NY/zdI4Pt+INNQcnuveWfLw0/fTfi+Iaq4AYZTdF CEdvfDrdjkXJSWUzP7FoN/rHCWIf1ddJpsMS4nsX6Tihikhyb/zuBTFOQ4N8X83eKbVrvanNId0 qfBESoicmWIA== X-Received: by 2002:a05:7300:6c9e:b0:2f2:5c68:5074 with SMTP id 5a478bee46e88-3077af66474mr2195059eec.13.1780683106018; Fri, 05 Jun 2026 11:11:46 -0700 (PDT) X-Received: by 2002:a05:7300:6c9e:b0:2f2:5c68:5074 with SMTP id 5a478bee46e88-3077af66474mr2195028eec.13.1780683105389; Fri, 05 Jun 2026 11:11:45 -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-3074dba046esm7644606eec.9.2026.06.05.11.11.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Fri, 05 Jun 2026 11:11:44 -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, Elson Serrao Subject: [PATCH v3] usb: dwc3: avoid probe deferral when USB power supply is not available Date: Fri, 5 Jun 2026 11:11:42 -0700 Message-Id: <20260605181142.1925832-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-ORIG-GUID: 8lrYLeBVS4wiKyTxwpTPLiMCK535U6nB X-Proofpoint-GUID: 8lrYLeBVS4wiKyTxwpTPLiMCK535U6nB X-Proofpoint-Spam-Details-Enc: AW1haW4tMjYwNjA1MDE3OSBTYWx0ZWRfX0n1iKxyfdp5N 0xz6gDyKmMe/bHU3Ja92eQSahPMo1fBHoD03uJt1ViTv3gzmat767BiYpfFMxk4U9KDy/JhnKHp a9l7s7zp1TA/yJ3op1Fg2XhfXEVc1m477tWtUBpWQDUJIYWm9yB1t20EP3Uuon9hCGnrtPrsAft rONxuMFA7yQGnu1KdrBDgG8/qafAAxE8qIMUR9ocQjNcHS7zPzDZkmyxHysiYf3tIalWaLlGFIQ 2S9ka6BVW7SOrMfg+li9TQiNPKl9pUzUevhdThhtxMXl9iSymBPaHuSjEr3IjLD0iTlaWk2//aY xLOhvvZ65/hrdN8urPSuqcTkNvY5knGUBD0Ma6WqE2GEvM/swgQfV0S3fqNHfancP/SvbFl1fda HE+yh+RqoOKKpcSE/JH0ixsVJko4ONYG7dJzaavW88BFgeP1cWFMNbLwd3OLskooYqVT6uFSOfi x7qmkFl1M7cUtBDjwJg== X-Authority-Analysis: v=2.4 cv=T9a8ifKQ c=1 sm=1 tr=0 ts=6a231162 cx=c_pps a=PfFC4Oe2JQzmKTvty2cRDw==:117 a=ouPCqIW2jiPt+lZRy3xVPw==:17 a=FelO9ux0wxsA:10 a=s4-Qcg_JpJYA:10 a=VkNPw1HP01LnGYTKEx00:22 a=u7WPNUs3qKkmUXheDGA7:22 a=yOCtJkima9RkubShWh1s:22 a=VwQbUJbxAAAA:8 a=EUspDBNiAAAA:8 a=BnH1jSTHCRmwS-4C6JUA:9 a=6Ab_bkdmUrQuMsNx7PHu:22 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-05_03,2026-06-05_02,2025-10-01_01 X-Proofpoint-Spam-Details: rule=outbound_notspam policy=outbound score=0 malwarescore=0 suspectscore=0 clxscore=1015 bulkscore=0 adultscore=0 priorityscore=1501 phishscore=0 spamscore=0 lowpriorityscore=0 impostorscore=0 classifier=typeunknown authscore=0 authtc= authcc= route=outbound adjust=0 reason=mlx scancount=1 engine=8.22.0-2605210000 definitions=main-2606050179 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 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 58899b1fa96d..8558bd3f38ea 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..d722d3f1402a 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -677,6 +677,8 @@ /* Force Gen1 speed on Gen2 link */ #define DWC3_LLUCTL_FORCE_GEN1 BIT(10) =20 +#define DWC3_CURRENT_UNSPECIFIED UINT_MAX + /* Structures */ =20 struct dwc3_trb; @@ -1059,6 +1061,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 +1255,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..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