Skip to content

Commit

Permalink
usb: cdns3: Put the cdns set active part outside the spin lock
Browse files Browse the repository at this point in the history
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 <[email protected]>
Acked-by: Peter Chen <[email protected]>
Link: https://lore.kernel.org/r/[email protected]
Signed-off-by: Greg Kroah-Hartman <[email protected]>
  • Loading branch information
Xiaolei Wang authored and gregkh committed Jul 25, 2023
1 parent 6eaae19 commit 2319b9c
Show file tree
Hide file tree
Showing 4 changed files with 20 additions and 8 deletions.
3 changes: 2 additions & 1 deletion drivers/usb/cdns3/cdns3-plat.c
Original file line number Diff line number Diff line change
Expand Up @@ -255,9 +255,10 @@ static int cdns3_controller_resume(struct device *dev, pm_message_t msg)
cdns3_set_platform_suspend(cdns->dev, false, false);

spin_lock_irqsave(&cdns->lock, flags);
cdns_resume(cdns, !PMSG_IS_AUTO(msg));
cdns_resume(cdns);
cdns->in_lpm = false;
spin_unlock_irqrestore(&cdns->lock, flags);
cdns_set_active(cdns, !PMSG_IS_AUTO(msg));
if (cdns->wakeup_pending) {
cdns->wakeup_pending = false;
enable_irq(cdns->wakeup_irq);
Expand Down
3 changes: 2 additions & 1 deletion drivers/usb/cdns3/cdnsp-pci.c
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,9 @@ static int __maybe_unused cdnsp_pci_resume(struct device *dev)
int ret;

spin_lock_irqsave(&cdns->lock, flags);
ret = cdns_resume(cdns, 1);
ret = cdns_resume(cdns);
spin_unlock_irqrestore(&cdns->lock, flags);
cdns_set_active(cdns, 1);

return ret;
}
Expand Down
15 changes: 11 additions & 4 deletions drivers/usb/cdns3/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -522,9 +522,8 @@ int cdns_suspend(struct cdns *cdns)
}
EXPORT_SYMBOL_GPL(cdns_suspend);

int cdns_resume(struct cdns *cdns, u8 set_active)
int cdns_resume(struct cdns *cdns)
{
struct device *dev = cdns->dev;
enum usb_role real_role;
bool role_changed = false;
int ret = 0;
Expand Down Expand Up @@ -556,15 +555,23 @@ int cdns_resume(struct cdns *cdns, u8 set_active)
if (cdns->roles[cdns->role]->resume)
cdns->roles[cdns->role]->resume(cdns, cdns_power_is_lost(cdns));

return 0;
}
EXPORT_SYMBOL_GPL(cdns_resume);

void cdns_set_active(struct cdns *cdns, u8 set_active)
{
struct device *dev = cdns->dev;

if (set_active) {
pm_runtime_disable(dev);
pm_runtime_set_active(dev);
pm_runtime_enable(dev);
}

return 0;
return;
}
EXPORT_SYMBOL_GPL(cdns_resume);
EXPORT_SYMBOL_GPL(cdns_set_active);
#endif /* CONFIG_PM_SLEEP */

MODULE_AUTHOR("Peter Chen <[email protected]>");
Expand Down
7 changes: 5 additions & 2 deletions drivers/usb/cdns3/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,13 @@ int cdns_init(struct cdns *cdns);
int cdns_remove(struct cdns *cdns);

#ifdef CONFIG_PM_SLEEP
int cdns_resume(struct cdns *cdns, u8 set_active);
int cdns_resume(struct cdns *cdns);
int cdns_suspend(struct cdns *cdns);
void cdns_set_active(struct cdns *cdns, u8 set_active);
#else /* CONFIG_PM_SLEEP */
static inline int cdns_resume(struct cdns *cdns, u8 set_active)
static inline int cdns_resume(struct cdns *cdns)
{ return 0; }
static inline int cdns_set_active(struct cdns *cdns, u8 set_active)
{ return 0; }
static inline int cdns_suspend(struct cdns *cdns)
{ return 0; }
Expand Down

0 comments on commit 2319b9c

Please sign in to comment.