bluetooth-init: validate HCI interface after initialization

Some Bluetooth controllers may expose hci0 even when the firmware
initialization has not completed correctly. In that state, the init
script may report success but bluetoothd cannot use the controller.

Validate the controller through the kernel management interface before
accepting the initialization as successful. This matches the interface
used by bluetoothd and catches controllers that are visible through HCI
but not registered in MGMT yet.

Use a timeout for the MGMT query so a broken controller state cannot
block the init script instead of falling back to the retry loop.

https://onedigi.atlassian.net/browse/DEL-9512

Signed-off-by: Isaac Hermida <isaac.hermida@digi.com>
This commit is contained in:
Isaac Hermida 2026-05-15 13:52:23 +02:00
parent 23c969f954
commit c7adf015f9
5 changed files with 53 additions and 17 deletions

View File

@ -48,12 +48,16 @@ bt_init() {
for i in $(seq ${RETRIES}); do
# Load manually the kernel module
modprobe "${MODULE_NAME}"
timeout 3 modprobe "${MODULE_NAME}"
sleep 1
# Reconfigure the HCI interface with the expected MAC address
is_kernel_module_loaded && set_btaddr && log info "Bluetooth activated" && return 0
is_kernel_module_loaded || continue
# Validate that the controller is available through the
# kernel management interface used by bluetoothd.
if timeout 3 btmgmt --index 0 info >/dev/null 2>&1; then
# Reconfigure the HCI interface with the expected MAC address
set_btaddr && log info "Bluetooth activated" && return 0
fi
bt_stop
if [ "$i" -lt "$RETRIES" ]; then
log err "Cannot initialize Bluetooth, retrying..."
fi

View File

@ -26,9 +26,15 @@ bluetooth_init() {
for RETRY in $(seq 1 5)
do
killproc hciattach
modprobe btdigi
timeout 3 modprobe btdigi
if hciattach ttyBt qca ${BT_RATE:-3000000} -t30 ${BT_FLOW:-flow} unused ${BT_MACADDR} >${HCIATTACH_LOG} 2>&1; then
return
# hciattach performs a reset to load the new firmware and needs some time to be ready
sleep 1
# Validate that the controller is available through the
# kernel management interface used by bluetoothd.
if timeout 3 btmgmt --index 0 info >/dev/null 2>&1; then
return
fi
fi
rmmod btdigi
sleep 1

View File

@ -50,6 +50,10 @@ is_kernel_module_loaded() {
lsmod | grep -qs -w "^${MODULE_NAME}"
}
unload_module() {
hciconfig "${HCI_IFACE}" up && rmmod "${MODULE_NAME}"
}
bluetooth_start() {
if ! [ -e "/proc/device-tree/bluetooth/mac-address" ]; then
log "[ERROR] Bluetooth mac-address not found"
@ -59,18 +63,31 @@ bluetooth_start() {
# If module is already loaded, skip
is_kernel_module_loaded && log "[ERROR] kernel module already present, skipping" && return 1
power 0 && sleep 0.2 && power 1
# Load manually the kernel module
modprobe "${MODULE_NAME}"
# Reconfigure the HCI interface with the expected MAC address and power levels
is_kernel_module_loaded && set_btaddr && set_power_config && log "Bluetooth activated" && return 0
for RETRY in $(seq 1 3)
do
power 0 && sleep 0.2 && power 1
# Load manually the kernel module
timeout 3 modprobe "${MODULE_NAME}"
is_kernel_module_loaded || continue
# Validate that the controller is available through the
# kernel management interface used by bluetoothd.
if timeout 3 btmgmt --index 0 info >/dev/null 2>&1; then
# Reconfigure the HCI interface with the expected MAC address and power levels
if set_btaddr && set_power_config; then
log "Bluetooth activated"
return 0
fi
fi
unload_module
power 0
done
log "[ERROR] Cannot initialize Bluetooth correctly" && return 1
}
is_system_running() {
state=$(systemctl is-system-running 2>/dev/null)
case "$state" in
running|degraded)
starting|running|degraded)
return 0 ;; # System is operational
*)
return 1 ;; # Assume not running
@ -84,7 +101,7 @@ bluetooth_stop() {
# sure the interface is UP before unloading the module.
#
if is_system_running; then
hciconfig "${HCI_IFACE}" up && rmmod "${MODULE_NAME}"
unload_module
power 0
else
log "System rebooting... not taking any action"

View File

@ -49,7 +49,13 @@ bluetooth_init() {
killproc hciattach
powercycle_gpio "${BT_EN_QCA_GPIO_NR}"
if hciattach ttyBt qca ${BT_RATE:-3000000} -t30 ${BT_FLOW:-flow} unused ${BT_MACADDR} >${HCIATTACH_LOG} 2>&1; then
return
# hciattach performs a reset to load the new firmware and needs some time to be ready
sleep 1
# Validate that the controller is available through the
# kernel management interface used by bluetoothd.
if timeout 3 btmgmt --index 0 info >/dev/null 2>&1; then
return
fi
fi
sleep 1
done

View File

@ -53,9 +53,12 @@ bt_init() {
# Attach serial UART to the Bluetooth stack
btattach -B /dev/ttySTM1 -P bcm -S 3000000 &
sleep 2
# Reconfigure the HCI interface with the expected MAC address
set_btaddr && log info "OK" && return 0
# Validate that the controller is available through the
# kernel management interface used by bluetoothd.
if timeout 3 btmgmt --index 0 info >/dev/null 2>&1; then
# Reconfigure the HCI interface with the expected MAC address
set_btaddr && log info "OK" && return 0
fi
fi
log err "FAILED to bring hci0 up, retrying..."
killall btattach 2> /dev/null