Bluetooth: hci_qca: Bug fixes for SSR
authorVenkata Lakshmi Narayana Gubba <gubbaven@codeaurora.org>
Sat, 11 Jul 2020 11:31:12 +0000 (17:01 +0530)
committerMarcel Holtmann <marcel@holtmann.org>
Mon, 13 Jul 2020 16:38:35 +0000 (18:38 +0200)
1.During SSR for command time out if BT SoC goes to inresponsive
state, power cycling of BT SoC was not happening. Given the fix by
sending hw error event to reset the BT SoC.

2.If SSR is triggered then ignore the transmit data requests to
BT SoC until SSR is completed.

Signed-off-by: Venkata Lakshmi Narayana Gubba <gubbaven@codeaurora.org>
Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
drivers/bluetooth/hci_qca.c

index 7e39546..3d13002 100644 (file)
@@ -72,7 +72,8 @@ enum qca_flags {
        QCA_DROP_VENDOR_EVENT,
        QCA_SUSPENDING,
        QCA_MEMDUMP_COLLECTION,
-       QCA_HW_ERROR_EVENT
+       QCA_HW_ERROR_EVENT,
+       QCA_SSR_TRIGGERED
 };
 
 enum qca_capabilities {
@@ -854,6 +855,13 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
        BT_DBG("hu %p qca enq skb %p tx_ibs_state %d", hu, skb,
               qca->tx_ibs_state);
 
+       if (test_bit(QCA_SSR_TRIGGERED, &qca->flags)) {
+               /* As SSR is in progress, ignore the packets */
+               bt_dev_dbg(hu->hdev, "SSR is in progress");
+               kfree_skb(skb);
+               return 0;
+       }
+
        /* Prepend skb with frame type */
        memcpy(skb_push(skb, 1), &hci_skb_pkt_type(skb), 1);
 
@@ -1123,6 +1131,7 @@ static int qca_controller_memdump_event(struct hci_dev *hdev,
        struct hci_uart *hu = hci_get_drvdata(hdev);
        struct qca_data *qca = hu->priv;
 
+       set_bit(QCA_SSR_TRIGGERED, &qca->flags);
        skb_queue_tail(&qca->rx_memdump_q, skb);
        queue_work(qca->workqueue, &qca->ctrl_memdump_evt);
 
@@ -1481,6 +1490,7 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
        struct hci_uart *hu = hci_get_drvdata(hdev);
        struct qca_data *qca = hu->priv;
 
+       set_bit(QCA_SSR_TRIGGERED, &qca->flags);
        set_bit(QCA_HW_ERROR_EVENT, &qca->flags);
        bt_dev_info(hdev, "mem_dump_status: %d", qca->memdump_state);
 
@@ -1529,10 +1539,30 @@ static void qca_cmd_timeout(struct hci_dev *hdev)
        struct hci_uart *hu = hci_get_drvdata(hdev);
        struct qca_data *qca = hu->priv;
 
-       if (qca->memdump_state == QCA_MEMDUMP_IDLE)
+       set_bit(QCA_SSR_TRIGGERED, &qca->flags);
+       if (qca->memdump_state == QCA_MEMDUMP_IDLE) {
+               set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
                qca_send_crashbuffer(hu);
-       else
-               bt_dev_info(hdev, "Dump collection is in process");
+               qca_wait_for_dump_collection(hdev);
+       } else if (qca->memdump_state == QCA_MEMDUMP_COLLECTING) {
+               /* Let us wait here until memory dump collected or
+                * memory dump timer expired.
+                */
+               bt_dev_info(hdev, "waiting for dump to complete");
+               qca_wait_for_dump_collection(hdev);
+       }
+
+       mutex_lock(&qca->hci_memdump_lock);
+       if (qca->memdump_state != QCA_MEMDUMP_COLLECTED) {
+               qca->memdump_state = QCA_MEMDUMP_TIMEOUT;
+               if (!test_bit(QCA_HW_ERROR_EVENT, &qca->flags)) {
+                       /* Inject hw error event to reset the device
+                        * and driver.
+                        */
+                       hci_reset_dev(hu->hdev);
+               }
+       }
+       mutex_unlock(&qca->hci_memdump_lock);
 }
 
 static int qca_wcn3990_init(struct hci_uart *hu)
@@ -1643,6 +1673,8 @@ retry:
        if (ret)
                return ret;
 
+       clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
+
        if (qca_is_wcn399x(soc_type)) {
                set_bit(HCI_QUIRK_USE_BDADDR_PROPERTY, &hdev->quirks);