From nobody Mon Sep 28 07:24:17 2026 Received: from out203-205-221-235.mail.qq.com (out203-205-221-235.mail.qq.com [203.205.221.235]) (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 D74EB38736E; Tue, 25 Aug 2026 09:09:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=203.205.221.235 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787648974; cv=none; b=MCOA40ftias8jJnbAHSGCPbteDXpPMzvr3KQw9UT+PM+rO9f9hqYcuQGywKQwREXfxUcnJvEjuaX5Ul6yk+PzeT2pchnQLLtGjwDRtVwfV3unoRFm6/tL06jNUH7+n4wmjz8EtAdBWEjQQU664wLTkQ7SmonYYmVGdur07F8oag= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1787648974; c=relaxed/simple; bh=CkjGispeNeATmQv6Xi2E8JuUM/PZSRCjFjw3y9D6BVA=; h=Message-ID:Date:MIME-Version:To:Cc:From:Subject:Content-Type; b=l1ixgUn2CgJ7dx9L87Mf+SrdPVGhC9hJU9uGeo5lOCZf/e7wRHBMSsvHqy+gxtosdILJjsqM/Jh+QxBmBLLlp4UEeAgfGSzzo7zg+xJrDCU0rl9cgKqqYfodz9IxuEHwL0QEuYSiqujO6JlwTBcKaXwMweYoPEf39cD05DjWdd8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=qq.com; spf=pass smtp.mailfrom=qq.com; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b=BCALfqP2; arc=none smtp.client-ip=203.205.221.235 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=quarantine dis=none) header.from=qq.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=qq.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (1024-bit key) header.d=qq.com header.i=@qq.com header.b="BCALfqP2" DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=qq.com; s=s201512; t=1787648962; bh=CkjGispeNeATmQv6Xi2E8JuUM/PZSRCjFjw3y9D6BVA=; h=Date:To:Cc:From:Subject; b=BCALfqP2vbIhClaX7zj1wTl3ZYCRYTNjxr9qQv7U2HTO/d1LjENGnQe4p79GJXyhA Y3b3OZ5MZToXhZKuU0x1w0UJ3ARdLE+vU+cwYKoVNsS7jjRjdq7WRV4bu8V6x+BCR3 QMX5wQRKuAPvB4Kg5bN5bpyWlQRrG4Ekvgs0PG3k= Received: from [192.168.255.10] ([111.206.145.19]) by newxmesmtplogicsvrsza53-0.qq.com (NewEsmtp) with SMTP id 254B40F8; Tue, 25 Aug 2026 17:09:20 +0800 X-QQ-mid: xmsmtpt1787648960tu4luly1m Message-ID: X-QQ-XMAILINFO: N/WmRbclY25G1B4NRc14k3FrqnI2CHxVBIriFmfn/o48iNol2hRC1Is6Gb/VDR K00i3wgfIL4X554ikRxU1aqvPJd/3ScsA6XpQvH/hytEAtpa0XMgEQqxVLACRlDAwxfSjGoPgqD0 qYPBc+3hhvLRjkEwLu4FlQV0mqclohscnoSbgGy7IEdc5UgTJ0rWGRWu3l+6j6hdoebN893bTEkD cU7NWcbYhQLBiUj9LmAoxmd9JkOcNS3RpYLkZqXS3yVimUFkETmcSalhEQbVG2oAsnRFrQUmWscJ 95zBfpIgUTNsOrkyPmnWsI1T57WyFngD2DdcoFodAn1VaWPoYQeOj2+sOYnaB/3418IcAPPVR1K5 G17a61PuPw8FqWC18NFJRzjg//z3UF+0n3HC4190CEU9HTiVPtkk4PHS9vo+joSj6sXRyUeAE/uS c3TGlLjpUAYkx+EPABiZWZa51ZAoCXSipyLz906S5BREylbLFV+poZ88qkYFvW0cSevSt8D7fhTQ 8xYLK1qkL0cP4QMIopaECSEJRx6t2OXMIuK7wrM4LTsiQwwxhu9TdBNhc8rA6L+z3Dzhc4YP61TC FL39omy5S2VMKjj6zOxGpi3dWsMRyqfFUH0wkYogKZG9+bmpAMerEJj6sJAQn771e9+PAnhadRZk hUnrygd5e1HTsFRZ5C9ETowBbzQd5SJ+vEdPKcOlxyleUnHJJsw/kHYqwAMND4g5SJE0hAi3pVll 3vHPXCQRVYR0fW3grO6afCSuMQgYKxJlaLYuWYYXt8d1V98Td8kvLvHkrePIUA87yWaL03RPniLw AbvWwDfavlekFRd+gd3hJ1fCLjZnPio/P2wi0x3XxjejD7E5HQQA+1NP8LoGSfdv8cKwRyaV21R6 EmVOYNxFG2ExxA17m+DZKABBU3XRcFm2ycSADY7hra8/DcpkM368knby2AGNF8lbWiRGD7EiAF0G nj3uNfwIQAtn02+hQ1LSOU7soZR2SAXKSCRQ5/Ea9UTzkEwjIJdSnLxknEQzmITkVQSI8N+4neix r1DxvVq1suQp55fVaqRP67g7s2+zq+ocNvaqVpb2H7Ga6rBmCvjjMuM2xR7dbxP8RWKy48o9Mau+ /jXt2nkPU7a3aT5BwykutwlY39+g== X-QQ-XMRINFO: NyFYKkN4Ny6FuXrnB5Ye7Aabb3ujjtK+gg== X-OQ-MSGID: Date: Tue, 25 Aug 2026 17:09:19 +0800 Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 User-Agent: Mozilla Thunderbird To: mathias.nyman@intel.com, gregkh@linuxfoundation.org Cc: linux-usb@vger.kernel.org, linux-kernel@vger.kernel.org From: Yang Zi <2959243019@qq.com> Subject: [PATCH] usb: xhci: Fix lockdep warning when entering test mode Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable xhci_enter_test_mode() and xhci_set_port_power() are annotated __must_hold(&xhci->lock), yet both drop the lock in the middle of the function: xhci_enter_test_mode() around the slot-disable loop (because xhci_disable_and_free_slot() takes the lock itself and can sleep) and xhci_set_port_power() around the ACPI power-state calls. xhci->lock is also taken from hardirq context in xhci_irq(), so it is a hardirq-safe lock.=C2=A0 Dropping it with spin_unlock_irqrestore() re-enabl= es interrupts while the lock is still held, and lockdep's trace_hardirqs_on() -> mark_held_locks() then records the lock as HARDIRQ-ON-W, which conflicts with the IN-HARDIRQ-W usage registered by xhci_irq(): =C2=A0 =C2=A0 inconsistent {IN-HARDIRQ-W} -> {HARDIRQ-ON-W} usage. Fix this by releasing the lock *before* re-enabling interrupts (and, on the way back, disabling interrupts before re-acquiring the lock), so the hardirq-safe lock is never held with IRQs enabled.=C2=A0 Also drop the incorrect __must_hold() annotations and pass the saved IRQ state by value so these helpers cannot clobber the caller's flags. This patch is tentative and needs maintainer review. Signed-off-by: Yang Zi <2959243019@qq.com> --- diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index b0264bd8577a..c28d278f45b0 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -638,12 +638,19 @@ struct xhci_hub *xhci_get_rhub(struct usb_hcd *hcd) =C2=A0 =C2=A0/* =C2=A0 * xhci_set_port_power() must be called with xhci->lock held. - * It will release and re-acquire the lock while calling ACPI - * method. + * It drops the lock while calling the ACPI method, which may sleep, and + * re-acquires it before returning. + * + * The lock is released *before* interrupts are re-enabled because + * xhci->lock is also taken in hardirq context (xhci_irq()) and must never + * be held with IRQs enabled. + * + * @flags is passed by value: it is the IRQ state saved by the caller's + * spin_lock_irqsave() and must not be clobbered by the lock/irqsave dance + * below, so the caller can later restore it with spin_unlock_irqrestore(). =C2=A0 */ =C2=A0static void xhci_set_port_power(struct xhci_hcd *xhci, struct xhci_po= rt *port, -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool on, unsigned = long *flags) -=C2=A0 =C2=A0 __must_hold(&xhci->lock) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 bool on, unsigned = long flags) =C2=A0{ =C2=A0 =C2=A0 =C2=A0struct usb_hcd *hcd; =C2=A0 =C2=A0 =C2=A0u32 temp; @@ -665,13 +672,15 @@ static void xhci_set_port_power(struct xhci_hcd *xhci= , struct xhci_port *port, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0xhci_portsc_writel(port, temp & ~PORT_POW= ER); =C2=A0 =C2=A0 =C2=A0} =C2=A0 -=C2=A0 =C2=A0 spin_unlock_irqrestore(&xhci->lock, *flags); +=C2=A0 =C2=A0 spin_unlock(&xhci->lock); +=C2=A0 =C2=A0 local_irq_restore(flags); =C2=A0 =C2=A0 =C2=A0temp =3D usb_acpi_power_manageable(hcd->self.root_hub, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 port->hcd_portnum); =C2=A0 =C2=A0 =C2=A0if (temp) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0usb_acpi_set_power_state(hcd->self.root_h= ub, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2= =A0 port->hcd_portnum, on); -=C2=A0 =C2=A0 spin_lock_irqsave(&xhci->lock, *flags); +=C2=A0 =C2=A0 local_irq_save(flags); +=C2=A0 =C2=A0 spin_lock(&xhci->lock); =C2=A0} =C2=A0 =C2=A0static void xhci_port_set_test_mode(struct xhci_hcd *xhci, u16 test_m= ode, int portnum) @@ -689,15 +698,24 @@ static void xhci_port_set_test_mode(struct xhci_hcd *= xhci, u16 test_mode, int po =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0xhci_start(xhci); =C2=A0} =C2=A0 +/* + * xhci_enter_test_mode() is called with xhci->lock held. It drops the lock + * around the slot-disable loop because xhci_disable_and_free_slot() takes + * xhci->lock itself and can sleep, then re-acquires it for the remainder = of + * the function. The lock is released before interrupts are re-enabled sin= ce + * xhci->lock is also taken in hardirq context (xhci_irq()). + * + * @flags is passed by value so the caller's saved IRQ state is preserved. + */ =C2=A0static int xhci_enter_test_mode(struct xhci_hcd *xhci, u16 test_mode,= int portnum, -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned long *fla= gs) -=C2=A0 =C2=A0 __must_hold(&xhci->lock) +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 unsigned long flag= s) =C2=A0{ =C2=A0 =C2=A0 =C2=A0int i, retval; =C2=A0 =C2=A0 =C2=A0 =C2=A0/* Disable all Device Slots */ =C2=A0 =C2=A0 =C2=A0xhci_dbg(xhci, "Disable all slots\n"); -=C2=A0 =C2=A0 spin_unlock_irqrestore(&xhci->lock, *flags); +=C2=A0 =C2=A0 spin_unlock(&xhci->lock); +=C2=A0 =C2=A0 local_irq_restore(flags); =C2=A0 =C2=A0 =C2=A0for (i =3D 1; i <=3D xhci->max_slots; i++) { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (!xhci->devs[i]) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0continue; @@ -707,7 +725,8 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, = u16 test_mode, int portnu =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0xhci_err(xhci, "Failed to d= isable slot %d, %d. Enter test mode anyway\n", =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 i, retval); =C2=A0 =C2=A0 =C2=A0} -=C2=A0 =C2=A0 spin_lock_irqsave(&xhci->lock, *flags); +=C2=A0 =C2=A0 local_irq_save(flags); +=C2=A0 =C2=A0 spin_lock(&xhci->lock); =C2=A0 =C2=A0 =C2=A0/* Put all ports to the Disable state by clear PP */ =C2=A0 =C2=A0 =C2=A0xhci_dbg(xhci, "Disable all port (PP =3D 0)\n"); =C2=A0 =C2=A0 =C2=A0/* Power off USB3 ports*/ @@ -1463,7 +1482,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq= , u16 wValue, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * However, hub_wq will ign= ore the roothub events until =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 * the roothub is registere= d. =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 */ -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xhci_set_port_power(xhci, port, = true, &flags); +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xhci_set_port_power(xhci, port, = true, flags); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case USB_PORT_FEAT_RESET: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0portsc |=3D PORT_RESET; @@ -1514,7 +1533,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq= , u16 wValue, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if (test_mode > USB_TEST_FO= RCE_ENABLE || =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0test_mode < U= SB_TEST_J) =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto error; -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 retval =3D xhci_enter_test_mode(= xhci, test_mode, portnum, &flags); +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 retval =3D xhci_enter_test_mode(= xhci, test_mode, portnum, flags); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0default: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0goto error; @@ -1581,7 +1600,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq= , u16 wValue, =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0xhci_disable_port(xhci, por= t); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case USB_PORT_FEAT_POWER: -=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xhci_set_port_power(xhci, port, = false, &flags); +=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 xhci_set_port_power(xhci, port, = false, flags); =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0break; =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0case USB_PORT_FEAT_TEST: =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0retval =3D xhci_exit_test_m= ode(xhci);