aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChin-Ran Lo <crlo@marvell.com>2014-07-01 17:00:14 -0400
committerMarcel Holtmann <marcel@holtmann.org>2014-07-03 11:42:54 -0400
commit396e04f4bb9afefb0744715dc76d9abe18ee5fb0 (patch)
tree0492fff5438d6a4b094489e8faa4536cb5d46689
parent4df82b5911c0e380d8b308958f158c3e7b365467 (diff)
Bluetooth: btmrvl: wait for HOST_SLEEP_ENABLE event in suspend
After BT_CMD_HOST_SLEEP_ENABLE command finishes, driver should wait until getting BT_EVENT_HOST_SLEEP_ENABLE event to complete suspend procedure. Without this patch the suspend handler would return success earlier. By the time when the BT_EVENT_HOST_SLEEP_ENABLE event comes in the controller driver could have already turned off the bus clock. This causes kernel crash or system reboot eventually. Cc: <stable@vger.kernel.org> # 3.13+ Signed-off-by: Chin-Ran Lo <crlo@marvell.com> Signed-off-by: Jeff CF Chen <jeffc@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Bing Zhao <bzhao@marvell.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
-rw-r--r--drivers/bluetooth/btmrvl_drv.h1
-rw-r--r--drivers/bluetooth/btmrvl_main.c25
2 files changed, 25 insertions, 1 deletions
diff --git a/drivers/bluetooth/btmrvl_drv.h b/drivers/bluetooth/btmrvl_drv.h
index 4c313e73df83..a8a9d3380e59 100644
--- a/drivers/bluetooth/btmrvl_drv.h
+++ b/drivers/bluetooth/btmrvl_drv.h
@@ -68,6 +68,7 @@ struct btmrvl_adapter {
68 u8 hs_state; 68 u8 hs_state;
69 u8 wakeup_tries; 69 u8 wakeup_tries;
70 wait_queue_head_t cmd_wait_q; 70 wait_queue_head_t cmd_wait_q;
71 wait_queue_head_t event_hs_wait_q;
71 u8 cmd_complete; 72 u8 cmd_complete;
72 bool is_suspended; 73 bool is_suspended;
73}; 74};
diff --git a/drivers/bluetooth/btmrvl_main.c b/drivers/bluetooth/btmrvl_main.c
index d35f2e189a6d..cc65fd2fe856 100644
--- a/drivers/bluetooth/btmrvl_main.c
+++ b/drivers/bluetooth/btmrvl_main.c
@@ -114,6 +114,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
114 adapter->hs_state = HS_ACTIVATED; 114 adapter->hs_state = HS_ACTIVATED;
115 if (adapter->psmode) 115 if (adapter->psmode)
116 adapter->ps_state = PS_SLEEP; 116 adapter->ps_state = PS_SLEEP;
117 wake_up_interruptible(&adapter->event_hs_wait_q);
117 BT_DBG("HS ACTIVATED!"); 118 BT_DBG("HS ACTIVATED!");
118 } else { 119 } else {
119 BT_DBG("HS Enable failed"); 120 BT_DBG("HS Enable failed");
@@ -270,11 +271,31 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
270 271
271int btmrvl_enable_hs(struct btmrvl_private *priv) 272int btmrvl_enable_hs(struct btmrvl_private *priv)
272{ 273{
274 struct btmrvl_adapter *adapter = priv->adapter;
273 int ret; 275 int ret;
274 276
275 ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0); 277 ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
276 if (ret) 278 if (ret) {
277 BT_ERR("Host sleep enable command failed\n"); 279 BT_ERR("Host sleep enable command failed\n");
280 return ret;
281 }
282
283 ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
284 adapter->hs_state,
285 msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
286 if (ret < 0) {
287 BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d",
288 ret, adapter->hs_state, adapter->ps_state,
289 adapter->wakeup_tries);
290 } else if (!ret) {
291 BT_ERR("hs_enable timeout: %d,%d,%d", adapter->hs_state,
292 adapter->ps_state, adapter->wakeup_tries);
293 ret = -ETIMEDOUT;
294 } else {
295 BT_DBG("host sleep enabled: %d,%d,%d", adapter->hs_state,
296 adapter->ps_state, adapter->wakeup_tries);
297 ret = 0;
298 }
278 299
279 return ret; 300 return ret;
280} 301}
@@ -375,6 +396,7 @@ static void btmrvl_init_adapter(struct btmrvl_private *priv)
375 } 396 }
376 397
377 init_waitqueue_head(&priv->adapter->cmd_wait_q); 398 init_waitqueue_head(&priv->adapter->cmd_wait_q);
399 init_waitqueue_head(&priv->adapter->event_hs_wait_q);
378} 400}
379 401
380static void btmrvl_free_adapter(struct btmrvl_private *priv) 402static void btmrvl_free_adapter(struct btmrvl_private *priv)
@@ -685,6 +707,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv)
685 hdev = priv->btmrvl_dev.hcidev; 707 hdev = priv->btmrvl_dev.hcidev;
686 708
687 wake_up_interruptible(&priv->adapter->cmd_wait_q); 709 wake_up_interruptible(&priv->adapter->cmd_wait_q);
710 wake_up_interruptible(&priv->adapter->event_hs_wait_q);
688 711
689 kthread_stop(priv->main_thread.task); 712 kthread_stop(priv->main_thread.task);
690 713