diff options
author | Tony Lindgren <tony@atomide.com> | 2016-11-16 22:21:23 +0300 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2016-11-17 18:25:39 +0300 |
commit | ea2f35c01d5ea72b43b9b4fb4c5b9417a9eb2fb8 (patch) | |
tree | 8dfa4ef390e0738db2c7d0f2c179a5c7b7a1ae7d /drivers/usb/musb/musb_core.h | |
parent | c723bd6ec2b50e7c8b3424d9cb8febd8ffa3da1f (diff) | |
download | linux-ea2f35c01d5ea72b43b9b4fb4c5b9417a9eb2fb8.tar.xz |
usb: musb: Fix sleeping function called from invalid context for hdrc glue
Commit 65b3f50ed6fa ("usb: musb: Add PM runtime support for MUSB DSPS
glue layer") wrongly added a call for pm_runtime_get_sync to otg_timer
that runs in softirq context. That causes a "BUG: sleeping function called
from invalid context" every time when polling the cable status:
[<c015ebb4>] (__might_sleep) from [<c0413d60>] (__pm_runtime_resume+0x9c/0xa0)
[<c0413d60>] (__pm_runtime_resume) from [<c04d0bc4>] (otg_timer+0x3c/0x254)
[<c04d0bc4>] (otg_timer) from [<c0191180>] (call_timer_fn+0xfc/0x41c)
[<c0191180>] (call_timer_fn) from [<c01915c0>] (expire_timers+0x120/0x210)
[<c01915c0>] (expire_timers) from [<c0191acc>] (run_timer_softirq+0xa4/0xdc)
[<c0191acc>] (run_timer_softirq) from [<c010168c>] (__do_softirq+0x12c/0x594)
I did not notice that as I did not have CONFIG_DEBUG_ATOMIC_SLEEP enabled.
And looks like also musb_gadget_queue() suffers from the same problem.
Let's fix the issue by using a list of delayed work then call it on
resume. Note that we want to do this only when musb core and it's
parent devices are awake, and we need to make sure the DSPS glue
timer is stopped as noted by Johan Hovold <johan@kernel.org>.
Note that we already are re-enabling the timer with mod_timer() in
dsps_musb_enable().
Later on we may be able to remove other delayed work in the musb driver
and just do it from pending_resume_work. But this should be done only
for delayed work that does not have other timing requirements beyond
just being run on resume.
Fixes: 65b3f50ed6fa ("usb: musb: Add PM runtime support for MUSB DSPS
glue layer")
Reported-by: Johan Hovold <johan@kernel.org>
Reviewed-by: Johan Hovold <johan@kernel.org>
Tested-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Tony Lindgren <tony@atomide.com>
Signed-off-by: Bin Liu <b-liu@ti.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/usb/musb/musb_core.h')
-rw-r--r-- | drivers/usb/musb/musb_core.h | 7 |
1 files changed, 7 insertions, 0 deletions
diff --git a/drivers/usb/musb/musb_core.h b/drivers/usb/musb/musb_core.h index c04abf424c5c..15b1f93c7037 100644 --- a/drivers/usb/musb/musb_core.h +++ b/drivers/usb/musb/musb_core.h @@ -303,6 +303,7 @@ struct musb_context_registers { struct musb { /* device lock */ spinlock_t lock; + spinlock_t list_lock; /* resume work list lock */ struct musb_io io; const struct musb_platform_ops *ops; @@ -337,6 +338,7 @@ struct musb { struct list_head control; /* of musb_qh */ struct list_head in_bulk; /* of musb_qh */ struct list_head out_bulk; /* of musb_qh */ + struct list_head pending_list; /* pending work list */ struct timer_list otg_timer; struct notifier_block nb; @@ -386,6 +388,7 @@ struct musb { unsigned long idle_timeout; /* Next timeout in jiffies */ unsigned is_initialized:1; + unsigned is_runtime_suspended:1; /* active means connected and not suspended */ unsigned is_active:1; @@ -542,6 +545,10 @@ extern irqreturn_t musb_interrupt(struct musb *); extern void musb_hnp_stop(struct musb *musb); +int musb_queue_resume_work(struct musb *musb, + int (*callback)(struct musb *musb, void *data), + void *data); + static inline void musb_platform_set_vbus(struct musb *musb, int is_on) { if (musb->ops->set_vbus) |