Skip to content

Commit 41d5b25

Browse files
Claire Changholtmann
authored andcommitted
Bluetooth: hci_qca: add PM support
Add PM suspend/resume callbacks for hci_qca driver. BT host will make sure both Rx and Tx go into sleep state in qca_suspend. Without this, Tx may still remain in awake state, which prevents BTSOC from entering deep sleep. For example, BlueZ will send Set Event Mask to device when suspending and this will wake the device Rx up. However, the Tx idle timeout on the host side is 2000 ms. If the host is suspended before its Tx idle times out, it won't send HCI_IBS_SLEEP_IND to the device and the device Rx will remain awake. We implement this by canceling relevant work in workqueue, sending HCI_IBS_SLEEP_IND to the device and then waiting HCI_IBS_SLEEP_IND sent by the device. In order to prevent the device from being awaken again after qca_suspend is called, we introduce QCA_SUSPEND flag. QCA_SUSPEND is set in the beginning of qca_suspend to indicate system is suspending and that we'd like to ignore any further wake events. With QCA_SUSPEND and spinlock, we can avoid race condition, e.g. if qca_enqueue acquires qca->hci_ibs_lock before qca_suspend calls cancel_work_sync and then qca_enqueue adds a new qca->ws_awake_device work after the previous one is cancelled. If BTSOC wants to wake the whole system up after qca_suspend is called, it will keep sending HCI_IBS_WAKE_IND and uart driver will take care of waking the system. For example, uart driver will reconfigure its Rx pin to a normal GPIO pin and enable irq wake on that pin when suspending. Once host detects Rx falling, the system will begin resuming. Then, the BT host clears QCA_SUSPEND flag in qca_resume and begins dealing with normal HCI packets. By doing so, only a few HCI_IBS_WAKE_IND packets are lost and there is no data packet loss. Signed-off-by: Claire Chang <[email protected]> Reviewed-by: Balakrishna Godavarthi <[email protected]> Signed-off-by: Marcel Holtmann <[email protected]>
1 parent 6012b93 commit 41d5b25

File tree

1 file changed

+124
-3
lines changed

1 file changed

+124
-3
lines changed

drivers/bluetooth/hci_qca.c

Lines changed: 124 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@
4343
#define HCI_MAX_IBS_SIZE 10
4444

4545
#define IBS_WAKE_RETRANS_TIMEOUT_MS 100
46-
#define IBS_TX_IDLE_TIMEOUT_MS 2000
46+
#define IBS_BTSOC_TX_IDLE_TIMEOUT_MS 40
47+
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
4748
#define CMD_TRANS_TIMEOUT_MS 100
4849

4950
/* susclk rate */
@@ -55,6 +56,7 @@
5556
enum qca_flags {
5657
QCA_IBS_ENABLED,
5758
QCA_DROP_VENDOR_EVENT,
59+
QCA_SUSPENDING,
5860
};
5961

6062
/* HCI_IBS transmit side sleep protocol states */
@@ -100,6 +102,7 @@ struct qca_data {
100102
struct work_struct ws_tx_vote_off;
101103
unsigned long flags;
102104
struct completion drop_ev_comp;
105+
wait_queue_head_t suspend_wait_q;
103106

104107
/* For debugging purpose */
105108
u64 ibs_sent_wacks;
@@ -437,6 +440,12 @@ static void hci_ibs_wake_retrans_timeout(struct timer_list *t)
437440
spin_lock_irqsave_nested(&qca->hci_ibs_lock,
438441
flags, SINGLE_DEPTH_NESTING);
439442

443+
/* Don't retransmit the HCI_IBS_WAKE_IND when suspending. */
444+
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
445+
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
446+
return;
447+
}
448+
440449
switch (qca->tx_ibs_state) {
441450
case HCI_IBS_TX_WAKING:
442451
/* No WAKE_ACK, retransmit WAKE */
@@ -496,6 +505,8 @@ static int qca_open(struct hci_uart *hu)
496505
INIT_WORK(&qca->ws_rx_vote_off, qca_wq_serial_rx_clock_vote_off);
497506
INIT_WORK(&qca->ws_tx_vote_off, qca_wq_serial_tx_clock_vote_off);
498507

508+
init_waitqueue_head(&qca->suspend_wait_q);
509+
499510
qca->hu = hu;
500511
init_completion(&qca->drop_ev_comp);
501512

@@ -532,7 +543,7 @@ static int qca_open(struct hci_uart *hu)
532543
qca->wake_retrans = IBS_WAKE_RETRANS_TIMEOUT_MS;
533544

534545
timer_setup(&qca->tx_idle_timer, hci_ibs_tx_idle_timeout, 0);
535-
qca->tx_idle_delay = IBS_TX_IDLE_TIMEOUT_MS;
546+
qca->tx_idle_delay = IBS_HOST_TX_IDLE_TIMEOUT_MS;
536547

537548
BT_DBG("HCI_UART_QCA open, tx_idle_delay=%u, wake_retrans=%u",
538549
qca->tx_idle_delay, qca->wake_retrans);
@@ -647,6 +658,12 @@ static void device_want_to_wakeup(struct hci_uart *hu)
647658

648659
qca->ibs_recv_wakes++;
649660

661+
/* Don't wake the rx up when suspending. */
662+
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
663+
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
664+
return;
665+
}
666+
650667
switch (qca->rx_ibs_state) {
651668
case HCI_IBS_RX_ASLEEP:
652669
/* Make sure clock is on - we may have turned clock off since
@@ -711,6 +728,8 @@ static void device_want_to_sleep(struct hci_uart *hu)
711728
break;
712729
}
713730

731+
wake_up_interruptible(&qca->suspend_wait_q);
732+
714733
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
715734
}
716735

@@ -728,6 +747,12 @@ static void device_woke_up(struct hci_uart *hu)
728747

729748
qca->ibs_recv_wacks++;
730749

750+
/* Don't react to the wake-up-acknowledgment when suspending. */
751+
if (test_bit(QCA_SUSPENDING, &qca->flags)) {
752+
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
753+
return;
754+
}
755+
731756
switch (qca->tx_ibs_state) {
732757
case HCI_IBS_TX_AWAKE:
733758
/* Expect one if we send 2 WAKEs */
@@ -780,8 +805,10 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
780805

781806
/* Don't go to sleep in middle of patch download or
782807
* Out-Of-Band(GPIOs control) sleep is selected.
808+
* Don't wake the device up when suspending.
783809
*/
784-
if (!test_bit(QCA_IBS_ENABLED, &qca->flags)) {
810+
if (!test_bit(QCA_IBS_ENABLED, &qca->flags) ||
811+
test_bit(QCA_SUSPENDING, &qca->flags)) {
785812
skb_queue_tail(&qca->txq, skb);
786813
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
787814
return 0;
@@ -1539,6 +1566,99 @@ static void qca_serdev_remove(struct serdev_device *serdev)
15391566
hci_uart_unregister_device(&qcadev->serdev_hu);
15401567
}
15411568

1569+
static int __maybe_unused qca_suspend(struct device *dev)
1570+
{
1571+
struct hci_dev *hdev = container_of(dev, struct hci_dev, dev);
1572+
struct hci_uart *hu = hci_get_drvdata(hdev);
1573+
struct qca_data *qca = hu->priv;
1574+
unsigned long flags;
1575+
int ret = 0;
1576+
u8 cmd;
1577+
1578+
set_bit(QCA_SUSPENDING, &qca->flags);
1579+
1580+
/* Device is downloading patch or doesn't support in-band sleep. */
1581+
if (!test_bit(QCA_IBS_ENABLED, &qca->flags))
1582+
return 0;
1583+
1584+
cancel_work_sync(&qca->ws_awake_device);
1585+
cancel_work_sync(&qca->ws_awake_rx);
1586+
1587+
spin_lock_irqsave_nested(&qca->hci_ibs_lock,
1588+
flags, SINGLE_DEPTH_NESTING);
1589+
1590+
switch (qca->tx_ibs_state) {
1591+
case HCI_IBS_TX_WAKING:
1592+
del_timer(&qca->wake_retrans_timer);
1593+
/* Fall through */
1594+
case HCI_IBS_TX_AWAKE:
1595+
del_timer(&qca->tx_idle_timer);
1596+
1597+
serdev_device_write_flush(hu->serdev);
1598+
cmd = HCI_IBS_SLEEP_IND;
1599+
ret = serdev_device_write_buf(hu->serdev, &cmd, sizeof(cmd));
1600+
1601+
if (ret < 0) {
1602+
BT_ERR("Failed to send SLEEP to device");
1603+
break;
1604+
}
1605+
1606+
qca->tx_ibs_state = HCI_IBS_TX_ASLEEP;
1607+
qca->ibs_sent_slps++;
1608+
1609+
qca_wq_serial_tx_clock_vote_off(&qca->ws_tx_vote_off);
1610+
break;
1611+
1612+
case HCI_IBS_TX_ASLEEP:
1613+
break;
1614+
1615+
default:
1616+
BT_ERR("Spurious tx state %d", qca->tx_ibs_state);
1617+
ret = -EINVAL;
1618+
break;
1619+
}
1620+
1621+
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
1622+
1623+
if (ret < 0)
1624+
goto error;
1625+
1626+
serdev_device_wait_until_sent(hu->serdev,
1627+
msecs_to_jiffies(CMD_TRANS_TIMEOUT_MS));
1628+
1629+
/* Wait for HCI_IBS_SLEEP_IND sent by device to indicate its Tx is going
1630+
* to sleep, so that the packet does not wake the system later.
1631+
*/
1632+
1633+
ret = wait_event_interruptible_timeout(qca->suspend_wait_q,
1634+
qca->rx_ibs_state == HCI_IBS_RX_ASLEEP,
1635+
msecs_to_jiffies(IBS_BTSOC_TX_IDLE_TIMEOUT_MS));
1636+
1637+
if (ret > 0)
1638+
return 0;
1639+
1640+
if (ret == 0)
1641+
ret = -ETIMEDOUT;
1642+
1643+
error:
1644+
clear_bit(QCA_SUSPENDING, &qca->flags);
1645+
1646+
return ret;
1647+
}
1648+
1649+
static int __maybe_unused qca_resume(struct device *dev)
1650+
{
1651+
struct hci_dev *hdev = container_of(dev, struct hci_dev, dev);
1652+
struct hci_uart *hu = hci_get_drvdata(hdev);
1653+
struct qca_data *qca = hu->priv;
1654+
1655+
clear_bit(QCA_SUSPENDING, &qca->flags);
1656+
1657+
return 0;
1658+
}
1659+
1660+
static SIMPLE_DEV_PM_OPS(qca_pm_ops, qca_suspend, qca_resume);
1661+
15421662
static const struct of_device_id qca_bluetooth_of_match[] = {
15431663
{ .compatible = "qcom,qca6174-bt" },
15441664
{ .compatible = "qcom,wcn3990-bt", .data = &qca_soc_data_wcn3990},
@@ -1553,6 +1673,7 @@ static struct serdev_device_driver qca_serdev_driver = {
15531673
.driver = {
15541674
.name = "hci_uart_qca",
15551675
.of_match_table = qca_bluetooth_of_match,
1676+
.pm = &qca_pm_ops,
15561677
},
15571678
};
15581679

0 commit comments

Comments
 (0)