Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: cdns3: Put the cdns set active part outside the spin lock

The device may be scheduled during the resume process,
so this cannot appear in atomic operations. Since
pm_runtime_set_active will resume suppliers, put set
active outside the spin lock, which is only used to
protect the struct cdns data structure, otherwise the
kernel will report the following warning:

BUG: sleeping function called from invalid context at drivers/base/power/runtime.c:1163
in_atomic(): 1, irqs_disabled(): 0, non_block: 0, pid: 651, name: sh
preempt_count: 1, expected: 0
RCU nest depth: 0, expected: 0
CPU: 0 PID: 651 Comm: sh Tainted: G WC 6.1.20 #1
Hardware name: Freescale i.MX8QM MEK (DT)
Call trace:
dump_backtrace.part.0+0xe0/0xf0
show_stack+0x18/0x30
dump_stack_lvl+0x64/0x80
dump_stack+0x1c/0x38
__might_resched+0x1fc/0x240
__might_sleep+0x68/0xc0
__pm_runtime_resume+0x9c/0xe0
rpm_get_suppliers+0x68/0x1b0
__pm_runtime_set_status+0x298/0x560
cdns_resume+0xb0/0x1c0
cdns3_controller_resume.isra.0+0x1e0/0x250
cdns3_plat_resume+0x28/0x40

Signed-off-by: Xiaolei Wang <xiaolei.wang@windriver.com>
Acked-by: Peter Chen <peter.chen@kernel.org>
Link: https://lore.kernel.org/r/20230616021952.1025854-1-xiaolei.wang@windriver.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Xiaolei Wang and committed by
Greg Kroah-Hartman
2319b9c8 6eaae198

+20 -8
+2 -1
drivers/usb/cdns3/cdns3-plat.c
··· 255 255 cdns3_set_platform_suspend(cdns->dev, false, false); 256 256 257 257 spin_lock_irqsave(&cdns->lock, flags); 258 - cdns_resume(cdns, !PMSG_IS_AUTO(msg)); 258 + cdns_resume(cdns); 259 259 cdns->in_lpm = false; 260 260 spin_unlock_irqrestore(&cdns->lock, flags); 261 + cdns_set_active(cdns, !PMSG_IS_AUTO(msg)); 261 262 if (cdns->wakeup_pending) { 262 263 cdns->wakeup_pending = false; 263 264 enable_irq(cdns->wakeup_irq);
+2 -1
drivers/usb/cdns3/cdnsp-pci.c
··· 208 208 int ret; 209 209 210 210 spin_lock_irqsave(&cdns->lock, flags); 211 - ret = cdns_resume(cdns, 1); 211 + ret = cdns_resume(cdns); 212 212 spin_unlock_irqrestore(&cdns->lock, flags); 213 + cdns_set_active(cdns, 1); 213 214 214 215 return ret; 215 216 }
+11 -4
drivers/usb/cdns3/core.c
··· 522 522 } 523 523 EXPORT_SYMBOL_GPL(cdns_suspend); 524 524 525 - int cdns_resume(struct cdns *cdns, u8 set_active) 525 + int cdns_resume(struct cdns *cdns) 526 526 { 527 - struct device *dev = cdns->dev; 528 527 enum usb_role real_role; 529 528 bool role_changed = false; 530 529 int ret = 0; ··· 555 556 if (cdns->roles[cdns->role]->resume) 556 557 cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns)); 557 558 559 + return 0; 560 + } 561 + EXPORT_SYMBOL_GPL(cdns_resume); 562 + 563 + void cdns_set_active(struct cdns *cdns, u8 set_active) 564 + { 565 + struct device *dev = cdns->dev; 566 + 558 567 if (set_active) { 559 568 pm_runtime_disable(dev); 560 569 pm_runtime_set_active(dev); 561 570 pm_runtime_enable(dev); 562 571 } 563 572 564 - return 0; 573 + return; 565 574 } 566 - EXPORT_SYMBOL_GPL(cdns_resume); 575 + EXPORT_SYMBOL_GPL(cdns_set_active); 567 576 #endif /* CONFIG_PM_SLEEP */ 568 577 569 578 MODULE_AUTHOR("Peter Chen <peter.chen@nxp.com>");
+5 -2
drivers/usb/cdns3/core.h
··· 125 125 int cdns_remove(struct cdns *cdns); 126 126 127 127 #ifdef CONFIG_PM_SLEEP 128 - int cdns_resume(struct cdns *cdns, u8 set_active); 128 + int cdns_resume(struct cdns *cdns); 129 129 int cdns_suspend(struct cdns *cdns); 130 + void cdns_set_active(struct cdns *cdns, u8 set_active); 130 131 #else /* CONFIG_PM_SLEEP */ 131 - static inline int cdns_resume(struct cdns *cdns, u8 set_active) 132 + static inline int cdns_resume(struct cdns *cdns) 133 + { return 0; } 134 + static inline int cdns_set_active(struct cdns *cdns, u8 set_active) 132 135 { return 0; } 133 136 static inline int cdns_suspend(struct cdns *cdns) 134 137 { return 0; }