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+
3445LOG_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
4253static 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+
4462static K_FIFO_DEFINE (tx_queue );
4563static 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
168171static void send (struct net_buf * buf , bool is_fatal_err )
@@ -226,34 +229,74 @@ static void bound(void *priv)
226229
227230static 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+
257300static void tx_thread (void )
258301{
259302 struct net_buf * buf ;
0 commit comments