public inbox for linux-bluetooth@vger.kernel.org
 help / color / mirror / Atom feed
From: Sasha Levin <sashal@kernel.org>
To: patches@lists.linux.dev, stable@vger.kernel.org
Cc: Shuai Zhang <shuai.zhang@oss.qualcomm.com>,
	Dmitry Baryshkov <dmitry.baryshkov@oss.qualcomm.com>,
	Luiz Augusto von Dentz <luiz.von.dentz@intel.com>,
	Sasha Levin <sashal@kernel.org>,
	brgl@kernel.org, marcel@holtmann.org, luiz.dentz@gmail.com,
	linux-arm-msm@vger.kernel.org, linux-bluetooth@vger.kernel.org
Subject: [PATCH AUTOSEL 6.19-6.18] Bluetooth: hci_qca: Fix SSR (SubSystem Restart) fail when BT_EN is pulled up by hw
Date: Sat, 14 Feb 2026 16:22:57 -0500	[thread overview]
Message-ID: <20260214212452.782265-32-sashal@kernel.org> (raw)
In-Reply-To: <20260214212452.782265-1-sashal@kernel.org>

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


       reply	other threads:[~2026-02-14 21:25 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <20260214212452.782265-1-sashal@kernel.org>
2026-02-14 21:22 ` Sasha Levin [this message]
2026-02-14 21:23 ` [PATCH AUTOSEL 6.19-6.18] Bluetooth: btusb: Add USB ID 0489:e112 for Realtek 8851BE Sasha Levin
2026-02-14 21:23 ` [PATCH AUTOSEL 6.19-6.12] Bluetooth: btusb: Add support for MediaTek7920 0489:e158 Sasha Levin
2026-02-14 21:23 ` [PATCH AUTOSEL 6.19-6.1] Bluetooth: btusb: Add new VID/PID for RTL8852CE Sasha Levin
2026-02-14 21:23 ` [PATCH AUTOSEL 6.19-6.6] Bluetooth: hci_conn: Set link_policy on incoming ACL connections Sasha Levin
2026-02-14 21:23 ` [PATCH AUTOSEL 6.19-5.10] Bluetooth: btusb: Add device ID for Realtek RTL8761BU Sasha Levin
2026-02-14 21:24 ` [PATCH AUTOSEL 6.19-5.10] Bluetooth: hci_conn: use mod_delayed_work for active mode timeout Sasha Levin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260214212452.782265-32-sashal@kernel.org \
    --to=sashal@kernel.org \
    --cc=brgl@kernel.org \
    --cc=dmitry.baryshkov@oss.qualcomm.com \
    --cc=linux-arm-msm@vger.kernel.org \
    --cc=linux-bluetooth@vger.kernel.org \
    --cc=luiz.dentz@gmail.com \
    --cc=luiz.von.dentz@intel.com \
    --cc=marcel@holtmann.org \
    --cc=patches@lists.linux.dev \
    --cc=shuai.zhang@oss.qualcomm.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox