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