1 /*
2 * Copyright (c) 2020 Demant
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <zephyr.h>
8 #include <soc.h>
9
10 #include "hal/cpu.h"
11 #include "hal/ccm.h"
12
13 #include "util/memq.h"
14 #include "util/mem.h"
15 #include "util/mfifo.h"
16
17 #include "pdu.h"
18
19 #include "lll.h"
20 #include "lll_conn.h" /* for `struct lll_tx` */
21
22 #define BT_DBG_ENABLED IS_ENABLED(CONFIG_BT_DEBUG_HCI_DRIVER)
23 #define LOG_MODULE_NAME bt_ctlr_ull_iso
24 #include "common/log.h"
25 #include "hal/debug.h"
26
27 #include "lll_conn_iso.h"
28 #include "ull_conn_iso_types.h"
29 #include "isoal.h"
30 #include "ull_iso_types.h"
31 #include "ull_conn_internal.h"
32 #include "ull_conn_iso_internal.h"
33
34 #if defined(CONFIG_BT_CTLR_CONN_ISO_STREAMS)
35 /* Allocate data path pools for RX/TX directions for each stream */
36 static struct ll_iso_datapath datapath_pool[2*CONFIG_BT_CTLR_CONN_ISO_STREAMS];
37 #endif
38 static void *datapath_free;
39
40 static int init_reset(void);
41
42 #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
43 static MFIFO_DEFINE(iso_tx, sizeof(struct lll_tx),
44 CONFIG_BT_CTLR_ISO_TX_BUFFERS);
45
46 static struct {
47 void *free;
48 uint8_t pool[CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE *
49 CONFIG_BT_CTLR_ISO_TX_BUFFERS];
50 } mem_iso_tx;
51 #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
52
53 /* must be implemented by vendor */
ll_data_path_configured(uint8_t data_path_dir,uint8_t data_path_id)54 __weak bool ll_data_path_configured(uint8_t data_path_dir,
55 uint8_t data_path_id)
56 {
57 ARG_UNUSED(data_path_dir);
58 ARG_UNUSED(data_path_id);
59
60 return false;
61 }
62
63 /* Contains vendor specific argument, function to be implemented by vendors */
ll_configure_data_path(uint8_t data_path_dir,uint8_t data_path_id,uint8_t vs_config_len,uint8_t * vs_config)64 __weak uint8_t ll_configure_data_path(uint8_t data_path_dir,
65 uint8_t data_path_id,
66 uint8_t vs_config_len,
67 uint8_t *vs_config)
68 {
69 ARG_UNUSED(data_path_dir);
70 ARG_UNUSED(data_path_id);
71 ARG_UNUSED(vs_config_len);
72 ARG_UNUSED(vs_config);
73
74 return BT_HCI_ERR_CMD_DISALLOWED;
75 }
76
ll_read_iso_tx_sync(uint16_t handle,uint16_t * seq,uint32_t * timestamp,uint32_t * offset)77 uint8_t ll_read_iso_tx_sync(uint16_t handle, uint16_t *seq,
78 uint32_t *timestamp, uint32_t *offset)
79 {
80 ARG_UNUSED(handle);
81 ARG_UNUSED(seq);
82 ARG_UNUSED(timestamp);
83 ARG_UNUSED(offset);
84
85 return BT_HCI_ERR_CMD_DISALLOWED;
86 }
87
path_is_vendor_specific(uint8_t path_id)88 static inline bool path_is_vendor_specific(uint8_t path_id)
89 {
90 return (path_id >= BT_HCI_DATAPATH_ID_VS &&
91 path_id <= BT_HCI_DATAPATH_ID_VS_END);
92 }
93
ll_setup_iso_path(uint16_t handle,uint8_t path_dir,uint8_t path_id,uint8_t coding_format,uint16_t company_id,uint16_t vs_codec_id,uint32_t controller_delay,uint8_t codec_config_len,uint8_t * codec_config)94 uint8_t ll_setup_iso_path(uint16_t handle, uint8_t path_dir, uint8_t path_id,
95 uint8_t coding_format, uint16_t company_id,
96 uint16_t vs_codec_id, uint32_t controller_delay,
97 uint8_t codec_config_len, uint8_t *codec_config)
98 {
99 ARG_UNUSED(controller_delay);
100 ARG_UNUSED(codec_config_len);
101 ARG_UNUSED(codec_config);
102
103 if (path_id == BT_HCI_DATAPATH_ID_DISABLED) {
104 return 0;
105 }
106
107 if (path_dir > BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
108 return BT_HCI_ERR_CMD_DISALLOWED;
109 }
110
111 /* Todo: If the Host attempts to set a data path with a Connection Handle
112 * that does not exist or that is not for a CIS or a BIS, the Controller
113 * shall return the error code Unknown Connection Identifier (0x02)
114 */
115 #if defined(CONFIG_BT_CTLR_CONN_ISO)
116 isoal_sink_handle_t sink_hdl;
117 isoal_status_t err = 0;
118
119 struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get(handle);
120 struct ll_conn_iso_group *cig;
121
122 cig = cis->group;
123
124 if ((path_dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR &&
125 cis->datapath_in) ||
126 (path_dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST &&
127 cis->datapath_out)) {
128 /* Data path has been set up, can only do setup once */
129 return BT_HCI_ERR_CMD_DISALLOWED;
130 }
131 #endif
132 if (path_is_vendor_specific(path_id) &&
133 !ll_data_path_configured(path_dir, path_id)) {
134 /* Data path must be configured prior to setup */
135 return BT_HCI_ERR_CMD_DISALLOWED;
136 }
137
138 /* If Codec_Configuration_Length non-zero and Codec_ID set to
139 * transparent air mode, the Controller shall return the error code
140 * Invalid HCI Command Parameters (0x12).
141 */
142 if (codec_config_len && vs_codec_id == BT_HCI_CODING_FORMAT_TRANSPARENT) {
143 return BT_HCI_ERR_INVALID_PARAM;
144 }
145
146 /* Allocate and configure datapath */
147 struct ll_iso_datapath *dp = mem_acquire(&datapath_free);
148
149 dp->path_dir = path_dir;
150 dp->path_id = path_id;
151 dp->coding_format = coding_format;
152 dp->company_id = company_id;
153
154 /* TODO dp->sync_delay = controller_delay; ?*/
155
156 #if defined(CONFIG_BT_CTLR_CONN_ISO)
157 uint32_t sdu_interval;
158 uint8_t burst_number;
159
160 if (path_dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) {
161 burst_number = cis->lll.tx.burst_number;
162 if (cig->lll.role) {
163 /* peripheral */
164 sdu_interval = cig->p_sdu_interval;
165 } else {
166 /* central */
167 sdu_interval = cig->c_sdu_interval;
168 }
169 cis->datapath_in = dp;
170 } else {
171 burst_number = cis->lll.rx.burst_number;
172 if (cig->lll.role) {
173 /* peripheral */
174 sdu_interval = cig->c_sdu_interval;
175 } else {
176 /* central */
177 sdu_interval = cig->p_sdu_interval;
178 }
179 cis->datapath_out = dp;
180 }
181
182 if (path_id == BT_HCI_DATAPATH_ID_HCI) {
183 /* Not vendor specific, thus alloc and emit functions known */
184 err = isoal_sink_create(&sink_hdl, handle, burst_number, sdu_interval,
185 cig->iso_interval, sink_sdu_alloc_hci,
186 sink_sdu_emit_hci, sink_sdu_write_hci);
187 } else {
188 /* TBD call vendor specific function to set up ISO path */
189 }
190
191 if (!err) {
192 dp->sink_hdl = sink_hdl;
193 isoal_sink_enable(sink_hdl);
194 } else {
195 return BT_HCI_ERR_CMD_DISALLOWED;
196 }
197 #endif
198
199 return 0;
200 }
201
ll_remove_iso_path(uint16_t handle,uint8_t path_dir)202 uint8_t ll_remove_iso_path(uint16_t handle, uint8_t path_dir)
203 {
204 struct ll_conn_iso_stream *cis = ll_conn_iso_stream_get(handle);
205 /* TBD: If the Host issues this command with a Connection_Handle that does not exist
206 * or is not for a CIS or a BIS, the Controller shall return the error code Unknown
207 * Connection Identifier (0x02).
208 */
209 struct ll_iso_datapath *dp;
210
211 if (path_dir == BT_HCI_DATAPATH_DIR_HOST_TO_CTLR) {
212 dp = cis->datapath_in;
213 if (dp) {
214 cis->datapath_in = NULL;
215 mem_release(dp, &datapath_free);
216 }
217 } else if (path_dir == BT_HCI_DATAPATH_DIR_CTLR_TO_HOST) {
218 dp = cis->datapath_out;
219 if (dp) {
220 cis->datapath_out = NULL;
221 mem_release(dp, &datapath_free);
222 }
223 } else {
224 /* Reserved for future use */
225 return BT_HCI_ERR_CMD_DISALLOWED;
226 }
227
228 if (!dp) {
229 /* Datapath was not previously set up */
230 return BT_HCI_ERR_CMD_DISALLOWED;
231
232 }
233
234 return 0;
235 }
236
ll_iso_receive_test(uint16_t handle,uint8_t payload_type)237 uint8_t ll_iso_receive_test(uint16_t handle, uint8_t payload_type)
238 {
239 ARG_UNUSED(handle);
240 ARG_UNUSED(payload_type);
241
242 return BT_HCI_ERR_CMD_DISALLOWED;
243 }
244
ll_iso_transmit_test(uint16_t handle,uint8_t payload_type)245 uint8_t ll_iso_transmit_test(uint16_t handle, uint8_t payload_type)
246 {
247 ARG_UNUSED(handle);
248 ARG_UNUSED(payload_type);
249
250 return BT_HCI_ERR_CMD_DISALLOWED;
251 }
252
ll_iso_test_end(uint16_t handle,uint32_t * received_cnt,uint32_t * missed_cnt,uint32_t * failed_cnt)253 uint8_t ll_iso_test_end(uint16_t handle, uint32_t *received_cnt,
254 uint32_t *missed_cnt, uint32_t *failed_cnt)
255 {
256 ARG_UNUSED(handle);
257 ARG_UNUSED(received_cnt);
258 ARG_UNUSED(missed_cnt);
259 ARG_UNUSED(failed_cnt);
260
261 return BT_HCI_ERR_CMD_DISALLOWED;
262 }
263
ll_iso_read_test_counters(uint16_t handle,uint32_t * received_cnt,uint32_t * missed_cnt,uint32_t * failed_cnt)264 uint8_t ll_iso_read_test_counters(uint16_t handle, uint32_t *received_cnt,
265 uint32_t *missed_cnt,
266 uint32_t *failed_cnt)
267 {
268 ARG_UNUSED(handle);
269 ARG_UNUSED(received_cnt);
270 ARG_UNUSED(missed_cnt);
271 ARG_UNUSED(failed_cnt);
272
273 return BT_HCI_ERR_CMD_DISALLOWED;
274 }
275
ll_read_iso_link_quality(uint16_t handle,uint32_t * tx_unacked_packets,uint32_t * tx_flushed_packets,uint32_t * tx_last_subevent_packets,uint32_t * retransmitted_packets,uint32_t * crc_error_packets,uint32_t * rx_unreceived_packets,uint32_t * duplicate_packets)276 uint8_t ll_read_iso_link_quality(uint16_t handle,
277 uint32_t *tx_unacked_packets,
278 uint32_t *tx_flushed_packets,
279 uint32_t *tx_last_subevent_packets,
280 uint32_t *retransmitted_packets,
281 uint32_t *crc_error_packets,
282 uint32_t *rx_unreceived_packets,
283 uint32_t *duplicate_packets)
284 {
285 ARG_UNUSED(handle);
286 ARG_UNUSED(tx_unacked_packets);
287 ARG_UNUSED(tx_flushed_packets);
288 ARG_UNUSED(tx_last_subevent_packets);
289 ARG_UNUSED(retransmitted_packets);
290 ARG_UNUSED(crc_error_packets);
291 ARG_UNUSED(rx_unreceived_packets);
292 ARG_UNUSED(duplicate_packets);
293
294 return BT_HCI_ERR_CMD_DISALLOWED;
295 }
296
ull_iso_init(void)297 int ull_iso_init(void)
298 {
299 int err;
300
301 err = init_reset();
302 if (err) {
303 return err;
304 }
305
306 return 0;
307 }
308
ull_iso_reset(void)309 int ull_iso_reset(void)
310 {
311 int err;
312
313 #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
314 /* Re-initialize the Tx mfifo */
315 MFIFO_INIT(iso_tx);
316 #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
317
318 err = init_reset();
319 if (err) {
320 return err;
321 }
322
323 return 0;
324 }
325
326 #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
ll_iso_tx_mem_acquire(void)327 void *ll_iso_tx_mem_acquire(void)
328 {
329 return mem_acquire(&mem_iso_tx.free);
330 }
331
ll_iso_tx_mem_release(void * tx)332 void ll_iso_tx_mem_release(void *tx)
333 {
334 mem_release(tx, &mem_iso_tx.free);
335 }
336
ll_iso_tx_mem_enqueue(uint16_t handle,void * tx)337 int ll_iso_tx_mem_enqueue(uint16_t handle, void *tx)
338 {
339 struct lll_tx *lll_tx;
340 uint8_t idx;
341
342 idx = MFIFO_ENQUEUE_GET(iso_tx, (void **) &lll_tx);
343 if (!lll_tx) {
344 return -ENOBUFS;
345 }
346
347 lll_tx->handle = handle;
348 lll_tx->node = tx;
349
350 MFIFO_ENQUEUE(iso_tx, idx);
351
352 return 0;
353 }
354 #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
355
init_reset(void)356 static int init_reset(void)
357 {
358 #if defined(CONFIG_BT_CTLR_ADV_ISO) || defined(CONFIG_BT_CTLR_CONN_ISO)
359 /* Initialize tx pool. */
360 mem_init(mem_iso_tx.pool, CONFIG_BT_CTLR_ISO_TX_BUFFER_SIZE,
361 CONFIG_BT_CTLR_ISO_TX_BUFFERS, &mem_iso_tx.free);
362 #endif /* CONFIG_BT_CTLR_ADV_ISO || CONFIG_BT_CTLR_CONN_ISO */
363
364 #if defined(CONFIG_BT_CTLR_CONN_ISO_STREAMS)
365 /* Initialize ISO Datapath pool */
366 mem_init(datapath_pool, sizeof(struct ll_iso_datapath),
367 sizeof(datapath_pool) / sizeof(struct ll_iso_datapath), &datapath_free);
368 #endif
369
370 return 0;
371 }
372