Commit 2be43aba authored by Venkata Lakshmi Narayana Gubba's avatar Venkata Lakshmi Narayana Gubba Committed by Marcel Holtmann

Bluetooth: hci_qca: Wait for timeout during suspend

Currently qca_suspend() is relied on IBS mechanism. During
FW download and memory dump collections, IBS will be disabled.
In those cases, driver will allow suspend and still uses the
serdev port, which results to errors. Now added a wait timeout
if suspend is triggered during FW download and memory collections.
Signed-off-by: default avatarVenkata Lakshmi Narayana Gubba <gubbaven@codeaurora.org>
Signed-off-by: default avatarBalakrishna Godavarthi <bgodavar@codeaurora.org>
Reviewed-by: default avatarAbhishek Pandit-Subedi <abhishekpandit@chromium.org>
Signed-off-by: default avatarMarcel Holtmann <marcel@holtmann.org>
parent f5e8e215
...@@ -50,6 +50,8 @@ ...@@ -50,6 +50,8 @@
#define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000 #define IBS_HOST_TX_IDLE_TIMEOUT_MS 2000
#define CMD_TRANS_TIMEOUT_MS 100 #define CMD_TRANS_TIMEOUT_MS 100
#define MEMDUMP_TIMEOUT_MS 8000 #define MEMDUMP_TIMEOUT_MS 8000
#define IBS_DISABLE_SSR_TIMEOUT_MS (MEMDUMP_TIMEOUT_MS + 1000)
#define FW_DOWNLOAD_TIMEOUT_MS 3000
/* susclk rate */ /* susclk rate */
#define SUSCLK_RATE_32KHZ 32768 #define SUSCLK_RATE_32KHZ 32768
...@@ -68,12 +70,13 @@ ...@@ -68,12 +70,13 @@
#define QCA_MEMDUMP_BYTE 0xFB #define QCA_MEMDUMP_BYTE 0xFB
enum qca_flags { enum qca_flags {
QCA_IBS_ENABLED, QCA_IBS_DISABLED,
QCA_DROP_VENDOR_EVENT, QCA_DROP_VENDOR_EVENT,
QCA_SUSPENDING, QCA_SUSPENDING,
QCA_MEMDUMP_COLLECTION, QCA_MEMDUMP_COLLECTION,
QCA_HW_ERROR_EVENT, QCA_HW_ERROR_EVENT,
QCA_SSR_TRIGGERED QCA_SSR_TRIGGERED,
QCA_BT_OFF
}; };
enum qca_capabilities { enum qca_capabilities {
...@@ -870,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb) ...@@ -870,7 +873,7 @@ static int qca_enqueue(struct hci_uart *hu, struct sk_buff *skb)
* Out-Of-Band(GPIOs control) sleep is selected. * Out-Of-Band(GPIOs control) sleep is selected.
* Don't wake the device up when suspending. * Don't wake the device up when suspending.
*/ */
if (!test_bit(QCA_IBS_ENABLED, &qca->flags) || if (test_bit(QCA_IBS_DISABLED, &qca->flags) ||
test_bit(QCA_SUSPENDING, &qca->flags)) { test_bit(QCA_SUSPENDING, &qca->flags)) {
skb_queue_tail(&qca->txq, skb); skb_queue_tail(&qca->txq, skb);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
...@@ -1015,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work) ...@@ -1015,7 +1018,7 @@ static void qca_controller_memdump(struct work_struct *work)
* the controller to send the dump is 8 seconds. let us * the controller to send the dump is 8 seconds. let us
* start timer to handle this asynchronous activity. * start timer to handle this asynchronous activity.
*/ */
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags); set_bit(QCA_MEMDUMP_COLLECTION, &qca->flags);
dump = (void *) skb->data; dump = (void *) skb->data;
dump_size = __le32_to_cpu(dump->dump_size); dump_size = __le32_to_cpu(dump->dump_size);
...@@ -1619,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev) ...@@ -1619,6 +1622,7 @@ static int qca_power_on(struct hci_dev *hdev)
struct hci_uart *hu = hci_get_drvdata(hdev); struct hci_uart *hu = hci_get_drvdata(hdev);
enum qca_btsoc_type soc_type = qca_soc_type(hu); enum qca_btsoc_type soc_type = qca_soc_type(hu);
struct qca_serdev *qcadev; struct qca_serdev *qcadev;
struct qca_data *qca = hu->priv;
int ret = 0; int ret = 0;
/* Non-serdev device usually is powered by external power /* Non-serdev device usually is powered by external power
...@@ -1638,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev) ...@@ -1638,6 +1642,7 @@ static int qca_power_on(struct hci_dev *hdev)
} }
} }
clear_bit(QCA_BT_OFF, &qca->flags);
return ret; return ret;
} }
...@@ -1657,7 +1662,7 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1657,7 +1662,7 @@ static int qca_setup(struct hci_uart *hu)
return ret; return ret;
/* Patch downloading has to be done without IBS mode */ /* Patch downloading has to be done without IBS mode */
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
/* Enable controller to do both LE scan and BR/EDR inquiry /* Enable controller to do both LE scan and BR/EDR inquiry
* simultaneously. * simultaneously.
...@@ -1708,7 +1713,7 @@ static int qca_setup(struct hci_uart *hu) ...@@ -1708,7 +1713,7 @@ static int qca_setup(struct hci_uart *hu)
ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver, ret = qca_uart_setup(hdev, qca_baudrate, soc_type, soc_ver,
firmware_name); firmware_name);
if (!ret) { if (!ret) {
set_bit(QCA_IBS_ENABLED, &qca->flags); clear_bit(QCA_IBS_DISABLED, &qca->flags);
qca_debugfs_init(hdev); qca_debugfs_init(hdev);
hu->hdev->hw_error = qca_hw_error; hu->hdev->hw_error = qca_hw_error;
hu->hdev->cmd_timeout = qca_cmd_timeout; hu->hdev->cmd_timeout = qca_cmd_timeout;
...@@ -1816,7 +1821,7 @@ static void qca_power_shutdown(struct hci_uart *hu) ...@@ -1816,7 +1821,7 @@ static void qca_power_shutdown(struct hci_uart *hu)
* data in skb's. * data in skb's.
*/ */
spin_lock_irqsave(&qca->hci_ibs_lock, flags); spin_lock_irqsave(&qca->hci_ibs_lock, flags);
clear_bit(QCA_IBS_ENABLED, &qca->flags); set_bit(QCA_IBS_DISABLED, &qca->flags);
qca_flush(hu); qca_flush(hu);
spin_unlock_irqrestore(&qca->hci_ibs_lock, flags); spin_unlock_irqrestore(&qca->hci_ibs_lock, flags);
...@@ -1833,6 +1838,8 @@ static void qca_power_shutdown(struct hci_uart *hu) ...@@ -1833,6 +1838,8 @@ static void qca_power_shutdown(struct hci_uart *hu)
} else if (qcadev->bt_en) { } else if (qcadev->bt_en) {
gpiod_set_value_cansleep(qcadev->bt_en, 0); gpiod_set_value_cansleep(qcadev->bt_en, 0);
} }
set_bit(QCA_BT_OFF, &qca->flags);
} }
static int qca_power_off(struct hci_dev *hdev) static int qca_power_off(struct hci_dev *hdev)
...@@ -2090,11 +2097,34 @@ static int __maybe_unused qca_suspend(struct device *dev) ...@@ -2090,11 +2097,34 @@ static int __maybe_unused qca_suspend(struct device *dev)
bool tx_pending = false; bool tx_pending = false;
int ret = 0; int ret = 0;
u8 cmd; u8 cmd;
u32 wait_timeout = 0;
set_bit(QCA_SUSPENDING, &qca->flags); set_bit(QCA_SUSPENDING, &qca->flags);
/* Device is downloading patch or doesn't support in-band sleep. */ if (test_bit(QCA_BT_OFF, &qca->flags))
if (!test_bit(QCA_IBS_ENABLED, &qca->flags)) return 0;
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
wait_timeout = test_bit(QCA_SSR_TRIGGERED, &qca->flags) ?
IBS_DISABLE_SSR_TIMEOUT_MS :
FW_DOWNLOAD_TIMEOUT_MS;
/* QCA_IBS_DISABLED flag is set to true, During FW download
* and during memory dump collection. It is reset to false,
* After FW download complete and after memory dump collections.
*/
wait_on_bit_timeout(&qca->flags, QCA_IBS_DISABLED,
TASK_UNINTERRUPTIBLE, msecs_to_jiffies(wait_timeout));
if (test_bit(QCA_IBS_DISABLED, &qca->flags)) {
bt_dev_err(hu->hdev, "SSR or FW download time out");
ret = -ETIMEDOUT;
goto error;
}
}
/* After memory dump collection, Controller is powered off.*/
if (test_bit(QCA_BT_OFF, &qca->flags))
return 0; return 0;
cancel_work_sync(&qca->ws_awake_device); cancel_work_sync(&qca->ws_awake_device);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment