Skip to content

Commit 6e9bfd5

Browse files
dchat-nordicrlubos
authored andcommitted
applications: ipc_radio: Fix ipc_radio dropping HCI packets
Fix ipc_radio dropping HCI packets, by utilizing the hold buffer functionality of the IPC. Jira: NCSDK-31261 Signed-off-by: Dominik Chat <[email protected]>
1 parent 00b6cd8 commit 6e9bfd5

File tree

2 files changed

+110
-50
lines changed

2 files changed

+110
-50
lines changed

applications/ipc_radio/Kconfig

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ choice IPC_RADIO_BT_SER
2828
config IPC_RADIO_BT_HCI_IPC
2929
bool "Bluetooth HCI serialization"
3030
depends on IPC_SERVICE
31+
depends on IPC_SERVICE_BACKEND_ICBMSG || IPC_SERVICE_BACKEND_RPMSG
3132
depends on BT_HCI_RAW
3233
help
3334
Use Bluetooth HCI serialization over ipc_service.
@@ -40,6 +41,22 @@ config IPC_RADIO_BT_RPC
4041

4142
endchoice # IPC_RADIO_BT_SER
4243

44+
if IPC_RADIO_BT_HCI_IPC
45+
46+
config QUEUE_THREAD_STACK_SIZE
47+
int "Queue thread stack size"
48+
default 512
49+
help
50+
Stack size for the queue thread.
51+
52+
config QUEUE_THREAD_PRIO
53+
int "Queue thread priority"
54+
default 7
55+
help
56+
Priority for the queue thread.
57+
58+
endif # IPC_RADIO_BT_HCI_IPC
59+
4360
config SETTINGS
4461
imply ZMS if SOC_FLASH_NRF_MRAM
4562
imply NVS if !SOC_FLASH_NRF_MRAM

applications/ipc_radio/src/bt_hci_ipc.c

Lines changed: 93 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,17 @@
3131

3232
#include "ipc_bt.h"
3333

34+
#if DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_bt_hci_ipc), zephyr_ipc_openamp_static_vrings)
35+
#include <openamp/rpmsg_virtio.h>
36+
#define IPC_BUF_SIZE DT_PROP_OR(DT_CHOSEN(zephyr_bt_hci_ipc), zephyr_buffer_size, RPMSG_BUFFER_SIZE)
37+
#define IPC_MEM_SIZE (DT_REG_SIZE(DT_PHANDLE(DT_CHOSEN(zephyr_bt_hci_ipc), memory_region)) / 2)
38+
#define MAX_IPC_BLOCKS DIV_ROUND_UP(IPC_MEM_SIZE, IPC_BUF_SIZE)
39+
#elif DT_NODE_HAS_COMPAT(DT_CHOSEN(zephyr_bt_hci_ipc), zephyr_ipc_icbmsg)
40+
#define MAX_IPC_BLOCKS DT_PROP(DT_CHOSEN(zephyr_bt_hci_ipc), rx_blocks)
41+
#else
42+
#error "IPC backends other than rpmsg or icbmsg are not supported."
43+
#endif
44+
3445
LOG_MODULE_DECLARE(ipc_radio, CONFIG_IPC_RADIO_LOG_LEVEL);
3546

3647
#if defined(CONFIG_BT_CTLR_ASSERT_HANDLER) || defined(CONFIG_BT_HCI_VS_FATAL_ERROR)
@@ -41,6 +52,13 @@ static K_SEM_DEFINE(ipc_bound_sem, 0, 1);
4152

4253
static struct ipc_ept hci_ept;
4354

55+
struct ipc_block_item {
56+
const void *ptr;
57+
size_t len;
58+
};
59+
60+
K_MSGQ_DEFINE(ipc_block_queue, sizeof(struct ipc_block_item), MAX_IPC_BLOCKS, sizeof(void *));
61+
4462
static K_FIFO_DEFINE(tx_queue);
4563
static K_FIFO_DEFINE(rx_queue);
4664

@@ -54,115 +72,100 @@ enum hci_h4_type {
5472
#define HCI_FATAL_MSG true
5573
#define HCI_REGULAR_MSG false
5674

57-
static void recv_cmd(const uint8_t *data, size_t len)
75+
static struct net_buf *recv_cmd(const uint8_t *data, size_t len)
5876
{
5977
const struct bt_hci_cmd_hdr *hdr = (const struct bt_hci_cmd_hdr *)data;
6078
struct net_buf *buf;
6179

6280
if (len < sizeof(*hdr)) {
6381
LOG_ERR("Not enough data for command header.");
64-
return;
82+
return NULL;
6583
}
6684

6785
if ((len - sizeof(*hdr)) != hdr->param_len) {
6886
LOG_ERR("Command param_len does not match the remaining data length.");
69-
return;
70-
}
71-
72-
buf = bt_buf_get_tx(BT_BUF_CMD, K_NO_WAIT, hdr, sizeof(*hdr));
73-
if (!buf) {
74-
LOG_ERR("No available command buffers.");
75-
return;
87+
return NULL;
7688
}
7789

90+
buf = bt_buf_get_tx(BT_BUF_CMD, K_FOREVER, hdr, sizeof(*hdr));
7891
data += sizeof(*hdr);
7992
len -= sizeof(*hdr);
8093

8194
if (len > net_buf_tailroom(buf)) {
8295
LOG_ERR("Not enough space in buffer.");
8396
net_buf_unref(buf);
84-
return;
97+
return NULL;
8598
}
8699

87100
LOG_DBG("Received HCI CMD packet (opcode: %#x, len: %u).",
88101
sys_le16_to_cpu(hdr->opcode), hdr->param_len);
89102

90103
net_buf_add_mem(buf, data, len);
91-
k_fifo_put(&tx_queue, buf);
104+
return buf;
92105
}
93106

94-
static void recv_acl(const uint8_t *data, size_t len)
107+
static struct net_buf *recv_acl(const uint8_t *data, size_t len)
95108
{
96109
const struct bt_hci_acl_hdr *hdr = (const struct bt_hci_acl_hdr *)data;
97110
struct net_buf *buf;
98111

99112
if (len < sizeof(*hdr)) {
100113
LOG_ERR("Not enough data for ACL header.");
101-
return;
114+
return NULL;
102115
}
103116

104117
if ((len - sizeof(*hdr)) != sys_le16_to_cpu(hdr->len)) {
105118
LOG_ERR("ACL payload length does not match the remaining data length.");
106-
return;
107-
}
108-
109-
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_NO_WAIT, hdr, sizeof(*hdr));
110-
if (!buf) {
111-
LOG_ERR("No available ACL buffers.");
112-
return;
119+
return NULL;
113120
}
114121

122+
buf = bt_buf_get_tx(BT_BUF_ACL_OUT, K_FOREVER, hdr, sizeof(*hdr));
115123
data += sizeof(*hdr);
116124
len -= sizeof(*hdr);
117125

118126
if (len > net_buf_tailroom(buf)) {
119127
LOG_ERR("Not enough space in buffer.");
120128
net_buf_unref(buf);
121-
return;
129+
return NULL;
122130
}
123131

124132
LOG_DBG("Received HCI ACL packet (handle: %u, len: %u).",
125133
sys_le16_to_cpu(hdr->handle), sys_le16_to_cpu(hdr->len));
126134

127135
net_buf_add_mem(buf, data, len);
128-
k_fifo_put(&tx_queue, buf);
136+
return buf;
129137
}
130138

131-
static void recv_iso(const uint8_t *data, size_t len)
139+
static struct net_buf *recv_iso(const uint8_t *data, size_t len)
132140
{
133141
const struct bt_hci_iso_hdr *hdr = (const struct bt_hci_iso_hdr *)data;
134142
struct net_buf *buf;
135143

136144
if (len < sizeof(*hdr)) {
137145
LOG_ERR("Not enough data for ISO header.");
138-
return;
146+
return NULL;
139147
}
140148

141149
if ((len - sizeof(*hdr)) != bt_iso_hdr_len(sys_le16_to_cpu(hdr->len))) {
142150
LOG_ERR("ISO payload length does not match the remaining data length.");
143-
return;
144-
}
145-
146-
buf = bt_buf_get_tx(BT_BUF_ISO_OUT, K_NO_WAIT, hdr, sizeof(*hdr));
147-
if (!buf) {
148-
LOG_ERR("No available ISO buffers.");
149-
return;
151+
return NULL;
150152
}
151153

154+
buf = bt_buf_get_tx(BT_BUF_ISO_OUT, K_FOREVER, hdr, sizeof(*hdr));
152155
data += sizeof(*hdr);
153156
len -= sizeof(*hdr);
154157

155158
if (len > net_buf_tailroom(buf)) {
156159
LOG_ERR("Not enough space in buffer.");
157160
net_buf_unref(buf);
158-
return;
161+
return NULL;
159162
}
160163

161164
LOG_DBG("Received HCI ISO packet (handle: %u, len: %u).",
162165
sys_le16_to_cpu(hdr->handle), sys_le16_to_cpu(hdr->len));
163166

164167
net_buf_add_mem(buf, data, len);
165-
k_fifo_put(&tx_queue, buf);
168+
return buf;
166169
}
167170

168171
static void send(struct net_buf *buf, bool is_fatal_err)
@@ -226,34 +229,74 @@ static void bound(void *priv)
226229

227230
static void recv(const void *data, size_t len, void *priv)
228231
{
229-
const uint8_t *tmp = (const uint8_t *)data;
230-
enum hci_h4_type type;
232+
struct ipc_block_item block;
233+
int err;
231234

232235
LOG_INF("Received hci message of %u bytes.", len);
233236
LOG_HEXDUMP_DBG(data, len, "HCI data:");
234237

235-
type = (enum hci_h4_type)*tmp++;
236-
len -= sizeof(type);
238+
block.ptr = data;
239+
block.len = len;
237240

238-
switch (type) {
239-
case HCI_H4_CMD:
240-
recv_cmd(tmp, len);
241-
break;
241+
err = ipc_service_hold_rx_buffer(&hci_ept, (void *)data);
242+
if (err) {
243+
LOG_ERR("Failed to hold rx buffer: %d.", err);
244+
}
242245

243-
case HCI_H4_ACL:
244-
recv_acl(tmp, len);
245-
break;
246+
err = k_msgq_put(&ipc_block_queue, &block, K_NO_WAIT);
247+
__ASSERT(err == 0, "Failed to put data into msgq: %d.", err);
248+
}
246249

247-
case HCI_H4_ISO:
248-
recv_iso(tmp, len);
249-
break;
250+
static void queue_thread(void)
251+
{
252+
struct ipc_block_item block;
253+
struct net_buf *buf;
254+
const uint8_t *tmp;
255+
enum hci_h4_type type;
256+
int err;
250257

251-
default:
252-
LOG_ERR("Unknown HCI type %u.", type);
253-
return;
258+
while (1) {
259+
err = k_msgq_get(&ipc_block_queue, &block, K_FOREVER);
260+
__ASSERT(err == 0, "Failed to get data from msgq: %d.", err);
261+
262+
tmp = (const uint8_t *)block.ptr;
263+
type = (enum hci_h4_type)*tmp++;
264+
block.len -= sizeof(type);
265+
266+
switch (type) {
267+
case HCI_H4_CMD:
268+
buf = recv_cmd(tmp, block.len);
269+
break;
270+
271+
case HCI_H4_ACL:
272+
buf = recv_acl(tmp, block.len);
273+
break;
274+
275+
case HCI_H4_ISO:
276+
buf = recv_iso(tmp, block.len);
277+
break;
278+
279+
default:
280+
LOG_ERR("Unknown HCI type %u.", type);
281+
buf = NULL;
282+
break;
283+
}
284+
285+
err = ipc_service_release_rx_buffer(&hci_ept, (void *)block.ptr);
286+
if (err) {
287+
LOG_ERR("Failed to release rx buffer: %d.", err);
288+
}
289+
290+
if (buf) {
291+
k_fifo_put(&tx_queue, buf);
292+
}
254293
}
255294
}
256295

296+
K_THREAD_DEFINE(queue_thread_id, CONFIG_QUEUE_THREAD_STACK_SIZE, queue_thread,
297+
NULL, NULL, NULL,
298+
CONFIG_QUEUE_THREAD_PRIO, 0, 0);
299+
257300
static void tx_thread(void)
258301
{
259302
struct net_buf *buf;

0 commit comments

Comments
 (0)