From patchwork Mon Jun 9 12:20:47 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mathias Nyman X-Patchwork-Id: 895511 Received: from mgamail.intel.com (mgamail.intel.com [198.175.65.17]) (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 E9FA77FD; Mon, 9 Jun 2025 12:20:57 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=198.175.65.17 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749471659; cv=none; b=ofr6QNRcToYwxo1IB8iJFsliH+i76EpcOHZdPS05meMJtxUYHRTaHNws/ljsu+2UZl4WUyb/j5+fDxQjunnFLhHBdJmUS09j3kFoDTkCY7KfkW+g6xI6lv9fofcXJAM7CPcStTULg45jxIBUm7+jQF2qOuBw9DnZFAVSaCP3Lac= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1749471659; c=relaxed/simple; bh=OFRtAhWSdSsaWqLAHuWOTpcG0lFqGPZRe/VR1ANVDbE=; h=From:To:Cc:Subject:Date:Message-ID:MIME-Version; b=ePlAcfkcacMUsSbqjrOmk9o8R38EY45wARTyFEJNsuZX2pY//2VdvVr+0KqkdrG1vDX3tUkAGA6jXzdSllEUUztKpjrY99TKiiKKR3u9Go4YVCcjS/q2xEqrU2A5e33nsTKKE83CatoVUMpQvlOeXl1eTqfsHZsTkP0ryZ47sIY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com; spf=none smtp.mailfrom=linux.intel.com; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b=QYMEUHgb; arc=none smtp.client-ip=198.175.65.17 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; spf=none smtp.mailfrom=linux.intel.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=intel.com header.i=@intel.com header.b="QYMEUHgb" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1749471658; x=1781007658; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=OFRtAhWSdSsaWqLAHuWOTpcG0lFqGPZRe/VR1ANVDbE=; b=QYMEUHgb9/8gBqf7NJdbjS5n8gZtwhCnvo6qMSFdG24v93We12tpX/Eq 7G3v1gED31xHyXZOS78PQX2JWTSzbX1ZDhL6Pw4lgwEGczzwuUodCgjJP wCAVGVOS4ttSVeG9Pv66undsAlCW7zpgf9knhT/cfHlSOc86DtoBXGDSb qZNFgj49gPxZBcuVEC90NoTb7wFMkzw0ycqXwuXcftjL8+4XYxs09XXVx vPeBgCSGPCpAOC7P+Be30ePd56rMqjB3fsSL4Uj/TIaryV8rjP2x2uXg5 TCSRzjOwnZ++uNkwJy0ckmYlEGhnx20M8PSWiT8cXn2quxKJostzTMHCI g==; X-CSE-ConnectionGUID: LXPdj5FQSluROfeaEGvCBg== X-CSE-MsgGUID: VKfpd7qFSq6L6eYj6N0WuQ== X-IronPort-AV: E=McAfee;i="6800,10657,11459"; a="51538650" X-IronPort-AV: E=Sophos;i="6.16,222,1744095600"; d="scan'208";a="51538650" Received: from fmviesa004.fm.intel.com ([10.60.135.144]) by orvoesa109.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 09 Jun 2025 05:20:58 -0700 X-CSE-ConnectionGUID: 1L6yiYf6RNuYZUFgwJEZEQ== X-CSE-MsgGUID: U8gnwLn5TjKz10TtGhhxAw== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.16,222,1744095600"; d="scan'208";a="151656029" Received: from unknown (HELO mnyman-desk.fi.intel.com) ([10.237.72.199]) by fmviesa004.fm.intel.com with ESMTP; 09 Jun 2025 05:20:55 -0700 From: Mathias Nyman To: Cc: , , Mathias Nyman , stable@vger.kernel.org Subject: [PATCH] usb: hub: fix detection of high tier USB3 devices behind suspended hubs Date: Mon, 9 Jun 2025 15:20:47 +0300 Message-ID: <20250609122047.1945539-1-mathias.nyman@linux.intel.com> X-Mailer: git-send-email 2.43.0 Precedence: bulk X-Mailing-List: linux-usb@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 USB3 devices connected behind several external suspended hubs may not be detected when plugged in due to aggressive hub runtime pm suspend. The hub driver immediately runtime-suspends hubs if there are no active children or port activity. There is a delay between the wake signal causing hub resume, and driver visible port activity on the hub downstream facing ports. Most of the LFPS handshake, resume signaling and link training done on the downstream ports is not visible to the hub driver until completed, when device then will appear fully enabled and running on the port. This delay between wake signal and detectable port change is even more significant with chained suspended hubs where the wake signal will propagate upstream first. Suspended hubs will only start resuming downstream ports after upstream facing port resumes. The hub driver may resume a USB3 hub, read status of all ports, not yet see any activity, and runtime suspend back the hub before any port activity is visible. This exact case was seen when conncting USB3 devices to a suspended Thunderbolt dock. USB3 specification defines a 100ms tU3WakeupRetryDelay, indicating USB3 devices expect to be resumed within 100ms after signaling wake. if not then device will resend the wake signal. Give the USB3 hubs twice this time (200ms) to detect any port changes after resume, before allowing hub to runtime suspend again. Cc: stable@vger.kernel.org Fixes: 596d789a211d ("USB: set hub's default autosuspend delay as 0") Signed-off-by: Mathias Nyman --- drivers/usb/core/hub.c | 33 ++++++++++++++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c index 770d1e91183c..5c12dfdef569 100644 --- a/drivers/usb/core/hub.c +++ b/drivers/usb/core/hub.c @@ -68,6 +68,12 @@ */ #define USB_SHORT_SET_ADDRESS_REQ_TIMEOUT 500 /* ms */ +/* + * Give SS hubs 200ms time after wake to train downstream links before + * assuming no port activity and allowing hub to runtime suspend back. + */ +#define USB_SS_PORT_U0_WAKE_TIME 200 /* ms */ + /* Protect struct usb_device->state and ->children members * Note: Both are also protected by ->dev.sem, except that ->state can * change to USB_STATE_NOTATTACHED even when the semaphore isn't held. */ @@ -1068,11 +1074,12 @@ int usb_remove_device(struct usb_device *udev) enum hub_activation_type { HUB_INIT, HUB_INIT2, HUB_INIT3, /* INITs must come first */ - HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, + HUB_POST_RESET, HUB_RESUME, HUB_RESET_RESUME, HUB_POST_RESUME, }; static void hub_init_func2(struct work_struct *ws); static void hub_init_func3(struct work_struct *ws); +static void hub_post_resume(struct work_struct *ws); static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) { @@ -1095,6 +1102,13 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) goto init2; goto init3; } + + if (type == HUB_POST_RESUME) { + usb_autopm_put_interface_async(to_usb_interface(hub->intfdev)); + hub_put(hub); + return; + } + hub_get(hub); /* The superspeed hub except for root hub has to use Hub Depth @@ -1343,6 +1357,16 @@ static void hub_activate(struct usb_hub *hub, enum hub_activation_type type) device_unlock(&hdev->dev); } + if (type == HUB_RESUME && hub_is_superspeed(hub->hdev)) { + /* give usb3 downstream links training time after hub resume */ + INIT_DELAYED_WORK(&hub->init_work, hub_post_resume); + queue_delayed_work(system_power_efficient_wq, &hub->init_work, + msecs_to_jiffies(USB_SS_PORT_U0_WAKE_TIME)); + usb_autopm_get_interface_no_resume( + to_usb_interface(hub->intfdev)); + return; + } + hub_put(hub); } @@ -1361,6 +1385,13 @@ static void hub_init_func3(struct work_struct *ws) hub_activate(hub, HUB_INIT3); } +static void hub_post_resume(struct work_struct *ws) +{ + struct usb_hub *hub = container_of(ws, struct usb_hub, init_work.work); + + hub_activate(hub, HUB_POST_RESUME); +} + enum hub_quiescing_type { HUB_DISCONNECT, HUB_PRE_RESET, HUB_SUSPEND };