Skip to content

hci_bcm4377 (BCM4388, M2 Pro): rfkill block during active LE scan causes HCI poweroff timeout (-110), ring destruction failures, and unrecoverable controller state #609

Description

@JJRPF

Hardware & Environment

  • Model: Apple MacBook Pro (14-inch, M2 Pro, 2023) (Mac14,9)
  • Device Tree Compatible: apple,j414s, apple,t6020, apple,arm-platform
  • OS / Distribution: Arch Linux ARM / Omarchy (Kernel: Linux 7.1.6-1-1-ARCH aarch64)
  • Bluetooth Device: 01:00.1 Network controller [0280]: Broadcom Inc. and subsidiaries BCM4388 Bluetooth Controller [14e4:5f72] (rev 04)
    • Subsystem: Apple Inc. Device [106b:4388]
    • Device Tree Node: /sys/firmware/devicetree/base/soc/pcie@580000000/pci@0,0/bluetooth@0,1
  • Driver: hci_bcm4377
  • BlueZ Version: 5.87-2

Description

When rfkill block bluetooth is triggered while the Bluetooth adapter is actively scanning (e.g., active LE discovery in a desktop environment) or exchanging traffic, hci_rfkill_set_block() calls hci_dev_do_poweroff(). The BCM4388 controller fails to respond to poweroff opcodes, resulting in an HCI tx timeout (-ETIMEDOUT / -110).

The kernel then attempts fallback device teardown via hci_dev_do_close(), where bcm4377_hci_close() attempts to destroy all 10 PCIe transfer and completion rings. Because the controller firmware is locked up, every ring destruction request times out (1s each, stalling the workqueue for ~10 seconds).

Crucially, unlike runtime command timeouts (e.g. as reported in #604 where the subsystem's cmd_timer initiates an automatic hci_bcm4377: resetting... reset done), in this rfkill teardown path NO automatic driver reset is ever triggered.

The device is left marked down in userland, but the underlying PCIe hardware / DMA engine remains in an unrecoverable dirty state. Subsequent calls to rfkill unblock bluetooth and bluetoothctl power on (hci_dev_open()) fail with Failed to set mode: Failed (0x03) / org.bluez.Error.Failed.

The only recovery without a full system reboot is manually unbinding and rebinding the PCIe driver via sysfs (echo 0000:01:00.1 > /sys/bus/pci/drivers/hci_bcm4377/unbind && echo 0000:01:00.1 > .../bind), which forces a clean hardware reset (hci_bcm4377: resetting... reset done).

(Note: This is distinct from #604: this occurs on BCM4388 [14e4:5f72] / M2 Pro, does not involve any WiFi brcmfmac errors or A2DP streaming crashes, is triggered directly by rfkill during LE scan, and does not automatically recover via driver reset).


Steps to Reproduce

  1. Ensure Bluetooth is powered on and actively discovering (e.g. bluetoothctl scan on, or opening a desktop environment status panel like GNOME/Omarchy Bluetooth panel).
  2. Soft-block Bluetooth via rfkill block bluetooth directly (without executing bluetoothctl power off first).
  3. Observe dmesg: HCI poweroff opcodes time out with -110, followed by 10 consecutive ring destruction timeouts taking ~10 seconds.
  4. Execute rfkill unblock bluetooth.
  5. Attempt to power the adapter back on: bluetoothctl power on.
  6. Result: bluetoothctl fails with Failed to set power on: org.bluez.Error.Failed and bluetoothd logs Failed to set mode: Failed (0x03).

Kernel Log (journalctl -k / dmesg)

Bluetooth: hci0: command 0x0c01 tx timeout
Bluetooth: hci0: Opcode 0x2005 failed: -110
Bluetooth: hci0: Opcode 0x2041 failed: -110
Bluetooth: hci0: command 0x0c01 tx timeout
Bluetooth: hci0: Opcode 0x2039 failed: -110
Bluetooth: hci0: Error when powering off device on rfkill (-110)
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 6
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 5
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 4
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 3
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 2
hci_bcm4377 0000:01:00.1: failed to destroy transfer ring 1
hci_bcm4377 0000:01:00.1: failed to destroy completion ring 4
hci_bcm4377 0000:01:00.1: failed to destroy completion ring 3
hci_bcm4377 0000:01:00.1: failed to destroy completion ring 2
hci_bcm4377 0000:01:00.1: failed to destroy completion ring 1

Subsequent bluetoothctl power on:

bluetoothd[961]: Failed to set mode: Failed (0x03)

Manual recovery via sysfs unbind/bind:

hci_bcm4377 0000:01:00.1: resetting
hci_bcm4377 0000:01:00.1: reset done
Bluetooth: MGMT ver 1.23

Analysis of drivers/bluetooth/hci_bcm4377.c

  1. hci_rfkill_set_block() calls hci_dev_do_poweroff(hdev), which fails due to opcode timeouts and returns -ETIMEDOUT.
  2. hci_rfkill_set_block() catches the error, logs "Error when powering off device on rfkill (-110)", and falls back to hci_dev_do_close(hdev).
  3. In hci_bcm4377.c, bcm4377_hci_close() loops through:
    • bcm4377_destroy_transfer_ring() for 6 transfer rings
    • bcm4377_destroy_completion_ring() for 4 completion rings
  4. Each call uses wait_for_completion_interruptible_timeout(&event, BCM4377_TIMEOUT) (1 second). When the chip is locked up, every call times out.
  5. Because this teardown occurred inside the intentional close path, the kernel core marks the device closed and does NOT trigger an automatic PCIe device reset.
  6. When bcm4377_hci_open() is called later, it attempts to recreate rings and talk to a chip whose firmware/DMA engine is still hung from the uncompleted poweroff.

Suggested Driver Improvements

  1. Trigger PCIe Reset on Dirty Close / Re-Open:
    If bcm4377_hci_close() fails to cleanly destroy any transfer or completion rings, flag the device instance (e.g. bcm4377->needs_reset = true). In bcm4377_hci_open(), if needs_reset is set, perform a full chip reset (similar to probe / bcm4377_pci_reset) before attempting to initialize rings.
  2. Fast-Fail on Ring Destruction:
    If the control ring fails to acknowledge the first BCM4377_CONTROL_MSG_DESTROY_XFER_RING with a timeout, subsequent ring destroy operations are guaranteed to fail as well. Fast-failing the remaining rings instead of waiting 1 second per ring would prevent blocking kernel workqueues for 10 seconds.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions