Bluetooth: btmrvl: don't send data to firmware while processing suspend
authorChin-Ran Lo <crlo@marvell.com>
Wed, 6 Jan 2016 14:34:38 +0000 (06:34 -0800)
committerMarcel Holtmann <marcel@holtmann.org>
Wed, 6 Jan 2016 15:37:14 +0000 (16:37 +0100)
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>
drivers/bluetooth/btmrvl_drv.h
drivers/bluetooth/btmrvl_main.c
drivers/bluetooth/btmrvl_sdio.c

index 27a9aac2558326c8f7801b891ef4b5f7441b1071..05904732e6f1502a630a45f842120da0f6dff68d 100644 (file)
@@ -89,6 +89,7 @@ struct btmrvl_adapter {
        wait_queue_head_t event_hs_wait_q;
        u8 cmd_complete;
        bool is_suspended;
+       bool is_suspending;
 };
 
 struct btmrvl_private {
index b2a567bb1b46b94f9613e0cd39ad580e5199fb3f..f25a825a693fa790dfb626b00367f4704a9a7f0b 100644 (file)
@@ -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);
 
+       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)) {
        case HCI_COMMAND_PKT:
                hdev->stat.cmd_tx++;
@@ -452,7 +457,8 @@ static int btmrvl_send_frame(struct hci_dev *hdev, struct sk_buff *skb)
 
        skb_queue_tail(&priv->adapter->tx_queue, skb);
 
-       wake_up_interruptible(&priv->main_thread.wait_q);
+       if (!priv->adapter->is_suspended)
+               wake_up_interruptible(&priv->main_thread.wait_q);
 
        return 0;
 }
@@ -643,7 +649,8 @@ static int btmrvl_service_main_thread(void *data)
                if (adapter->ps_state == PS_SLEEP)
                        continue;
 
-               if (!priv->btmrvl_dev.tx_dnld_rdy)
+               if (!priv->btmrvl_dev.tx_dnld_rdy ||
+                   priv->adapter->is_suspended)
                        continue;
 
                skb = skb_dequeue(&adapter->tx_queue);
index 73a1c277996947dbb0664a8dde17771f04a068d8..6ed8acfcfa9cbfa6474e1fc790d214a9aaf48a3f 100644 (file)
@@ -1545,10 +1545,10 @@ static int btmrvl_sdio_suspend(struct device *dev)
        }
 
        priv = card->priv;
+       priv->adapter->is_suspending = true;
        hcidev = priv->btmrvl_dev.hcidev;
        BT_DBG("%s: SDIO suspend", hcidev->name);
        hci_suspend_dev(hcidev);
-       skb_queue_purge(&priv->adapter->tx_queue);
 
        if (priv->adapter->hs_state != HS_ACTIVATED) {
                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;
 
        /* We will keep the power when hs enabled successfully */