diff mbox series

Bluetooth: btnxpuart: Fix baudrate reset on remove

Message ID 20250226151340.1017790-1-loic.poulain@linaro.org
State New
Headers show
Series Bluetooth: btnxpuart: Fix baudrate reset on remove | expand

Commit Message

Loic Poulain Feb. 26, 2025, 3:13 p.m. UTC
Trying to reset the baudrate from device remove callback does not
work if HCI dev is down and not running, causing the next device
probing to fail, as host/controller baudrates are then out-of-sync.

To prevent this issue, we ensure the controller's baudrate is always
reset to its initial value in the shutdown callback, during the hdev
close procedure. That guarantees subsequent open procedure to succeed,
regardless of any device removal/binding in between. This also means
we want to reconfigure the baudrate in the next hdev open procedure
via the setup() callback (HCI_QUIRK_NON_PERSISTENT_SETUP required).

In case of removal when the hdev is up and running, we have to call
the shutdown procedure explicitly before unregistering the hdev.

Signed-off-by: Loic Poulain <loic.poulain@linaro.org>
---
 drivers/bluetooth/btnxpuart.c | 20 ++++++++++++--------
 1 file changed, 12 insertions(+), 8 deletions(-)
diff mbox series

Patch

diff --git a/drivers/bluetooth/btnxpuart.c b/drivers/bluetooth/btnxpuart.c
index fc313559c2aa..b1344a9a8925 100644
--- a/drivers/bluetooth/btnxpuart.c
+++ b/drivers/bluetooth/btnxpuart.c
@@ -1274,6 +1274,9 @@  static int nxp_shutdown(struct hci_dev *hdev)
 			set_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
 		}
 		kfree_skb(skb);
+	} else if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
+		nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
+		nxp_set_baudrate_cmd(hdev, NULL);
 	}
 
 	return 0;
@@ -1578,6 +1581,8 @@  static int nxp_serdev_probe(struct serdev_device *serdev)
 	hdev->wakeup = nxp_wakeup;
 	SET_HCIDEV_DEV(hdev, &serdev->dev);
 
+	set_bit(HCI_QUIRK_NON_PERSISTENT_SETUP, &hdev->quirks);
+
 	if (hci_register_dev(hdev) < 0) {
 		dev_err(&serdev->dev, "Can't register HCI device\n");
 		goto probe_fail;
@@ -1603,16 +1608,15 @@  static void nxp_serdev_remove(struct serdev_device *serdev)
 		clear_bit(BTNXPUART_FW_DOWNLOADING, &nxpdev->tx_state);
 		wake_up_interruptible(&nxpdev->check_boot_sign_wait_q);
 		wake_up_interruptible(&nxpdev->fw_dnld_done_wait_q);
-	} else {
-		/* Restore FW baudrate to fw_init_baudrate if changed.
-		 * This will ensure FW baudrate is in sync with
-		 * driver baudrate in case this driver is re-inserted.
+	}
+
+	if (test_bit(HCI_RUNNING, &hdev->flags)) {
+		/* Ensure shutdown callback is executed before unregistering, so
+		 * that baudrate is reset to initial value.
 		 */
-		if (nxpdev->current_baudrate != nxpdev->fw_init_baudrate) {
-			nxpdev->new_baudrate = nxpdev->fw_init_baudrate;
-			nxp_set_baudrate_cmd(hdev, NULL);
-		}
+		nxp_shutdown(hdev);
 	}
+
 	ps_cleanup(nxpdev);
 	hci_unregister_dev(hdev);
 	hci_free_dev(hdev);