]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob
a1d4310b48f8bc3f4d50d7953040449147399626
[thirdparty/kernel/stable-queue.git] /
1 From 7838de15bb700c2898a7d741db9b1f3cbc86c136 Mon Sep 17 00:00:00 2001
2 From: Meng Li <Meng.Li@windriver.com>
3 Date: Tue, 18 Jun 2024 11:19:18 +0800
4 Subject: usb: dwc3: core: remove lock of otg mode during gadget suspend/resume to avoid deadlock
5
6 From: Meng Li <Meng.Li@windriver.com>
7
8 commit 7838de15bb700c2898a7d741db9b1f3cbc86c136 upstream.
9
10 When config CONFIG_USB_DWC3_DUAL_ROLE is selected, and trigger system
11 to enter suspend status with below command:
12 echo mem > /sys/power/state
13 There will be a deadlock issue occurring. Detailed invoking path as
14 below:
15 dwc3_suspend_common()
16 spin_lock_irqsave(&dwc->lock, flags); <-- 1st
17 dwc3_gadget_suspend(dwc);
18 dwc3_gadget_soft_disconnect(dwc);
19 spin_lock_irqsave(&dwc->lock, flags); <-- 2nd
20 This issue is exposed by commit c7ebd8149ee5 ("usb: dwc3: gadget: Fix
21 NULL pointer dereference in dwc3_gadget_suspend") that removes the code
22 of checking whether dwc->gadget_driver is NULL or not. It causes the
23 following code is executed and deadlock occurs when trying to get the
24 spinlock. In fact, the root cause is the commit 5265397f9442("usb: dwc3:
25 Remove DWC3 locking during gadget suspend/resume") that forgot to remove
26 the lock of otg mode. So, remove the redundant lock of otg mode during
27 gadget suspend/resume.
28
29 Fixes: 5265397f9442 ("usb: dwc3: Remove DWC3 locking during gadget suspend/resume")
30 Cc: Xu Yang <xu.yang_2@nxp.com>
31 Cc: stable@vger.kernel.org
32 Signed-off-by: Meng Li <Meng.Li@windriver.com>
33 Acked-by: Thinh Nguyen <Thinh.Nguyen@synopsys.com>
34 Link: https://lore.kernel.org/r/20240618031918.2585799-1-Meng.Li@windriver.com
35 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
36 ---
37 drivers/usb/dwc3/core.c | 6 ------
38 1 file changed, 6 deletions(-)
39
40 --- a/drivers/usb/dwc3/core.c
41 +++ b/drivers/usb/dwc3/core.c
42 @@ -2084,7 +2084,6 @@ assert_reset:
43
44 static int dwc3_suspend_common(struct dwc3 *dwc, pm_message_t msg)
45 {
46 - unsigned long flags;
47 u32 reg;
48
49 switch (dwc->current_dr_role) {
50 @@ -2122,9 +2121,7 @@ static int dwc3_suspend_common(struct dw
51 break;
52
53 if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
54 - spin_lock_irqsave(&dwc->lock, flags);
55 dwc3_gadget_suspend(dwc);
56 - spin_unlock_irqrestore(&dwc->lock, flags);
57 synchronize_irq(dwc->irq_gadget);
58 }
59
60 @@ -2141,7 +2138,6 @@ static int dwc3_suspend_common(struct dw
61
62 static int dwc3_resume_common(struct dwc3 *dwc, pm_message_t msg)
63 {
64 - unsigned long flags;
65 int ret;
66 u32 reg;
67
68 @@ -2190,9 +2186,7 @@ static int dwc3_resume_common(struct dwc
69 if (dwc->current_otg_role == DWC3_OTG_ROLE_HOST) {
70 dwc3_otg_host_init(dwc);
71 } else if (dwc->current_otg_role == DWC3_OTG_ROLE_DEVICE) {
72 - spin_lock_irqsave(&dwc->lock, flags);
73 dwc3_gadget_resume(dwc);
74 - spin_unlock_irqrestore(&dwc->lock, flags);
75 }
76
77 break;