Bluetooth: btmrvl: don't send data to firmware while processing suspend
Usually when driver sends data to firmware it receives TX_DONE (DN_LD_HOST_INT_STATUS) interrupt from firmware right away. It's also observed that some times the fireware could delay sending DN_LD_HOST_INT_STATUS interrupt. If driver sends data to firmware during suspend processing and the TX_DONE interrupt is delayed, it may come back at wrong time when SDIO host driver is in the middle of suspending. Block any data from stack while suspending. Also skip sending data that are already in driver tx_queue. Don't purge the skb queue on suspend to avoid intermittent music after system resumes from S3. Signed-off-by: Chin-Ran Lo <crlo@marvell.com> Signed-off-by: Amitkumar Karwar <akarwar@marvell.com> Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
d716892f08
commit
8cf60cf238
|
@ -89,6 +89,7 @@ struct btmrvl_adapter {
|
||||||
wait_queue_head_t event_hs_wait_q;
|
wait_queue_head_t event_hs_wait_q;
|
||||||
u8 cmd_complete;
|
u8 cmd_complete;
|
||||||
bool is_suspended;
|
bool is_suspended;
|
||||||
|
bool is_suspending;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct btmrvl_private {
|
struct btmrvl_private {
|
||||||
|
|
|
@ -436,6 +436,11 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len);
|
BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len);
|
||||||
|
|
||||||
|
if (priv->adapter->is_suspending || priv->adapter->is_suspended) {
|
||||||
|
BT_ERR("%s: Device is suspending or suspended", __func__);
|
||||||
|
return -EBUSY;
|
||||||
|
}
|
||||||
|
|
||||||
switch (hci_skb_pkt_type(skb)) {
|
switch (hci_skb_pkt_type(skb)) {
|
||||||
case HCI_COMMAND_PKT:
|
case HCI_COMMAND_PKT:
|
||||||
hdev->stat.cmd_tx++;
|
hdev->stat.cmd_tx++;
|
||||||
|
@ -452,6 +457,7 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
||||||
skb_queue_tail(&priv->adapter->tx_queue, skb);
|
skb_queue_tail(&priv->adapter->tx_queue, skb);
|
||||||
|
|
||||||
|
if (!priv->adapter->is_suspended)
|
||||||
wake_up_interruptible(&priv->main_thread.wait_q);
|
wake_up_interruptible(&priv->main_thread.wait_q);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -643,7 +649,8 @@ static int btmrvl_service_main_thread(void *data)
|
||||||
if (adapter->ps_state == PS_SLEEP)
|
if (adapter->ps_state == PS_SLEEP)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (!priv->btmrvl_dev.tx_dnld_rdy)
|
if (!priv->btmrvl_dev.tx_dnld_rdy ||
|
||||||
|
priv->adapter->is_suspended)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
skb = skb_dequeue(&adapter->tx_queue);
|
skb = skb_dequeue(&adapter->tx_queue);
|
||||||
|
|
|
@ -1545,10 +1545,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
||||||
}
|
}
|
||||||
|
|
||||||
priv = card->priv;
|
priv = card->priv;
|
||||||
|
priv->adapter->is_suspending = true;
|
||||||
hcidev = priv->btmrvl_dev.hcidev;
|
hcidev = priv->btmrvl_dev.hcidev;
|
||||||
BT_DBG("%s: SDIO suspend", hcidev->name);
|
BT_DBG("%s: SDIO suspend", hcidev->name);
|
||||||
hci_suspend_dev(hcidev);
|
hci_suspend_dev(hcidev);
|
||||||
skb_queue_purge(&priv->adapter->tx_queue);
|
|
||||||
|
|
||||||
if (priv->adapter->hs_state != HS_ACTIVATED) {
|
if (priv->adapter->hs_state != HS_ACTIVATED) {
|
||||||
if (btmrvl_enable_hs(priv)) {
|
if (btmrvl_enable_hs(priv)) {
|
||||||
|
@ -1557,6 +1557,7 @@ static int btmrvl_sdio_suspend(struct device *dev)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv->adapter->is_suspending = false;
|
||||||
priv->adapter->is_suspended = true;
|
priv->adapter->is_suspended = true;
|
||||||
|
|
||||||
/* We will keep the power when hs enabled successfully */
|
/* We will keep the power when hs enabled successfully */
|
||||||
|
|
Loading…
Reference in New Issue