Re: [PATCH] Bluetooth: hci_qca: Reprobe QCA6390 after hibernation
From: Daniel Golle
Date: Mon Oct 19 2026 - 05:35:04 EST
Hi Nikolay,
On Sat, Oct 17, 2026 at 08:43:10PM +0300, Nikolay Bryskin wrote:
> +static void qca_reprobe_work(struct work_struct *work)
> +{
> + struct qca_reprobe *reprobe = container_of(work, struct qca_reprobe,
> + work);
> + int ret;
> +
> + ret = device_reprobe(reprobe->dev);
> + if (ret && ret != -EPROBE_DEFER)
> + dev_err(reprobe->dev, "Failed to reprobe device (error %d)\n",
> + ret);
> +
> + put_device(reprobe->dev);
> + kfree(reprobe);
> +}
This is the pattern hci_h5 and iwlwifi use today, and it has the same
two problems, which the series at [1] addresses with a driver core
helper, device_schedule_reprobe():
- qca_reprobe_work() lives in hci_uart.ko and nothing pins the module.
The work runs from thaw for the whole re-probe, firmware download
included, and an rmmod of hci_uart in that time frees the text it is
executing as well as the lock class key INIT_WORK() placed in module
data. On a lockdep kernel the latter ends in an oops; we reproduced
that with the equivalent iwlwifi work.
- device_reprobe() runs whatever is bound by then, so an unbind between
thaw and the work starting is undone.
With the helper the work item goes away entirely, and qca_restore()
becomes:
static int __maybe_unused qca_restore(struct device *dev)
{
struct serdev_device *serdev = to_serdev_device(dev);
struct qca_serdev *qcadev = serdev_device_get_drvdata(serdev);
struct hci_uart *hu = &qcadev->serdev_hu;
qca_resume(dev);
if (hci_test_quirk(hu->hdev, HCI_QUIRK_NON_PERSISTENT_SETUP))
return 0;
return device_schedule_reprobe(dev, 0);
}
It may be called from .restore with the device lock held, runs on
system_freezable_wq as yours does, and its request is cancelled if the
device is unbound, removed or its module unloaded before it runs.
Would you be fine basing your patch on it once it has landed?
[1] https://lore.kernel.org/all/cover.1792203271.git.daniel@xxxxxxxxxxxxxx/
Cheers,
Daniel