diff --git a/drivers/bluetooth/hci/Kconfig b/drivers/bluetooth/hci/Kconfig index 198d07ac4ac..2e7ec5e9781 100644 --- a/drivers/bluetooth/hci/Kconfig +++ b/drivers/bluetooth/hci/Kconfig @@ -112,26 +112,16 @@ config BT_RPMSG_NRF53 bool "nRF53 configuration of RPMsg" default y if SOC_NRF5340_CPUAPP depends on BT_RPMSG - select IPM - select IPM_NRFX - select IPM_MSG_CH_1_ENABLE - select IPM_MSG_CH_0_ENABLE - select IPM_MSG_CH_0_TX - select IPM_MSG_CH_1_RX - select OPENAMP + select RPMSG_SERVICE help Enable RPMsg configuration for nRF53. Two channels of the IPM driver are used in the HCI driver: channel 0 for TX and channel 1 for RX. if BT_RPMSG_NRF53 -config BT_RPMSG_NRF53_RX_STACK_SIZE - int "RPMsg stack size for RX thread" - default 1024 - -config BT_RPMSG_NRF53_RX_PRIO - int "RPMsg RX thread priority" - default 8 +choice RPMSG_SERVICE_MODE + default RPMSG_SERVICE_MODE_MASTER +endchoice endif # BT_RPMSG_NRF53 diff --git a/drivers/bluetooth/hci/rpmsg.c b/drivers/bluetooth/hci/rpmsg.c index 4706d2c3b52..d679af6cce1 100644 --- a/drivers/bluetooth/hci/rpmsg.c +++ b/drivers/bluetooth/hci/rpmsg.c @@ -23,6 +23,7 @@ int bt_rpmsg_platform_init(void); int bt_rpmsg_platform_send(struct net_buf *buf); +int bt_rpmsg_platform_endpoint_is_bound(void); static bool is_hci_event_discardable(const uint8_t *evt_data) { @@ -234,7 +235,10 @@ static int bt_rpmsg_open(void) { BT_DBG(""); - return bt_rpmsg_platform_init(); + while (!bt_rpmsg_platform_endpoint_is_bound()) { + k_sleep(K_MSEC(1)); + } + return 0; } static const struct bt_hci_driver drv = { @@ -251,7 +255,20 @@ static int bt_rpmsg_init(const struct device *unused) { ARG_UNUSED(unused); - return bt_hci_driver_register(&drv); + int err; + + err = bt_rpmsg_platform_init(); + if (err < 0) { + BT_ERR("Failed to initialize BT RPMSG (err %d)", err); + return err; + } + + err = bt_hci_driver_register(&drv); + if (err < 0) { + BT_ERR("Failed to register BT HIC driver (err %d)", err); + } + + return err; } -SYS_INIT(bt_rpmsg_init, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT); +SYS_INIT(bt_rpmsg_init, POST_KERNEL, CONFIG_RPMSG_SERVICE_EP_REG_PRIORITY); diff --git a/drivers/bluetooth/hci/rpmsg_nrf53.c b/drivers/bluetooth/hci/rpmsg_nrf53.c index 62afda90f60..4f07c92f507 100644 --- a/drivers/bluetooth/hci/rpmsg_nrf53.c +++ b/drivers/bluetooth/hci/rpmsg_nrf53.c @@ -6,10 +6,7 @@ #include -#include -#include -#include -#include +#include #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER) #define LOG_MODULE_NAME bt_hci_driver_nrf53 @@ -20,107 +17,10 @@ void bt_rpmsg_rx(uint8_t *data, size_t len); static K_SEM_DEFINE(ready_sem, 0, 1); static K_SEM_DEFINE(rx_sem, 0, 1); -static K_KERNEL_STACK_DEFINE(bt_rpmsg_rx_thread_stack, - CONFIG_BT_RPMSG_NRF53_RX_STACK_SIZE); -static struct k_thread bt_rpmsg_rx_thread_data; - -static const struct device *ipm_tx_handle; -static const struct device *ipm_rx_handle; - -/* Configuration defines */ - -#define SHM_NODE DT_CHOSEN(zephyr_ipc_shm) -#define SHM_BASE_ADDRESS DT_REG_ADDR(SHM_NODE) - -#define SHM_START_ADDR (SHM_BASE_ADDRESS + 0x400) -#define SHM_SIZE 0x7c00 -#define SHM_DEVICE_NAME "sram0.shm" - -BUILD_ASSERT((SHM_START_ADDR + SHM_SIZE - SHM_BASE_ADDRESS) - <= DT_REG_SIZE(SHM_NODE), - "Allocated size exceeds available shared memory reserved for IPC"); - -#define VRING_COUNT 2 -#define VRING_TX_ADDRESS (SHM_START_ADDR + SHM_SIZE - 0x400) -#define VRING_RX_ADDRESS (VRING_TX_ADDRESS - 0x400) -#define VRING_ALIGNMENT 4 -#define VRING_SIZE 16 - -#define VDEV_STATUS_ADDR SHM_BASE_ADDRESS - BUILD_ASSERT(CONFIG_HEAP_MEM_POOL_SIZE >= 1024, "Not enough heap memory for RPMsg queue allocation"); -/* End of configuration defines */ - -static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; -static struct metal_device shm_device = { - .name = SHM_DEVICE_NAME, - .bus = NULL, - .num_regions = 1, - .regions = { - { - .virt = (void *) SHM_START_ADDR, - .physmap = shm_physmap, - .size = SHM_SIZE, - .page_shift = 0xffffffff, - .page_mask = 0xffffffff, - .mem_flags = 0, - .ops = { NULL }, - }, - }, - .node = { NULL }, - .irq_num = 0, - .irq_info = NULL -}; - -static struct virtqueue *vq[2]; -static struct rpmsg_endpoint ep; - -static unsigned char virtio_get_status(struct virtio_device *vdev) -{ - return VIRTIO_CONFIG_STATUS_DRIVER_OK; -} - -static void virtio_set_status(struct virtio_device *vdev, unsigned char status) -{ - sys_write8(status, VDEV_STATUS_ADDR); -} - -static uint32_t virtio_get_features(struct virtio_device *vdev) -{ - return BIT(VIRTIO_RPMSG_F_NS); -} - -static void virtio_set_features(struct virtio_device *vdev, uint32_t features) -{ - /* No need for implementation */ -} - -static void virtio_notify(struct virtqueue *vq) -{ - int status; - - status = ipm_send(ipm_tx_handle, 0, 0, NULL, 0); - if (status != 0) { - BT_ERR("ipm_send failed to notify: %d", status); - } -} - -const struct virtio_dispatch dispatch = { - .get_status = virtio_get_status, - .set_status = virtio_set_status, - .get_features = virtio_get_features, - .set_features = virtio_set_features, - .notify = virtio_notify, -}; - -static void ipm_callback(const struct device *dev, void *context, - uint32_t id, volatile void *data) -{ - BT_DBG("Got callback of id %u", id); - k_sem_give(&rx_sem); -} +static int endpoint_id; static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src, void *priv) @@ -133,146 +33,28 @@ static int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, return RPMSG_SUCCESS; } -static void rpmsg_service_unbind(struct rpmsg_endpoint *ep) -{ - rpmsg_destroy_ept(ep); -} - -static void ns_bind_cb(struct rpmsg_device *rdev, const char *name, uint32_t dest) -{ - (void)rpmsg_create_ept(&ep, - rdev, - name, - RPMSG_ADDR_ANY, - dest, - endpoint_cb, - rpmsg_service_unbind); - - k_sem_give(&ready_sem); -} - -static void bt_rpmsg_rx_thread(void *p1, void *p2, void *p3) -{ - ARG_UNUSED(p1); - ARG_UNUSED(p2); - ARG_UNUSED(p3); - - while (1) { - int status = k_sem_take(&rx_sem, K_FOREVER); - - if (status == 0) { - virtqueue_notification(vq[0]); - } - } -} - int bt_rpmsg_platform_init(void) { int err; - struct metal_init_params metal_params = METAL_INIT_DEFAULTS; - static struct virtio_vring_info rvrings[2]; - static struct rpmsg_virtio_shm_pool shpool; - static struct virtio_device vdev; - static struct rpmsg_virtio_device rvdev; - static struct metal_io_region *io; - static struct metal_device *device; + err = rpmsg_service_register_endpoint("nrf_bt_hci", endpoint_cb); - /* Setup thread for RX data processing. */ - k_thread_create(&bt_rpmsg_rx_thread_data, bt_rpmsg_rx_thread_stack, - K_KERNEL_STACK_SIZEOF(bt_rpmsg_rx_thread_stack), - bt_rpmsg_rx_thread, NULL, NULL, NULL, - K_PRIO_COOP(CONFIG_BT_RPMSG_NRF53_RX_PRIO), - 0, K_NO_WAIT); - - /* Libmetal setup */ - err = metal_init(&metal_params); - if (err) { - BT_ERR("metal_init: failed - error code %d", err); - return err; + if (err < 0) { + LOG_ERR("Registering endpoint failed with %d", err); + return RPMSG_ERR_INIT; } - err = metal_register_generic_device(&shm_device); - if (err) { - BT_ERR("Couldn't register shared memory device: %d", err); - return err; - } + endpoint_id = err; - err = metal_device_open("generic", SHM_DEVICE_NAME, &device); - if (err) { - BT_ERR("metal_device_open failed: %d", err); - return err; - } - - io = metal_device_io_region(device, 0); - if (!io) { - BT_ERR("metal_device_io_region failed to get region"); - return -ENODEV; - } - - /* IPM setup */ - ipm_tx_handle = device_get_binding("IPM_0"); - if (!ipm_tx_handle) { - BT_ERR("Could not get TX IPM device handle"); - return -ENODEV; - } - - ipm_rx_handle = device_get_binding("IPM_1"); - if (!ipm_rx_handle) { - BT_ERR("Could not get RX IPM device handle"); - return -ENODEV; - } - - ipm_register_callback(ipm_rx_handle, ipm_callback, NULL); - - /* Virtqueue setup */ - vq[0] = virtqueue_allocate(VRING_SIZE); - if (!vq[0]) { - BT_ERR("virtqueue_allocate failed to alloc vq[0]"); - return -ENOMEM; - } - - vq[1] = virtqueue_allocate(VRING_SIZE); - if (!vq[1]) { - BT_ERR("virtqueue_allocate failed to alloc vq[1]"); - return -ENOMEM; - } - - rvrings[0].io = io; - rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS; - rvrings[0].info.num_descs = VRING_SIZE; - rvrings[0].info.align = VRING_ALIGNMENT; - rvrings[0].vq = vq[0]; - - rvrings[1].io = io; - rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS; - rvrings[1].info.num_descs = VRING_SIZE; - rvrings[1].info.align = VRING_ALIGNMENT; - rvrings[1].vq = vq[1]; - - vdev.role = RPMSG_MASTER; - vdev.vrings_num = VRING_COUNT; - vdev.func = &dispatch; - vdev.vrings_info = &rvrings[0]; - - rpmsg_virtio_init_shm_pool(&shpool, (void *)SHM_START_ADDR, SHM_SIZE); - err = rpmsg_init_vdev(&rvdev, &vdev, ns_bind_cb, io, &shpool); - if (err) { - BT_ERR("rpmsg_init_vdev failed %d", err); - return err; - } - - /* Wait til nameservice ep is setup */ - err = k_sem_take(&ready_sem, K_SECONDS(3)); - if (err) { - BT_ERR("No contact with network core EP (err %d)", err); - return err; - } - - return 0; + return RPMSG_SUCCESS; } int bt_rpmsg_platform_send(struct net_buf *buf) { - return rpmsg_send(&ep, buf->data, buf->len); + return rpmsg_service_send(endpoint_id, buf->data, buf->len); +} + +int bt_rpmsg_platform_endpoint_is_bound(void) +{ + return rpmsg_service_endpoint_is_bound(endpoint_id); } diff --git a/samples/bluetooth/hci_rpmsg/prj.conf b/samples/bluetooth/hci_rpmsg/prj.conf index d3445b93668..46a1992edc7 100644 --- a/samples/bluetooth/hci_rpmsg/prj.conf +++ b/samples/bluetooth/hci_rpmsg/prj.conf @@ -1,13 +1,7 @@ CONFIG_LOG=y -CONFIG_OPENAMP=y -CONFIG_IPM=y -CONFIG_IPM_NRFX=y - -CONFIG_IPM_MSG_CH_1_ENABLE=y -CONFIG_IPM_MSG_CH_1_TX=y -CONFIG_IPM_MSG_CH_0_ENABLE=y -CONFIG_IPM_MSG_CH_0_RX=y +CONFIG_RPMSG_SERVICE=y +CONFIG_RPMSG_SERVICE_MODE_REMOTE=y CONFIG_HEAP_MEM_POOL_SIZE=8192 @@ -18,3 +12,7 @@ CONFIG_BT_HCI_RAW=y CONFIG_BT_MAX_CONN=16 CONFIG_BT_CTLR_ASSERT_HANDLER=y CONFIG_BT_HCI_RAW_RESERVE=1 + +CONFIG_ASSERT=y +CONFIG_DEBUG_INFO=y +CONFIG_EXCEPTION_STACK_TRACE=y diff --git a/samples/bluetooth/hci_rpmsg/src/main.c b/samples/bluetooth/hci_rpmsg/src/main.c index 68dfe7abe9f..d328dc28718 100644 --- a/samples/bluetooth/hci_rpmsg/src/main.c +++ b/samples/bluetooth/hci_rpmsg/src/main.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Nordic Semiconductor ASA + * Copyright (c) 2019-2021 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ @@ -21,6 +21,8 @@ #include #include +#include + #include #include #include @@ -32,108 +34,7 @@ #define LOG_MODULE_NAME hci_rpmsg LOG_MODULE_REGISTER(LOG_MODULE_NAME); -/* Configuration defines */ -#if !DT_HAS_CHOSEN(zephyr_ipc_shm) -#error "Sample requires definition of shared memory for rpmsg" -#endif - -#define SHM_NODE DT_CHOSEN(zephyr_ipc_shm) -#define SHM_BASE_ADDRESS DT_REG_ADDR(SHM_NODE) -#define SHM_START_ADDR (SHM_BASE_ADDRESS + 0x400) -#define SHM_SIZE 0x7c00 -#define SHM_DEVICE_NAME "sram0.shm" - -BUILD_ASSERT((SHM_START_ADDR + SHM_SIZE - SHM_BASE_ADDRESS) - <= DT_REG_SIZE(SHM_NODE), - "Allocated size exceeds available shared memory reserved for IPC"); - -#define VRING_COUNT 2 -#define VRING_TX_ADDRESS (SHM_START_ADDR + SHM_SIZE - 0x400) -#define VRING_RX_ADDRESS (VRING_TX_ADDRESS - 0x400) -#define VRING_ALIGNMENT 4 -#define VRING_SIZE 16 - -#define VDEV_STATUS_ADDR SHM_BASE_ADDRESS - -/* End of configuration defines */ - -static const struct device *ipm_tx_handle; -static const struct device *ipm_rx_handle; - -static metal_phys_addr_t shm_physmap[] = { SHM_START_ADDR }; -static struct metal_device shm_device = { - .name = SHM_DEVICE_NAME, - .bus = NULL, - .num_regions = 1, - .regions = { - { - .virt = (void *) SHM_START_ADDR, - .physmap = shm_physmap, - .size = SHM_SIZE, - .page_shift = 0xffffffff, - .page_mask = 0xffffffff, - .mem_flags = 0, - .ops = { NULL }, - }, - }, - .node = { NULL }, - .irq_num = 0, - .irq_info = NULL -}; - -static struct virtqueue *vq[2]; -static struct rpmsg_endpoint ep; - -static struct k_work ipm_work; - -static unsigned char virtio_get_status(struct virtio_device *vdev) -{ - return sys_read8(VDEV_STATUS_ADDR); -} - -static uint32_t virtio_get_features(struct virtio_device *vdev) -{ - return BIT(VIRTIO_RPMSG_F_NS); -} - -static void virtio_set_status(struct virtio_device *vdev, unsigned char status) -{ - sys_write8(status, VDEV_STATUS_ADDR); -} - -static void virtio_notify(struct virtqueue *vq) -{ - int status; - - status = ipm_send(ipm_tx_handle, 0, 0, NULL, 0); - if (status != 0) { - LOG_ERR("ipm_send failed to notify: %d", status); - } -} - -const struct virtio_dispatch dispatch = { - .get_status = virtio_get_status, - .set_status = virtio_set_status, - .get_features = virtio_get_features, - .notify = virtio_notify, -}; - -static void ipm_callback_process(struct k_work *work) -{ - virtqueue_notification(vq[1]); -} - -static void ipm_callback(const struct device *dev, void *context, - uint32_t id, volatile void *data) -{ - LOG_INF("Got callback of id %u", id); - k_work_submit(&ipm_work); -} - -static void rpmsg_service_unbind(struct rpmsg_endpoint *ep) -{ - rpmsg_destroy_ept(ep); -} +static int endpoint_id; static K_THREAD_STACK_DEFINE(tx_thread_stack, CONFIG_BT_HCI_TX_STACK_SIZE); static struct k_thread tx_thread_data; @@ -323,7 +224,7 @@ static int hci_rpmsg_send(struct net_buf *buf) net_buf_push_u8(buf, pkt_indicator); LOG_HEXDUMP_DBG(buf->data, buf->len, "Final HCI buffer:"); - rpmsg_send(&ep, buf->data, buf->len); + rpmsg_service_send(endpoint_id, buf->data, buf->len); net_buf_unref(buf); @@ -346,110 +247,6 @@ int endpoint_cb(struct rpmsg_endpoint *ept, void *data, size_t len, uint32_t src return RPMSG_SUCCESS; } -static int hci_rpmsg_init(void) -{ - int err; - struct metal_init_params metal_params = METAL_INIT_DEFAULTS; - - static struct virtio_vring_info rvrings[2]; - static struct virtio_device vdev; - static struct rpmsg_device *rdev; - static struct rpmsg_virtio_device rvdev; - static struct metal_io_region *io; - static struct metal_device *device; - - /* Setup IPM workqueue item */ - k_work_init(&ipm_work, ipm_callback_process); - - /* Libmetal setup */ - err = metal_init(&metal_params); - if (err) { - LOG_ERR("metal_init: failed - error code %d", err); - return err; - } - - err = metal_register_generic_device(&shm_device); - if (err) { - LOG_ERR("Couldn't register shared memory device: %d", err); - return err; - } - - err = metal_device_open("generic", SHM_DEVICE_NAME, &device); - if (err) { - LOG_ERR("metal_device_open failed: %d", err); - return err; - } - - io = metal_device_io_region(device, 0); - if (!io) { - LOG_ERR("metal_device_io_region failed to get region"); - return -ENODEV; - } - - /* IPM setup */ - ipm_tx_handle = device_get_binding("IPM_1"); - if (!ipm_tx_handle) { - LOG_ERR("Could not get TX IPM device handle"); - return -ENODEV; - } - - ipm_rx_handle = device_get_binding("IPM_0"); - if (!ipm_rx_handle) { - LOG_ERR("Could not get RX IPM device handle"); - return -ENODEV; - } - - ipm_register_callback(ipm_rx_handle, ipm_callback, NULL); - - vq[0] = virtqueue_allocate(VRING_SIZE); - if (!vq[0]) { - LOG_ERR("virtqueue_allocate failed to alloc vq[0]"); - return -ENOMEM; - } - - vq[1] = virtqueue_allocate(VRING_SIZE); - if (!vq[1]) { - LOG_ERR("virtqueue_allocate failed to alloc vq[1]"); - return -ENOMEM; - } - - rvrings[0].io = io; - rvrings[0].info.vaddr = (void *)VRING_TX_ADDRESS; - rvrings[0].info.num_descs = VRING_SIZE; - rvrings[0].info.align = VRING_ALIGNMENT; - rvrings[0].vq = vq[0]; - - rvrings[1].io = io; - rvrings[1].info.vaddr = (void *)VRING_RX_ADDRESS; - rvrings[1].info.num_descs = VRING_SIZE; - rvrings[1].info.align = VRING_ALIGNMENT; - rvrings[1].vq = vq[1]; - - vdev.role = RPMSG_REMOTE; - vdev.vrings_num = VRING_COUNT; - vdev.func = &dispatch; - vdev.vrings_info = &rvrings[0]; - - /* setup rvdev */ - err = rpmsg_init_vdev(&rvdev, &vdev, NULL, io, NULL); - if (err) { - LOG_ERR("rpmsg_init_vdev failed %d", err); - return err; - } - - rdev = rpmsg_virtio_get_rpmsg_device(&rvdev); - - err = rpmsg_create_ept(&ep, rdev, "bt_hci", RPMSG_ADDR_ANY, - RPMSG_ADDR_ANY, endpoint_cb, - rpmsg_service_unbind); - if (err) { - LOG_ERR("rpmsg_create_ept failed %d", err); - return err; - } - - return err; -} - void main(void) { int err; @@ -457,12 +254,6 @@ void main(void) /* incoming events and data from the controller */ static K_FIFO_DEFINE(rx_queue); - /* initialize RPMSG */ - err = hci_rpmsg_init(); - if (err != 0) { - return; - } - LOG_DBG("Start"); /* Enable the raw interface, this will in turn open the HCI driver */ @@ -486,3 +277,22 @@ void main(void) } } } + +/* Make sure we register endpoint before RPMsg Service is initialized. */ +int register_endpoint(const struct device *arg) +{ + int status; + + status = rpmsg_service_register_endpoint("nrf_bt_hci", endpoint_cb); + + if (status < 0) { + LOG_ERR("Registering endpoint failed with %d", status); + return status; + } + + endpoint_id = status; + + return 0; +} + +SYS_INIT(register_endpoint, POST_KERNEL, CONFIG_RPMSG_SERVICE_EP_REG_PRIORITY);