Skip to content

Commit

Permalink
[nrf fromlist] drivers: bluetooth: hci: Add retries for IPC interface
Browse files Browse the repository at this point in the history
Add HCI IPC retry handling in case of full IPC
queue. This mechanism improves reliability.

The ipc_service_send can return -ENOMEM in case
of full queue. If this happens the retries are
executed in order to wait for queue to empty
and not drop messages.
If the retry mechanism reaches maximum then
the error code is passed back to the host.

The change should improve the handling of
passing messages to full ipc and reduce
dropping of packets.

Upstream PR #: 85649

Signed-off-by: Dominik Chat <[email protected]>
  • Loading branch information
dchat-nordic authored and nordicjm committed Feb 24, 2025
1 parent cd78af5 commit 0aa2141
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 2 deletions.
18 changes: 18 additions & 0 deletions drivers/bluetooth/hci/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,24 @@ config BT_HCI_IPC
Bluetooth HCI driver for communication with another CPU
using the IPC subsystem.

config BT_HCI_IPC_SEND_RETRY_COUNT
int "HCI IPC send retry count"
depends on BT_HCI_IPC
default 3
help
Number of times to retry sending a message via IPC.
The retries occur in case of a failure to send a message
through IPC (-ENOMEM returned by ipc_service_send).

config BT_HCI_IPC_SEND_RETRY_DELAY_US
int "HCI IPC send retry delay (us)"
depends on BT_HCI_IPC
default 75
help
Delay in microseconds between retries when sending a message via IPC.
When a single tick (CONFIG_SYS_CLOCK_TICKS_PER_SEC) is bigger then
the retry delay the k_busy_wait function is used. Set with care.

config BT_SPI
bool
select SPI
Expand Down
28 changes: 26 additions & 2 deletions drivers/bluetooth/hci/ipc.c
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ LOG_MODULE_REGISTER(bt_hci_driver);

#define IPC_BOUND_TIMEOUT_IN_MS K_MSEC(1000)

/* The retry of ipc_service_send function requires a small (tens of us) delay.
* In order to ensure proper delay k_usleep is used when the system clock is
* precise enough and available (CONFIG_SYS_CLOCK_TICKS_PER_SEC different than 0).
*/
#define USE_SLEEP_BETWEEN_IPC_RETRIES COND_CODE_0(CONFIG_SYS_CLOCK_TICKS_PER_SEC, \
(false), \
((USEC_PER_SEC / CONFIG_SYS_CLOCK_TICKS_PER_SEC) > CONFIG_BT_HCI_IPC_SEND_RETRY_DELAY_US))

struct ipc_data {
bt_hci_recv_t recv;
struct ipc_ept hci_ept;
Expand Down Expand Up @@ -265,19 +273,35 @@ static int bt_ipc_send(const struct device *dev, struct net_buf *buf)
break;
default:
LOG_ERR("Unknown type %u", bt_buf_get_type(buf));
err = -ENOMSG;
goto done;
}
net_buf_push_u8(buf, pkt_indicator);

LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:");
err = ipc_service_send(&data->hci_ept, buf->data, buf->len);

for (int retries = 0; retries < CONFIG_BT_HCI_IPC_SEND_RETRY_COUNT + 1; retries++) {
err = ipc_service_send(&data->hci_ept, buf->data, buf->len);
if ((err >= 0) || (err != -ENOMEM)) {
break;
}

if (USE_SLEEP_BETWEEN_IPC_RETRIES) {
k_usleep(CONFIG_BT_HCI_IPC_SEND_RETRY_DELAY_US);
} else {
k_busy_wait(CONFIG_BT_HCI_IPC_SEND_RETRY_DELAY_US);
}
}

if (err < 0) {
LOG_ERR("Failed to send (err %d)", err);
} else {
err = 0;
}

done:
net_buf_unref(buf);
return 0;
return err;
}

static void hci_ept_bound(void *priv)
Expand Down

0 comments on commit 0aa2141

Please sign in to comment.