* [PATCH 0/2] Bluetooth: hci_bcm4377: resume after ACPI S3
@ 2026-11-07 15:48 Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 1/2] Bluetooth: hci_bcm4377: treat only negative hci_register_dev() returns as errors Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 2/2] Bluetooth: hci_bcm4377: probe again after a resume through firmware Andre Eikmeyer
0 siblings, 2 replies; 3+ messages in thread
From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw)
To: Sven Peter, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Janne Grunau, Neal Gompa, asahi, linux-arm-kernel,
linux-bluetooth, linux-kernel
After ACPI S3 the Bluetooth function of the BCM4377 comes back without
its firmware. Patch 2 probes it again after such a resume.
When the previous controller is still being released, the re-probe
registers the new one under another index, which runs into the probe
return check fixed in patch 1. Patch 1 is a fix on its own and goes
first.
The Wi-Fi function of the same chip needs the same after S3 and goes to
linux-wireless in "wifi: brcmfmac: pcie: S3 suspend and resume on the
T2 Mac chips".
Tested on a MacBookAir9,1 with three S3 cycles, holding the old
controller across each resume so the new one comes up under the other
index.
Andre Eikmeyer (2):
Bluetooth: hci_bcm4377: treat only negative hci_register_dev() returns
as errors
Bluetooth: hci_bcm4377: probe again after a resume through firmware
drivers/bluetooth/hci_bcm4377.c | 61 ++++++++++++++++++++++++++++++++-
1 file changed, 60 insertions(+), 1 deletion(-)
base-commit: 3f425f95ba3923d605f6a8b382e8fcdc59d479db
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 1/2] Bluetooth: hci_bcm4377: treat only negative hci_register_dev() returns as errors
2026-11-07 15:48 [PATCH 0/2] Bluetooth: hci_bcm4377: resume after ACPI S3 Andre Eikmeyer
@ 2026-11-07 15:48 ` Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 2/2] Bluetooth: hci_bcm4377: probe again after a resume through firmware Andre Eikmeyer
1 sibling, 0 replies; 3+ messages in thread
From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw)
To: Sven Peter, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Janne Grunau, Neal Gompa, asahi, linux-arm-kernel,
linux-bluetooth, linux-kernel
If another controller already holds hci0, a USB Bluetooth dongle for
example, the BCM4377 is registered as hci1 and probe returns 1. The PCI
core takes that as success, but the devm action that unregisters the
controller is never added, so it stays registered after unbind while
its driver data is freed.
hci_register_dev() returns the index of the new controller on success.
Check for a negative return, as the other drivers do.
Fixes: 8a06127602de ("Bluetooth: hci_bcm4377: Add new driver for BCM4377 PCIe boards")
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
---
drivers/bluetooth/hci_bcm4377.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index 66d49b47154..da0a48c2be3 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -2410,7 +2410,7 @@ static int bcm4377_probe(struct pci_dev *pdev, const struct pci_device_id *id)
return ret;
ret = hci_register_dev(hdev);
- if (ret)
+ if (ret < 0)
return ret;
return devm_add_action_or_reset(&pdev->dev, bcm4377_hci_unregister_dev,
hdev);
^ permalink raw reply [flat|nested] 3+ messages in thread
* [PATCH 2/2] Bluetooth: hci_bcm4377: probe again after a resume through firmware
2026-11-07 15:48 [PATCH 0/2] Bluetooth: hci_bcm4377: resume after ACPI S3 Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 1/2] Bluetooth: hci_bcm4377: treat only negative hci_register_dev() returns as errors Andre Eikmeyer
@ 2026-11-07 15:48 ` Andre Eikmeyer
1 sibling, 0 replies; 3+ messages in thread
From: Andre Eikmeyer @ 2026-11-07 15:48 UTC (permalink / raw)
To: Sven Peter, Marcel Holtmann, Luiz Augusto von Dentz
Cc: Janne Grunau, Neal Gompa, asahi, linux-arm-kernel,
linux-bluetooth, linux-kernel
The BCM4377 is powered off during ACPI S3 and loses its firmware. On
resume the driver only unquiesces it, so every command times out.
When the platform firmware handled the resume, probe the controller
again from a work item and skip the ring teardown messages to the lost
firmware.
Signed-off-by: Andre Eikmeyer <dev@deq.rocks>
---
drivers/bluetooth/hci_bcm4377.c | 59 +++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/drivers/bluetooth/hci_bcm4377.c b/drivers/bluetooth/hci_bcm4377.c
index da0a48c2be3..4e3630774c0 100644
--- a/drivers/bluetooth/hci_bcm4377.c
+++ b/drivers/bluetooth/hci_bcm4377.c
@@ -16,6 +16,9 @@
#include <linux/of.h>
#include <linux/pci.h>
#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/suspend.h>
+#include <linux/workqueue.h>
#include <linux/unaligned.h>
@@ -566,6 +569,9 @@ struct bcm4377_data {
struct pci_dev *pdev;
struct hci_dev *hdev;
+ /* set when the controller lost its firmware during system sleep */
+ bool fw_lost;
+
void __iomem *bar0;
void __iomem *bar2;
@@ -1017,6 +1023,11 @@ static int bcm4377_destroy_completion_ring(struct bcm4377_data *bcm4377,
struct bcm4377_destroy_completion_ring_msg msg;
int ret;
+ if (bcm4377->fw_lost) {
+ ring->enabled = false;
+ return 0;
+ }
+
memset(&msg, 0, sizeof(msg));
msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_COMPLETION_RING;
msg.ring_id = cpu_to_le16(ring->ring_id);
@@ -1107,6 +1118,11 @@ static int bcm4377_destroy_transfer_ring(struct bcm4377_data *bcm4377,
struct bcm4377_destroy_transfer_ring_msg msg;
int ret;
+ if (bcm4377->fw_lost) {
+ ring->enabled = false;
+ return 0;
+ }
+
memset(&msg, 0, sizeof(msg));
msg.msg_type = BCM4377_CONTROL_MSG_DESTROY_XFER_RING;
msg.ring_id = cpu_to_le16(ring->ring_id);
@@ -2432,11 +2448,54 @@ static int bcm4377_suspend(struct device *dev)
return 0;
}
+struct bcm4377_reprobe {
+ struct work_struct work;
+ struct pci_dev *pdev;
+};
+
+static void bcm4377_reprobe_work(struct work_struct *work)
+{
+ struct bcm4377_reprobe *reprobe =
+ container_of(work, struct bcm4377_reprobe, work);
+ int ret;
+
+ /*
+ * Probing stays blocked until the system resume completes, the driver
+ * core then retries the deferred probe.
+ */
+ ret = device_reprobe(&reprobe->pdev->dev);
+ if (ret && ret != -EPROBE_DEFER)
+ dev_err(&reprobe->pdev->dev, "re-probe after resume failed (%d)\n",
+ ret);
+
+ pci_dev_put(reprobe->pdev);
+ kfree(reprobe);
+}
+
static int bcm4377_resume(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
struct bcm4377_data *bcm4377 = pci_get_drvdata(pdev);
+ /*
+ * The controller is powered off when the platform firmware handles
+ * the system sleep, as with ACPI S3 on x86 Macs, and comes back
+ * without its firmware. Probe it again.
+ */
+ if (pm_resume_via_firmware()) {
+ struct bcm4377_reprobe *reprobe;
+
+ reprobe = kzalloc_obj(*reprobe);
+ if (!reprobe)
+ return -ENOMEM;
+
+ bcm4377->fw_lost = true;
+ reprobe->pdev = pci_dev_get(pdev);
+ INIT_WORK(&reprobe->work, bcm4377_reprobe_work);
+ schedule_work(&reprobe->work);
+ return 0;
+ }
+
iowrite32(BCM4377_BAR0_SLEEP_CONTROL_UNQUIESCE,
bcm4377->bar0 + BCM4377_BAR0_SLEEP_CONTROL);
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-11-07 15:48 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-11-07 15:48 [PATCH 0/2] Bluetooth: hci_bcm4377: resume after ACPI S3 Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 1/2] Bluetooth: hci_bcm4377: treat only negative hci_register_dev() returns as errors Andre Eikmeyer
2026-11-07 15:48 ` [PATCH 2/2] Bluetooth: hci_bcm4377: probe again after a resume through firmware Andre Eikmeyer
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®