zephyr/drivers/bluetooth/hci/slz_hci.c
Aleksander Wasaznik b91728619c Bluetooth: host: remove CONFIG_BT_RECV_BLOCKING
This config selects a variant of the HCI driver interface that spills
out host internals unto the drivers and even the Zephyr controller. It
will now be removed in favor of driver interfaces that hide the
internals of the host.

The new default is `CONFIG_BT_RECV_WORKQ_BT`.

Any references to the removed kconfig are refactored out.

Any out-of-tree driver using the removed interface can be easily adapted
by copying the following implementations into the driver as private
functions:

 - `hci_driver.h:BT_HCI_EVT_FLAG_RECV_PRIO`
 - `hci_driver.h:BT_HCI_EVT_FLAG_RECV`
 - `hci_driver.h:bt_hci_evt_get_flags`
 - `hci_raw.c:bt_recv_prio`

In combination these symbols function as a interface adapter. These
symbols will be removed in this PR in subsequent commits.

Signed-off-by: Aleksander Wasaznik <aleksander.wasaznik@nordicsemi.no>
2024-03-26 11:17:29 -05:00

217 lines
5.1 KiB
C

/*
* Copyright (c) 2023 Antmicro <www.antmicro.com>
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <zephyr/drivers/bluetooth/hci_driver.h>
#include <sl_btctrl_linklayer.h>
#include <sl_hci_common_transport.h>
#include <pa_conversions_efr32.h>
#include <sl_bt_ll_zephyr.h>
#include <rail.h>
#define LOG_LEVEL CONFIG_BT_HCI_DRIVER_LOG_LEVEL
#include <zephyr/logging/log.h>
LOG_MODULE_REGISTER(bt_hci_driver_slz);
#define SL_BT_CONFIG_ACCEPT_LIST_SIZE 1
#define SL_BT_CONFIG_MAX_CONNECTIONS 1
#define SL_BT_CONFIG_USER_ADVERTISERS 1
#define SL_BT_CONTROLLER_BUFFER_MEMORY CONFIG_BT_SILABS_HCI_BUFFER_MEMORY
#define SL_BT_CONTROLLER_LE_BUFFER_SIZE_MAX CONFIG_BT_BUF_ACL_TX_COUNT
#define SL_BT_CONTROLLER_COMPLETED_PACKETS_THRESHOLD 1
#define SL_BT_CONTROLLER_COMPLETED_PACKETS_EVENTS_TIMEOUT 3
#define SL_BT_SILABS_LL_STACK_SIZE 1024
static K_KERNEL_STACK_DEFINE(slz_ll_stack, SL_BT_SILABS_LL_STACK_SIZE);
static struct k_thread slz_ll_thread;
void rail_isr_installer(void)
{
#ifdef CONFIG_SOC_SERIES_EFR32MG24
IRQ_CONNECT(SYNTH_IRQn, 0, SYNTH_IRQHandler, NULL, 0);
#else
IRQ_CONNECT(RDMAILBOX_IRQn, 0, RDMAILBOX_IRQHandler, NULL, 0);
#endif
IRQ_CONNECT(RAC_SEQ_IRQn, 0, RAC_SEQ_IRQHandler, NULL, 0);
IRQ_CONNECT(RAC_RSM_IRQn, 0, RAC_RSM_IRQHandler, NULL, 0);
IRQ_CONNECT(PROTIMER_IRQn, 0, PROTIMER_IRQHandler, NULL, 0);
IRQ_CONNECT(MODEM_IRQn, 0, MODEM_IRQHandler, NULL, 0);
IRQ_CONNECT(FRC_IRQn, 0, FRC_IRQHandler, NULL, 0);
IRQ_CONNECT(BUFC_IRQn, 0, BUFC_IRQHandler, NULL, 0);
IRQ_CONNECT(AGC_IRQn, 0, AGC_IRQHandler, NULL, 0);
}
/**
* @brief Transmit HCI message using the currently used transport layer.
* The HCI calls this function to transmit a full HCI message.
* @param[in] data Packet type followed by HCI packet data.
* @param[in] len Length of the `data` parameter
* @return 0 - on success, or non-zero on failure.
*/
uint32_t hci_common_transport_transmit(uint8_t *data, int16_t len)
{
struct net_buf *buf;
uint8_t packet_type = data[0];
uint8_t event_code;
LOG_HEXDUMP_DBG(data, len, "host packet data:");
/* drop packet type from the frame buffer - it is no longer needed */
data = &data[1];
len -= 1;
switch (packet_type) {
case h4_event:
event_code = data[0];
buf = bt_buf_get_evt(event_code, false, K_FOREVER);
break;
case h4_acl:
buf = bt_buf_get_rx(BT_BUF_ACL_IN, K_FOREVER);
break;
default:
LOG_ERR("Unknown HCI type: %d", packet_type);
return -EINVAL;
}
net_buf_add_mem(buf, data, len);
bt_recv(buf);
sl_btctrl_hci_transmit_complete(0);
return 0;
}
static int slz_bt_send(struct net_buf *buf)
{
int rv = 0;
switch (bt_buf_get_type(buf)) {
case BT_BUF_ACL_OUT:
net_buf_push_u8(buf, h4_acl);
break;
case BT_BUF_CMD:
net_buf_push_u8(buf, h4_command);
break;
default:
rv = -EINVAL;
goto done;
}
rv = hci_common_transport_receive(buf->data, buf->len, true);
if (!rv) {
goto done;
}
done:
net_buf_unref(buf);
return rv;
}
static void slz_thread_func(void *p1, void *p2, void *p3)
{
ARG_UNUSED(p1);
ARG_UNUSED(p2);
ARG_UNUSED(p3);
slz_ll_thread_func();
}
static int slz_bt_open(void)
{
int ret;
/* Start RX thread */
k_thread_create(&slz_ll_thread, slz_ll_stack,
K_KERNEL_STACK_SIZEOF(slz_ll_stack),
slz_thread_func, NULL, NULL, NULL,
K_PRIO_COOP(CONFIG_BT_DRIVER_RX_HIGH_PRIO), 0,
K_NO_WAIT);
rail_isr_installer();
sl_rail_util_pa_init();
/* sl_btctrl_init_mem returns the number of memory buffers allocated */
ret = sl_btctrl_init_mem(SL_BT_CONTROLLER_BUFFER_MEMORY);
if (!ret) {
LOG_ERR("Failed to allocate memory %d", ret);
return -ENOMEM;
}
sl_btctrl_configure_le_buffer_size(SL_BT_CONTROLLER_LE_BUFFER_SIZE_MAX);
ret = sl_btctrl_init_ll();
if (ret) {
LOG_ERR("Bluetooth link layer init failed %d", ret);
goto deinit;
}
sl_btctrl_init_adv();
sl_btctrl_init_scan();
sl_btctrl_init_conn();
sl_btctrl_init_adv_ext();
sl_btctrl_init_scan_ext();
ret = sl_btctrl_init_basic(SL_BT_CONFIG_MAX_CONNECTIONS,
SL_BT_CONFIG_USER_ADVERTISERS,
SL_BT_CONFIG_ACCEPT_LIST_SIZE);
if (ret) {
LOG_ERR("Failed to initialize the controller %d", ret);
goto deinit;
}
sl_btctrl_configure_completed_packets_reporting(
SL_BT_CONTROLLER_COMPLETED_PACKETS_THRESHOLD,
SL_BT_CONTROLLER_COMPLETED_PACKETS_EVENTS_TIMEOUT);
sl_bthci_init_upper();
sl_btctrl_hci_parser_init_default();
sl_btctrl_hci_parser_init_conn();
sl_btctrl_hci_parser_init_adv();
sl_btctrl_hci_parser_init_phy();
#ifdef CONFIG_PM
{
RAIL_Status_t status = RAIL_InitPowerManager();
if (status != RAIL_STATUS_NO_ERROR) {
LOG_ERR("RAIL: failed to initialize power management, status=%d",
status);
ret = -EIO;
goto deinit;
}
}
#endif
LOG_DBG("SiLabs BT HCI started");
return 0;
deinit:
sli_btctrl_deinit_mem();
return ret;
}
static const struct bt_hci_driver drv = {
.name = "sl:bt",
.bus = BT_HCI_DRIVER_BUS_UART,
.open = slz_bt_open,
.send = slz_bt_send,
.quirks = BT_QUIRK_NO_RESET
};
static int slz_bt_init(void)
{
int ret;
ret = bt_hci_driver_register(&drv);
if (ret) {
LOG_ERR("Failed to register SiLabs BT HCI %d", ret);
}
return ret;
}
SYS_INIT(slz_bt_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE);