Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Chin-Ran Lo and committed by
Marcel Holtmann
8cf60cf2 d716892f

+12 -3
+1
drivers/bluetooth/btmrvl_drv.h
··· 89 89 wait_queue_head_t event_hs_wait_q; 90 90 u8 cmd_complete; 91 91 bool is_suspended; 92 + bool is_suspending; 92 93 }; 93 94 94 95 struct btmrvl_private {
+9 -2
drivers/bluetooth/btmrvl_main.c
··· 436 436 437 437 BT_DBG("type=%d, len=%d", hci_skb_pkt_type(skb), skb->len); 438 438 439 + if (priv->adapter->is_suspending || priv->adapter->is_suspended) { 440 + BT_ERR("%s: Device is suspending or suspended", __func__); 441 + return -EBUSY; 442 + } 443 + 439 444 switch (hci_skb_pkt_type(skb)) { 440 445 case HCI_COMMAND_PKT: 441 446 hdev->stat.cmd_tx++; ··· 457 452 458 453 skb_queue_tail(&priv->adapter->tx_queue, skb); 459 454 460 - wake_up_interruptible(&priv->main_thread.wait_q); 455 + if (!priv->adapter->is_suspended) 456 + wake_up_interruptible(&priv->main_thread.wait_q); 461 457 462 458 return 0; 463 459 } ··· 649 643 if (adapter->ps_state == PS_SLEEP) 650 644 continue; 651 645 652 - if (!priv->btmrvl_dev.tx_dnld_rdy) 646 + if (!priv->btmrvl_dev.tx_dnld_rdy || 647 + priv->adapter->is_suspended) 653 648 continue; 654 649 655 650 skb = skb_dequeue(&adapter->tx_queue);
+2 -1
drivers/bluetooth/btmrvl_sdio.c
··· 1545 1545 } 1546 1546 1547 1547 priv = card->priv; 1548 + priv->adapter->is_suspending = true; 1548 1549 hcidev = priv->btmrvl_dev.hcidev; 1549 1550 BT_DBG("%s: SDIO suspend", hcidev->name); 1550 1551 hci_suspend_dev(hcidev); 1551 - skb_queue_purge(&priv->adapter->tx_queue); 1552 1552 1553 1553 if (priv->adapter->hs_state != HS_ACTIVATED) { 1554 1554 if (btmrvl_enable_hs(priv)) { ··· 1557 1557 } 1558 1558 } 1559 1559 1560 + priv->adapter->is_suspending = false; 1560 1561 priv->adapter->is_suspended = true; 1561 1562 1562 1563 /* We will keep the power when hs enabled successfully */