Skip to content

Commit 88e7223

Browse files
zijun-huVudentz
authored andcommitted
Bluetooth: qca: Fix BT enable failure again for QCA6390 after warm reboot
Commit 272970b ("Bluetooth: hci_qca: Fix driver shutdown on closed serdev") will cause below regression issue: BT can't be enabled after below steps: cold boot -> enable BT -> disable BT -> warm reboot -> BT enable failure if property enable-gpios is not configured within DT|ACPI for QCA6390. The commit is to fix a use-after-free issue within qca_serdev_shutdown() by adding condition to avoid the serdev is flushed or wrote after closed but also introduces this regression issue regarding above steps since the VSC is not sent to reset controller during warm reboot. Fixed by sending the VSC to reset controller within qca_serdev_shutdown() once BT was ever enabled, and the use-after-free issue is also fixed by this change since the serdev is still opened before it is flushed or wrote. Verified by the reported machine Dell XPS 13 9310 laptop over below two kernel commits: commit e00fc2700a3f ("Bluetooth: btusb: Fix triggering coredump implementation for QCA") of bluetooth-next tree. commit b23d98d ("Bluetooth: btusb: Fix triggering coredump implementation for QCA") of linus mainline tree. Fixes: 272970b ("Bluetooth: hci_qca: Fix driver shutdown on closed serdev") Cc: [email protected] Reported-by: Wren Turkal <[email protected]> Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218726 Signed-off-by: Zijun Hu <[email protected]> Tested-by: Wren Turkal <[email protected]> Signed-off-by: Luiz Augusto von Dentz <[email protected]>
1 parent ac65ecc commit 88e7223

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

drivers/bluetooth/hci_qca.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2450,15 +2450,27 @@ static void qca_serdev_shutdown(struct device *dev)
24502450
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
24512451
struct hci_uart *hu = &qcadev->serdev_hu;
24522452
struct hci_dev *hdev = hu->hdev;
2453-
struct qca_data *qca = hu->priv;
24542453
const u8 ibs_wake_cmd[] = { 0xFD };
24552454
const u8 edl_reset_soc_cmd[] = { 0x01, 0x00, 0xFC, 0x01, 0x05 };
24562455

24572456
if (qcadev->btsoc_type == QCA_QCA6390) {
2458-
if (test_bit(QCA_BT_OFF, &qca->flags) ||
2459-
!test_bit(HCI_RUNNING, &hdev->flags))
2457+
/* The purpose of sending the VSC is to reset SOC into a initial
2458+
* state and the state will ensure next hdev->setup() success.
2459+
* if HCI_QUIRK_NON_PERSISTENT_SETUP is set, it means that
2460+
* hdev->setup() can do its job regardless of SoC state, so
2461+
* don't need to send the VSC.
2462+
* if HCI_SETUP is set, it means that hdev->setup() was never
2463+
* invoked and the SOC is already in the initial state, so
2464+
* don't also need to send the VSC.
2465+
*/
2466+
if (test_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks) ||
2467+
hci_dev_test_flag(hdev, HCI_SETUP))
24602468
return;
24612469

2470+
/* The serdev must be in open state when conrol logic arrives
2471+
* here, so also fix the use-after-free issue caused by that
2472+
* the serdev is flushed or wrote after it is closed.
2473+
*/
24622474
serdev_device_write_flush(serdev);
24632475
ret = serdev_device_write_buf(serdev, ibs_wake_cmd,
24642476
sizeof(ibs_wake_cmd));

0 commit comments

Comments
 (0)