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>
This commit is contained in:
parent
4df82b5911
commit
396e04f4bb
|
@ -68,6 +68,7 @@ struct btmrvl_adapter {
|
|||
u8 hs_state;
|
||||
u8 wakeup_tries;
|
||||
wait_queue_head_t cmd_wait_q;
|
||||
wait_queue_head_t event_hs_wait_q;
|
||||
u8 cmd_complete;
|
||||
bool is_suspended;
|
||||
};
|
||||
|
|
|
@ -114,6 +114,7 @@ int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb)
|
|||
adapter->hs_state = HS_ACTIVATED;
|
||||
if (adapter->psmode)
|
||||
adapter->ps_state = PS_SLEEP;
|
||||
wake_up_interruptible(&adapter->event_hs_wait_q);
|
||||
BT_DBG("HS ACTIVATED!");
|
||||
} else {
|
||||
BT_DBG("HS Enable failed");
|
||||
|
@ -270,11 +271,31 @@ EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
|
|||
|
||||
int btmrvl_enable_hs(struct btmrvl_private *priv)
|
||||
{
|
||||
struct btmrvl_adapter *adapter = priv->adapter;
|
||||
int ret;
|
||||
|
||||
ret = btmrvl_send_sync_cmd(priv, BT_CMD_HOST_SLEEP_ENABLE, NULL, 0);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
BT_ERR("Host sleep enable command failed\n");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = wait_event_interruptible_timeout(adapter->event_hs_wait_q,
|
||||
adapter->hs_state,
|
||||
msecs_to_jiffies(WAIT_UNTIL_HS_STATE_CHANGED));
|
||||
if (ret < 0) {
|
||||
BT_ERR("event_hs_wait_q terminated (%d): %d,%d,%d",
|
||||
ret, adapter->hs_state, adapter->ps_state,
|
||||
adapter->wakeup_tries);
|
||||
} else if (!ret) {
|
||||
BT_ERR("hs_enable timeout: %d,%d,%d", adapter->hs_state,
|
||||
adapter->ps_state, adapter->wakeup_tries);
|
||||
ret = -ETIMEDOUT;
|
||||
} else {
|
||||
BT_DBG("host sleep enabled: %d,%d,%d", adapter->hs_state,
|
||||
adapter->ps_state, adapter->wakeup_tries);
|
||||
ret = 0;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -375,6 +396,7 @@ static void btmrvl_init_adapter(struct btmrvl_private *priv)
|
|||
}
|
||||
|
||||
init_waitqueue_head(&priv->adapter->cmd_wait_q);
|
||||
init_waitqueue_head(&priv->adapter->event_hs_wait_q);
|
||||
}
|
||||
|
||||
static void btmrvl_free_adapter(struct btmrvl_private *priv)
|
||||
|
@ -685,6 +707,7 @@ int btmrvl_remove_card(struct btmrvl_private *priv)
|
|||
hdev = priv->btmrvl_dev.hcidev;
|
||||
|
||||
wake_up_interruptible(&priv->adapter->cmd_wait_q);
|
||||
wake_up_interruptible(&priv->adapter->event_hs_wait_q);
|
||||
|
||||
kthread_stop(priv->main_thread.task);
|
||||
|
||||
|
|
Loading…
Reference in New Issue