| From 5bc2735ea58ca2a6dc507ba37637dffec0148405 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Sat, 11 Jul 2020 17:01:12 +0530 |
| Subject: Bluetooth: hci_qca: Bug fixes for SSR |
| |
| From: Venkata Lakshmi Narayana Gubba <gubbaven@codeaurora.org> |
| |
| [ Upstream commit 3344537f614b966f726c1ec044d1c70a8cabe178 ] |
| |
| 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> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/bluetooth/hci_qca.c | 40 +++++++++++++++++++++++++++++++++---- |
| 1 file changed, 36 insertions(+), 4 deletions(-) |
| |
| diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c |
| index 0b1036e5e963c..14e4d2eaf8959 100644 |
| --- a/drivers/bluetooth/hci_qca.c |
| +++ b/drivers/bluetooth/hci_qca.c |
| @@ -71,7 +71,8 @@ enum qca_flags { |
| QCA_DROP_VENDOR_EVENT, |
| QCA_SUSPENDING, |
| QCA_MEMDUMP_COLLECTION, |
| - QCA_HW_ERROR_EVENT |
| + QCA_HW_ERROR_EVENT, |
| + QCA_SSR_TRIGGERED |
| }; |
| |
| |
| @@ -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); |
| |
| @@ -1085,6 +1093,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); |
| |
| @@ -1445,6 +1454,7 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code) |
| struct qca_memdump_data *qca_memdump = qca->qca_memdump; |
| char *memdump_buf = NULL; |
| |
| + 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); |
| |
| @@ -1489,10 +1499,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) |
| @@ -1603,6 +1633,8 @@ static int qca_setup(struct hci_uart *hu) |
| 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); |
| |
| -- |
| 2.25.1 |
| |