[PATCH AUTOSEL 6.19-6.18] Bluetooth: hci_qca: Fix SSR (SubSystem Restart) fail when BT_EN is pulled up by hw

Sasha Levin
2026-02-14T21:25:51Z

From: Shuai Zhang <shuai.zhang@oss.qualcomm.com>

[ Upstream commit fce1a9244a0f85683be8530e623bc729f24c5067 ]

On QCS9075 and QCA8275 platforms, the BT_EN pin is always pulled up by hw
and cannot be controlled by the host. As a result, in case of a firmware
crash, the host cannot trigger a cold reset. Instead, the BT controller
performs a warm restart on its own, without reloading the firmware.

This leads to the controller remaining in IBS_WAKE state, while the host
expects it to be in sleep mode. The mismatch causes HCI reset commands
to time out. Additionally, the driver does not clear internal flags
QCA_SSR_TRIGGERED and QCA_IBS_DISABLED, which blocks the reset sequence.
If the SSR duration exceeds 2 seconds, the host may enter TX sleep mode
due to tx_idle_timeout, further preventing recovery. Also, memcoredump_flag
is not cleared, so only the first SSR generates a coredump.

Tell the driver that the BT controller has undergone a proper restart sequence:

- Clear QCA_SSR_TRIGGERED and QCA_IBS_DISABLED flags after SSR.
- Add a 50ms delay to allow the controller to complete its warm reset.
- Reset tx_idle_timer to prevent the host from entering TX sleep mode.
- Clear memcoredump_flag to allow multiple coredump captures.

Apply these steps only when HCI_QUIRK_NON_PERSISTENT_SETUP is not set,
which indicates that BT_EN is defined in DTS and cannot be toggled.

Refer to the comment in include/net/bluetooth/hci.h for details on
HCI_QUIRK_NON_PERSISTENT_SETUP.

Reviewed-by: Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>
Signed-off-by: Shuai Zhang <shuai.zhang@oss.qualcomm.com>
Signed-off-by: Luiz Augusto von Dentz <luiz.von.dentz@intel.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>
---

LLM Generated explanations, may be completely bogus:

`HCI_QUIRK_NON_PERSISTENT_SETUP` has existed since 2018 (commit
`740011cfe9485`), so it's available in all stable trees. The only issue
is the accessor macro change (`test_bit` → `hci_test_quirk`).

### 8. FINAL ASSESSMENT

**Bug being fixed**: Real, user-impacting bug — Bluetooth SSR (SubSystem
Restart) fails on specific Qualcomm platforms (QCS9075, QCA8275) where
BT_EN is hardware-pulled high. After a firmware crash, Bluetooth becomes
permanently non-functional until reboot.

**Severity**: HIGH — Complete loss of Bluetooth functionality after
firmware crash with no recovery path.

**Fix quality**: Well-documented, well-reviewed (by Qualcomm and
Bluetooth maintainers), small and contained.

**Scope**: LOW risk — only affects platforms where
`HCI_QUIRK_NON_PERSISTENT_SETUP` is NOT set (specific hardware
configuration). Does not change behavior for any other platforms.

**Backportability concern**: The `hci_test_quirk()` macro only exists in
v6.16+. For older stable trees (6.1.y, 6.6.y, 6.12.y, 6.13.y), the
backport would need to use `!test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP,
&hu->hdev->quirks)` instead. This is a trivial adaptation but means the
patch won't apply cleanly to older stable trees.

**Other concern**: The fix adds `msleep(50)` in the hw_error path, which
is acceptable for an error recovery path but not something you'd want in
a hot path.

**Verdict**: This fixes a real, important bug (complete Bluetooth
failure after firmware crash) on specific hardware. The fix is small,
well-contained, and guarded by a quirk check so it has minimal risk. It
meets stable kernel criteria. The backport will need minor adaptation
for older trees due to the quirk API change, but this is
straightforward. The fix has proper review from Qualcomm and the
Bluetooth subsystem maintainer.

**YES**

drivers/bluetooth/hci_qca.c | 33 +++++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)

diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
index 888176b0faa90..a3c217571c3c4 100644
--- a/drivers/bluetooth/hci_qca.c
+++ b/drivers/bluetooth/hci_qca.c
@@ -1653,6 +1653,39 @@ static void qca_hw_error(struct hci_dev *hdev, u8 code)
skb_queue_purge(&qca->rx_memdump_q);
}

+ /*
+ * If the BT chip's bt_en pin is connected to a 3.3V power supply via
+ * hardware and always stays high, driver cannot control the bt_en pin.
+ * As a result, during SSR (SubSystem Restart), QCA_SSR_TRIGGERED and
+ * QCA_IBS_DISABLED flags cannot be cleared, which leads to a reset
+ * command timeout.
+ * Add an msleep delay to ensure controller completes the SSR process.
+ *
+ * Host will not download the firmware after SSR, controller to remain
+ * in the IBS_WAKE state, and the host needs to synchronize with it
+ *
+ * Since the bluetooth chip has been reset, clear the memdump state.
+ */
+ if (!hci_test_quirk(hu->hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) {
+ /*
+ * When the SSR (SubSystem Restart) duration exceeds 2 seconds,
+ * it triggers host tx_idle_delay, which sets host TX state
+ * to sleep. Reset tx_idle_timer after SSR to prevent
+ * host enter TX IBS_Sleep mode.
+ */
+ mod_timer(&qca->tx_idle_timer, jiffies +
+ msecs_to_jiffies(qca->tx_idle_delay));
+
+ /* Controller reset completion time is 50ms */
+ msleep(50);
+
+ clear_bit(QCA_SSR_TRIGGERED, &qca->flags);
+ clear_bit(QCA_IBS_DISABLED, &qca->flags);
+
+ qca->tx_ibs_state = HCI_IBS_TX_AWAKE;
+ qca->memdump_state = QCA_MEMDUMP_IDLE;
+ }
+
clear_bit(QCA_HW_ERROR_EVENT, &qca->flags);
}

--
2.51.0