From: Markus Probst <markus.probst@posteo.de>
To: Michael McAllister <me@michaelmcallister.org>,
Marcel Holtmann <marcel@holtmann.org>,
Luiz Augusto von Dentz <luiz.dentz@gmail.com>,
Bartosz Golaszewski <brgl@kernel.org>,
linux-bluetooth@vger.kernel.org
Cc: linux-arm-msm@vger.kernel.org, linux-kernel@vger.kernel.org,
Balakrishna Godavarthi <quic_bgodavar@quicinc.com>,
Dmitry Baryshkov <lumag@kernel.org>,
Matthias Kaehlcke <mka@chromium.org>
Subject: Re: [PATCH 2/4] Bluetooth: hci_serdev: Track whether the serial port is open
Date: Thu, 12 Nov 2026 18:56:00 +0000 [thread overview]
Message-ID: <341e56b1ff7d8a5b109e26e30dfed61faa54d603.camel@posteo.de> (raw)
In-Reply-To: <179322687811.94538.11949086384142524062.wcn3950-poweroff-v1-2@michaelmcallister.org>
[-- Attachment #1: Type: text/plain, Size: 7741 bytes --]
On Wed, 2026-10-28 at 22:34 +0000, Michael McAllister wrote:
> QCA setup temporarily closes the serial port while enabling the supplies.
> If enabling the supplies or reopening the port fails, PROTO_READY stays
> set. Error cleanup can then flush or close an already-closed port.
>
> Track the open state separately from protocol readiness. Use the same
> open and close helpers in the transport and the QCA and Marvell drivers,
> so setup retries do not close the port twice. Skip the serial flush when
> the port is closed, while still flushing the protocol queues.
>
> Close the port during unregister according to its actual open state.
>
> Signed-off-by: Michael McAllister <me@michaelmcallister.org>
> ---
> drivers/bluetooth/hci_mrvl.c | 4 ++--
> drivers/bluetooth/hci_qca.c | 12 +++++------
> drivers/bluetooth/hci_serdev.c | 37 +++++++++++++++++++++++++++-------
> drivers/bluetooth/hci_uart.h | 3 +++
> 4 files changed, 41 insertions(+), 15 deletions(-)
>
> diff --git a/drivers/bluetooth/hci_mrvl.c b/drivers/bluetooth/hci_mrvl.c
> index 5798a8db0..38d9add89 100644
> --- a/drivers/bluetooth/hci_mrvl.c
> +++ b/drivers/bluetooth/hci_mrvl.c
> @@ -76,7 +76,7 @@ static int mrvl_open(struct hci_uart *hu)
> hu->priv = mrvl;
>
> if (hu->serdev) {
> - ret = serdev_device_open(hu->serdev);
> + ret = hci_uart_serdev_open(hu);
Hi,
Why is `serdev_device_open`/`hci_uart_serdev_open` even called here?
According to Sashiko [1], `hci_uart_register_device` already calls
`serdev_device_open` and directly after that `p->open` (effectively
`mvrl_open` and thus another `serdev_device_open`). If Sashiko is right
(which appears to be the case at first look), the device is always
opened twice on probe.
From what I can tell, opening it twice is *undefined behaviour*. This
patch adds a check if the device is open, before calling
`serdev_device_open`. This solves the issue (possibly by accident), but
does not explain why it exists in the first place.
My patch [2] would instead return the error -EALREADY, which could
prevent it to probe entirely. It would also allow calling
`serdev_device_close` on a already closed serdev device, which makes
the use in the commit message obsolete.
Thanks
- Markus Probst
[1]
https://lore.kernel.org/linux-serial/sashiko-outbox-211656@kernel.org/
[2]
https://lore.kernel.org/linux-serial/20261112-rust_serdev_probe_refactor-v6-1-3568ed56264c@posteo.de/
> if (ret)
> goto err;
> }
> @@ -95,7 +95,7 @@ static int mrvl_close(struct hci_uart *hu)
> BT_DBG("hu %p", hu);
>
> if (hu->serdev)
> - serdev_device_close(hu->serdev);
> + hci_uart_serdev_close(hu);
>
> skb_queue_purge(&mrvl->txq);
> skb_queue_purge(&mrvl->rawq);
> diff --git a/drivers/bluetooth/hci_qca.c b/drivers/bluetooth/hci_qca.c
> index 8705c4543..3d9e6cd15 100644
> --- a/drivers/bluetooth/hci_qca.c
> +++ b/drivers/bluetooth/hci_qca.c
> @@ -1755,8 +1755,8 @@ static int qca_port_reopen(struct hci_uart *hu)
> * Without this, we will have RTS and CTS synchronization
> * issues.
> */
> - serdev_device_close(hu->serdev);
> - ret = serdev_device_open(hu->serdev);
> + hci_uart_serdev_close(hu);
> + ret = hci_uart_serdev_open(hu);
> if (ret) {
> bt_dev_err(hu->hdev, "failed to open port");
> return ret;
> @@ -1780,12 +1780,12 @@ static int qca_regulator_init(struct hci_uart *hu)
> qcadev = serdev_device_get_drvdata(hu->serdev);
>
> if (!qcadev->bt_power->vregs_on) {
> - serdev_device_close(hu->serdev);
> + hci_uart_serdev_close(hu);
> ret = qca_regulator_enable(qcadev);
> if (ret)
> return ret;
>
> - ret = serdev_device_open(hu->serdev);
> + ret = hci_uart_serdev_open(hu);
> if (ret) {
> bt_dev_err(hu->hdev, "failed to open port");
> return ret;
> @@ -2061,8 +2061,8 @@ static int qca_setup(struct hci_uart *hu)
> if (retries < MAX_INIT_RETRIES) {
> bt_dev_warn(hdev, "Retry BT power ON:%d", retries);
> if (hu->serdev) {
> - serdev_device_close(hu->serdev);
> - ret = serdev_device_open(hu->serdev);
> + hci_uart_serdev_close(hu);
> + ret = hci_uart_serdev_open(hu);
> if (ret) {
> bt_dev_err(hdev, "failed to open port");
> return ret;
> diff --git a/drivers/bluetooth/hci_serdev.c b/drivers/bluetooth/hci_serdev.c
> index 48ba017e2..05aa490a9 100644
> --- a/drivers/bluetooth/hci_serdev.c
> +++ b/drivers/bluetooth/hci_serdev.c
> @@ -21,6 +21,29 @@
>
> #include "hci_uart.h"
>
> +int hci_uart_serdev_open(struct hci_uart *hu)
> +{
> + int err;
> +
> + if (hu->serdev_open)
> + return 0;
> +
> + err = serdev_device_open(hu->serdev);
> + if (!err)
> + hu->serdev_open = true;
> +
> + return err;
> +}
> +
> +void hci_uart_serdev_close(struct hci_uart *hu)
> +{
> + if (!hu->serdev_open)
> + return;
> +
> + hu->serdev_open = false;
> + serdev_device_close(hu->serdev);
> +}
> +
> static inline void hci_uart_tx_complete(struct hci_uart *hu, int pkt_type)
> {
> struct hci_dev *hdev = hu->hdev;
> @@ -102,7 +125,8 @@ static int hci_uart_flush(struct hci_dev *hdev)
> }
>
> /* Flush any pending characters in the driver and discipline. */
> - serdev_device_write_flush(hu->serdev);
> + if (hu->serdev_open)
> + serdev_device_write_flush(hu->serdev);
>
> if (test_bit(HCI_UART_PROTO_READY, &hu->flags))
> hu->proto->flush(hu);
> @@ -123,7 +147,7 @@ static int hci_uart_open(struct hci_dev *hdev)
> * BT OFF. Upon next BT ON UART port should be opened.
> */
> if (!test_bit(HCI_UART_PROTO_READY, &hu->flags)) {
> - err = serdev_device_open(hu->serdev);
> + err = hci_uart_serdev_open(hu);
> if (err)
> return err;
> set_bit(HCI_UART_PROTO_READY, &hu->flags);
> @@ -154,7 +178,7 @@ static int hci_uart_close(struct hci_dev *hdev)
> */
> if (hci_test_quirk(hdev, HCI_QUIRK_NON_PERSISTENT_SETUP)) {
> clear_bit(HCI_UART_PROTO_READY, &hu->flags);
> - serdev_device_close(hu->serdev);
> + hci_uart_serdev_close(hu);
> }
>
> return 0;
> @@ -314,7 +338,7 @@ int hci_uart_register_device_priv(struct hci_uart *hu,
> if (percpu_init_rwsem(&hu->proto_lock))
> return -ENOMEM;
>
> - err = serdev_device_open(hu->serdev);
> + err = hci_uart_serdev_open(hu);
> if (err)
> goto err_rwsem;
>
> @@ -385,7 +409,7 @@ int hci_uart_register_device_priv(struct hci_uart *hu,
> clear_bit(HCI_UART_PROTO_READY, &hu->flags);
> p->close(hu);
> err_open:
> - serdev_device_close(hu->serdev);
> + hci_uart_serdev_close(hu);
> err_rwsem:
> percpu_free_rwsem(&hu->proto_lock);
> return err;
> @@ -438,8 +462,7 @@ void hci_uart_unregister_device(struct hci_uart *hu)
> */
> hu->proto->close(hu);
>
> - if (proto_ready)
> - serdev_device_close(hu->serdev);
> + hci_uart_serdev_close(hu);
>
> hci_free_dev(hdev);
>
> diff --git a/drivers/bluetooth/hci_uart.h b/drivers/bluetooth/hci_uart.h
> index 7fbe8dffa..2f8e346f3 100644
> --- a/drivers/bluetooth/hci_uart.h
> +++ b/drivers/bluetooth/hci_uart.h
> @@ -66,6 +66,7 @@ struct hci_uart_proto {
> struct hci_uart {
> struct tty_struct *tty;
> struct serdev_device *serdev;
> + bool serdev_open;
> struct hci_dev *hdev;
> unsigned long flags;
> unsigned long hdev_flags;
> @@ -112,6 +113,8 @@ static inline int hci_uart_register_device(struct hci_uart *hu,
> }
>
> void hci_uart_unregister_device(struct hci_uart *hu);
> +int hci_uart_serdev_open(struct hci_uart *hu);
> +void hci_uart_serdev_close(struct hci_uart *hu);
>
> int hci_uart_tx_wakeup(struct hci_uart *hu);
> int hci_uart_wait_until_sent(struct hci_uart *hu);
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 870 bytes --]
prev parent reply other threads:[~2026-11-12 18:56 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 22:34 [PATCH 0/4] Bluetooth: qca: Fix WCN3950 power-off Michael McAllister
2026-10-28 22:34 ` [PATCH 4/4] Bluetooth: qca: Power off WCN3950 Michael McAllister
2026-10-28 22:34 ` [PATCH 3/4] Bluetooth: qca: Power off after unregistering the HCI device Michael McAllister
2026-10-28 22:34 ` [PATCH 1/4] Bluetooth: qca: Restore flow control after a failed power pulse Michael McAllister
2026-10-28 22:34 ` [PATCH 2/4] Bluetooth: hci_serdev: Track whether the serial port is open Michael McAllister
2026-11-12 18:56 ` Markus Probst [this message]
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=341e56b1ff7d8a5b109e26e30dfed61faa54d603.camel@posteo.de \
--to=markus.probst@posteo.de \
--cc=brgl@kernel.org \
--cc=linux-arm-msm@vger.kernel.org \
--cc=linux-bluetooth@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=luiz.dentz@gmail.com \
--cc=lumag@kernel.org \
--cc=marcel@holtmann.org \
--cc=me@michaelmcallister.org \
--cc=mka@chromium.org \
--cc=quic_bgodavar@quicinc.com \
/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
all inboxes | Powered by JetHome®