[PATCH 2/6] usb: musb: Fix sleeping function called from invalid context for hdrc glue

2016-11-16 Thread Bin Liu
From: Tony Lindgren 

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:

[] (__might_sleep) from [] (__pm_runtime_resume+0x9c/0xa0)
[] (__pm_runtime_resume) from [] (otg_timer+0x3c/0x254)
[] (otg_timer) from [] (call_timer_fn+0xfc/0x41c)
[] (call_timer_fn) from [] (expire_timers+0x120/0x210)
[] (expire_timers) from [] (run_timer_softirq+0xa4/0xdc)
[] (run_timer_softirq) from [] (__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 .
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 
Reviewed-by: Johan Hovold 
Tested-by: Laurent Pinchart 
Signed-off-by: Tony Lindgren 
Signed-off-by: Bin Liu 
---
 drivers/usb/musb/musb_core.c   | 109 +++--
 drivers/usb/musb/musb_core.h   |   7 +++
 drivers/usb/musb/musb_dsps.c   |  36 ++
 drivers/usb/musb/musb_gadget.c |  33 +++--
 4 files changed, 167 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
index f1ea4494dcb2..384de6cd26f5 100644
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1969,6 +1969,7 @@ static struct musb *allocate_instance(struct device *dev,
INIT_LIST_HEAD(&musb->control);
INIT_LIST_HEAD(&musb->in_bulk);
INIT_LIST_HEAD(&musb->out_bulk);
+   INIT_LIST_HEAD(&musb->pending_list);
 
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -2018,6 +2019,84 @@ static void musb_free(struct musb *musb)
musb_host_free(musb);
 }
 
+struct musb_pending_work {
+   int (*callback)(struct musb *musb, void *data);
+   void *data;
+   struct list_head node;
+};
+
+/*
+ * Called from musb_runtime_resume(), musb_resume(), and
+ * musb_queue_resume_work(). Callers must take musb->lock.
+ */
+static int musb_run_resume_work(struct musb *musb)
+{
+   struct musb_pending_work *w, *_w;
+   unsigned long flags;
+   int error = 0;
+
+   spin_lock_irqsave(&musb->list_lock, flags);
+   list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
+   if (w->callback) {
+   error = w->callback(musb, w->data);
+   if (error < 0) {
+   dev_err(musb->controller,
+   "resume callback %p failed: %i\n",
+   w->callback, error);
+   }
+   }
+   list_del(&w->node);
+   devm_kfree(musb->controller, w);
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+
+/*
+ * Called to run work if device is active or else queue the work to happen
+ * on resume. Caller must take musb->lock and must hold an RPM reference.
+ *
+ * Note that we cowardly refuse queuing work after musb PM runtime
+ * resume is done calling musb_run_resume_work() and return -EINPROGRESS
+ * instead.
+ */
+int musb_queue_resume_work(struct musb *musb,
+  int (*callback)(struct musb *musb, void *data),
+  void *data)
+{
+   struct musb_pending_work *w;
+   unsigned long flags;
+   int error;
+
+   if (WARN_ON(!callback))
+   return -EINVAL;
+
+   if (pm_runtime_active(musb->controller))
+   return callback(musb, data);
+
+   w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
+   if (!w)
+   return -ENOMEM;
+
+   w->callback = callback;
+   w->data = data;
+   spin_lock_irqsave(&musb->list_lock, flags);
+   if (musb->is_runtime_suspended) {
+   list_add_tail(&w->node, &musb->pending_list);
+   error = 0;
+   } else {
+   dev_err(musb->controller, "could not add resume work %p\n",
+   callback);
+   devm_kfree(musb->controller, w);
+   error = -EINPROGRESS;
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+EXPORT_SYMBOL_

[PATCH 2/6] usb: musb: Fix sleeping function called from invalid context for hdrc glue

2016-11-15 Thread Tony Lindgren
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:

[] (__might_sleep) from [] (__pm_runtime_resume+0x9c/0xa0)
[] (__pm_runtime_resume) from [] (otg_timer+0x3c/0x254)
[] (otg_timer) from [] (call_timer_fn+0xfc/0x41c)
[] (call_timer_fn) from [] (expire_timers+0x120/0x210)
[] (expire_timers) from [] (run_timer_softirq+0xa4/0xdc)
[] (run_timer_softirq) from [] (__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 .
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 
Reviewed-by: Johan Hovold 
Tested-by: Laurent Pinchart 
Signed-off-by: Tony Lindgren 
---
 drivers/usb/musb/musb_core.c   | 109 +++--
 drivers/usb/musb/musb_core.h   |   7 +++
 drivers/usb/musb/musb_dsps.c   |  36 ++
 drivers/usb/musb/musb_gadget.c |  33 +++--
 4 files changed, 167 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1969,6 +1969,7 @@ static struct musb *allocate_instance(struct device *dev,
INIT_LIST_HEAD(&musb->control);
INIT_LIST_HEAD(&musb->in_bulk);
INIT_LIST_HEAD(&musb->out_bulk);
+   INIT_LIST_HEAD(&musb->pending_list);
 
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -2018,6 +2019,84 @@ static void musb_free(struct musb *musb)
musb_host_free(musb);
 }
 
+struct musb_pending_work {
+   int (*callback)(struct musb *musb, void *data);
+   void *data;
+   struct list_head node;
+};
+
+/*
+ * Called from musb_runtime_resume(), musb_resume(), and
+ * musb_queue_resume_work(). Callers must take musb->lock.
+ */
+static int musb_run_resume_work(struct musb *musb)
+{
+   struct musb_pending_work *w, *_w;
+   unsigned long flags;
+   int error = 0;
+
+   spin_lock_irqsave(&musb->list_lock, flags);
+   list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
+   if (w->callback) {
+   error = w->callback(musb, w->data);
+   if (error < 0) {
+   dev_err(musb->controller,
+   "resume callback %p failed: %i\n",
+   w->callback, error);
+   }
+   }
+   list_del(&w->node);
+   devm_kfree(musb->controller, w);
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+
+/*
+ * Called to run work if device is active or else queue the work to happen
+ * on resume. Caller must take musb->lock and must hold an RPM reference.
+ *
+ * Note that we cowardly refuse queuing work after musb PM runtime
+ * resume is done calling musb_run_resume_work() and return -EINPROGRESS
+ * instead.
+ */
+int musb_queue_resume_work(struct musb *musb,
+  int (*callback)(struct musb *musb, void *data),
+  void *data)
+{
+   struct musb_pending_work *w;
+   unsigned long flags;
+   int error;
+
+   if (WARN_ON(!callback))
+   return -EINVAL;
+
+   if (pm_runtime_active(musb->controller))
+   return callback(musb, data);
+
+   w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
+   if (!w)
+   return -ENOMEM;
+
+   w->callback = callback;
+   w->data = data;
+   spin_lock_irqsave(&musb->list_lock, flags);
+   if (musb->is_runtime_suspended) {
+   list_add_tail(&w->node, &musb->pending_list);
+   error = 0;
+   } else {
+   dev_err(musb->controller, "could not add resume work %p\n",
+   callback);
+   devm_kfree(musb->controller, w);
+   error = -EINPROGRESS;
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+EXPORT_SYMBOL_GPL(musb_queue_resume_work);
+
 static void musb_deassert_reset(struct work_struct *wo

[PATCH 2/6] usb: musb: Fix sleeping function called from invalid context for hdrc glue

2016-11-11 Thread Tony Lindgren
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:

[] (__might_sleep) from [] (__pm_runtime_resume+0x9c/0xa0)
[] (__pm_runtime_resume) from [] (otg_timer+0x3c/0x254)
[] (otg_timer) from [] (call_timer_fn+0xfc/0x41c)
[] (call_timer_fn) from [] (expire_timers+0x120/0x210)
[] (expire_timers) from [] (run_timer_softirq+0xa4/0xdc)
[] (run_timer_softirq) from [] (__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 .
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 
Reviewed-by: Johan Hovold 
Signed-off-by: Tony Lindgren 
---
 drivers/usb/musb/musb_core.c   | 109 +++--
 drivers/usb/musb/musb_core.h   |   7 +++
 drivers/usb/musb/musb_dsps.c   |  36 ++
 drivers/usb/musb/musb_gadget.c |  33 +++--
 4 files changed, 167 insertions(+), 18 deletions(-)

diff --git a/drivers/usb/musb/musb_core.c b/drivers/usb/musb/musb_core.c
--- a/drivers/usb/musb/musb_core.c
+++ b/drivers/usb/musb/musb_core.c
@@ -1969,6 +1969,7 @@ static struct musb *allocate_instance(struct device *dev,
INIT_LIST_HEAD(&musb->control);
INIT_LIST_HEAD(&musb->in_bulk);
INIT_LIST_HEAD(&musb->out_bulk);
+   INIT_LIST_HEAD(&musb->pending_list);
 
musb->vbuserr_retry = VBUSERR_RETRY_COUNT;
musb->a_wait_bcon = OTG_TIME_A_WAIT_BCON;
@@ -2018,6 +2019,84 @@ static void musb_free(struct musb *musb)
musb_host_free(musb);
 }
 
+struct musb_pending_work {
+   int (*callback)(struct musb *musb, void *data);
+   void *data;
+   struct list_head node;
+};
+
+/*
+ * Called from musb_runtime_resume(), musb_resume(), and
+ * musb_queue_resume_work(). Callers must take musb->lock.
+ */
+static int musb_run_resume_work(struct musb *musb)
+{
+   struct musb_pending_work *w, *_w;
+   unsigned long flags;
+   int error = 0;
+
+   spin_lock_irqsave(&musb->list_lock, flags);
+   list_for_each_entry_safe(w, _w, &musb->pending_list, node) {
+   if (w->callback) {
+   error = w->callback(musb, w->data);
+   if (error < 0) {
+   dev_err(musb->controller,
+   "resume callback %p failed: %i\n",
+   w->callback, error);
+   }
+   }
+   list_del(&w->node);
+   devm_kfree(musb->controller, w);
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+
+/*
+ * Called to run work if device is active or else queue the work to happen
+ * on resume. Caller must take musb->lock and must hold an RPM reference.
+ *
+ * Note that we cowardly refuse queuing work after musb PM runtime
+ * resume is done calling musb_run_resume_work() and return -EINPROGRESS
+ * instead.
+ */
+int musb_queue_resume_work(struct musb *musb,
+  int (*callback)(struct musb *musb, void *data),
+  void *data)
+{
+   struct musb_pending_work *w;
+   unsigned long flags;
+   int error;
+
+   if (WARN_ON(!callback))
+   return -EINVAL;
+
+   if (pm_runtime_active(musb->controller))
+   return callback(musb, data);
+
+   w = devm_kzalloc(musb->controller, sizeof(*w), GFP_ATOMIC);
+   if (!w)
+   return -ENOMEM;
+
+   w->callback = callback;
+   w->data = data;
+   spin_lock_irqsave(&musb->list_lock, flags);
+   if (musb->is_runtime_suspended) {
+   list_add_tail(&w->node, &musb->pending_list);
+   error = 0;
+   } else {
+   dev_err(musb->controller, "could not add resume work %p\n",
+   callback);
+   devm_kfree(musb->controller, w);
+   error = -EINPROGRESS;
+   }
+   spin_unlock_irqrestore(&musb->list_lock, flags);
+
+   return error;
+}
+EXPORT_SYMBOL_GPL(musb_queue_resume_work);
+
 static void musb_deassert_reset(struct work_struct *work)
 {
struct musb *m