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 for i in $(seq ${RETRIES}); do
# Load manually the kernel module # Load manually the kernel module
modprobe "${MODULE_NAME}" timeout 3 modprobe "${MODULE_NAME}"
sleep 1 sleep 1
# Reconfigure the HCI interface with the expected MAC address is_kernel_module_loaded || continue
is_kernel_module_loaded && set_btaddr && log info "Bluetooth activated" && 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 "Bluetooth activated" && return 0
fi
bt_stop bt_stop
if [ "$i" -lt "$RETRIES" ]; then if [ "$i" -lt "$RETRIES" ]; then
log err "Cannot initialize Bluetooth, retrying..." log err "Cannot initialize Bluetooth, retrying..."
fi fi

View File

@ -26,9 +26,15 @@ bluetooth_init() {
for RETRY in $(seq 1 5) for RETRY in $(seq 1 5)
do do
killproc hciattach 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 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 fi
rmmod btdigi rmmod btdigi
sleep 1 sleep 1

View File

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

View File

@ -49,7 +49,13 @@ bluetooth_init() {
killproc hciattach killproc hciattach
powercycle_gpio "${BT_EN_QCA_GPIO_NR}" 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 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 fi
sleep 1 sleep 1
done done

View File

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