diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 6fa8177638e..2e96cb58372 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -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 diff --git a/drivers/bluetooth/hci/ipc.c b/drivers/bluetooth/hci/ipc.c index d25f7c8af10..28b2a322f60 100644 --- a/drivers/bluetooth/hci/ipc.c +++ b/drivers/bluetooth/hci/ipc.c @@ -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; @@ -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)