1 /*
2 * Copyright (c) 2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <stdint.h>
8
9 #include <soc.h>
10
11 #include <zephyr/sys/byteorder.h>
12
13 #include "hal/cpu.h"
14 #include "hal/ccm.h"
15 #include "hal/radio.h"
16 #include "hal/ticker.h"
17 #include "hal/radio_df.h"
18
19 #include "util/util.h"
20 #include "util/mem.h"
21 #include "util/memq.h"
22 #include "util/dbuf.h"
23
24 #include "pdu_df.h"
25 #include "pdu_vendor.h"
26 #include "pdu.h"
27
28 #include "lll.h"
29 #include "lll_vendor.h"
30 #include "lll_clock.h"
31 #include "lll_chan.h"
32 #include "lll_adv_types.h"
33 #include "lll_adv.h"
34 #include "lll_adv_pdu.h"
35 #include "lll_adv_sync.h"
36 #include "lll_adv_iso.h"
37 #include "lll_df_types.h"
38
39 #include "lll_internal.h"
40 #include "lll_adv_internal.h"
41 #include "lll_tim_internal.h"
42 #include "lll_prof_internal.h"
43 #include "lll_df_internal.h"
44
45 #include "hal/debug.h"
46
47 static int init_reset(void);
48 static int prepare_cb(struct lll_prepare_param *p);
49 static void abort_cb(struct lll_prepare_param *prepare_param, void *param);
50 static void isr_done(void *param);
51
52 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
53 static void isr_tx(void *param);
54 static int aux_ptr_get(struct pdu_adv *pdu, struct pdu_adv_aux_ptr **aux_ptr);
55 static void chain_pdu_aux_ptr_chan_idx_set(struct lll_adv_sync *lll);
56 static void aux_ptr_chan_idx_set(struct lll_adv_sync *lll, struct pdu_adv *pdu);
57 static void switch_radio_complete_and_b2b_tx(const struct lll_adv_sync *lll, uint8_t phy_s);
58 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
59
lll_adv_sync_init(void)60 int lll_adv_sync_init(void)
61 {
62 int err;
63
64 err = init_reset();
65 if (err) {
66 return err;
67 }
68
69 return 0;
70 }
71
lll_adv_sync_reset(void)72 int lll_adv_sync_reset(void)
73 {
74 int err;
75
76 err = init_reset();
77 if (err) {
78 return err;
79 }
80
81 return 0;
82 }
83
lll_adv_sync_prepare(void * param)84 void lll_adv_sync_prepare(void *param)
85 {
86 int err;
87
88 err = lll_hfclock_on();
89 LL_ASSERT(err >= 0);
90
91 /* Invoke common pipeline handling of prepare */
92 err = lll_prepare(lll_is_abort_cb, abort_cb, prepare_cb, 0, param);
93 LL_ASSERT(!err || err == -EINPROGRESS);
94 }
95
init_reset(void)96 static int init_reset(void)
97 {
98 return 0;
99 }
100
is_instant_or_past(uint16_t event_counter,uint16_t instant)101 static bool is_instant_or_past(uint16_t event_counter, uint16_t instant)
102 {
103 uint16_t instant_latency;
104
105 instant_latency = (event_counter - instant) &
106 EVENT_INSTANT_MAX;
107
108 return instant_latency <= EVENT_INSTANT_LATENCY_MAX;
109 }
110
prepare_cb(struct lll_prepare_param * p)111 static int prepare_cb(struct lll_prepare_param *p)
112 {
113 struct lll_adv_sync *lll;
114 uint32_t ticks_at_event;
115 uint32_t ticks_at_start;
116 uint8_t data_chan_count;
117 uint8_t *data_chan_map;
118 uint16_t event_counter;
119 uint8_t data_chan_use;
120 struct pdu_adv *pdu;
121 struct ull_hdr *ull;
122 uint32_t cte_len_us;
123 uint32_t remainder;
124 uint32_t start_us;
125 uint8_t phy_s;
126 uint32_t ret;
127 uint8_t upd;
128
129 DEBUG_RADIO_START_A(1);
130
131 lll = p->param;
132
133 /* Calculate the current event latency */
134 lll->latency_event = lll->latency_prepare + p->lazy;
135
136 /* Calculate the current event counter value */
137 event_counter = lll->event_counter + lll->latency_event;
138
139 /* Update event counter to next value */
140 lll->event_counter = (event_counter + 1);
141
142 /* Reset accumulated latencies */
143 lll->latency_prepare = 0;
144
145 /* Process channel map update, if any */
146 if ((lll->chm_first != lll->chm_last) &&
147 is_instant_or_past(event_counter, lll->chm_instant)) {
148 /* At or past the instant, use channelMapNew */
149 lll->chm_first = lll->chm_last;
150 }
151
152 /* Calculate the radio channel to use */
153 data_chan_map = lll->chm[lll->chm_first].data_chan_map;
154 data_chan_count = lll->chm[lll->chm_first].data_chan_count;
155 data_chan_use = lll_chan_sel_2(event_counter, lll->data_chan_id,
156 data_chan_map, data_chan_count);
157
158 /* Start setting up of Radio h/w */
159 radio_reset();
160 #if defined(CONFIG_BT_CTLR_TX_PWR_DYNAMIC_CONTROL)
161 radio_tx_power_set(lll->adv->tx_pwr_lvl);
162 #else
163 radio_tx_power_set(RADIO_TXP_DEFAULT);
164 #endif
165
166 phy_s = lll->adv->phy_s;
167
168 /* TODO: if coded we use S8? */
169 radio_phy_set(phy_s, lll->adv->phy_flags);
170 radio_pkt_configure(RADIO_PKT_CONF_LENGTH_8BIT, PDU_AC_PAYLOAD_SIZE_MAX,
171 RADIO_PKT_CONF_PHY(phy_s));
172 radio_aa_set(lll->access_addr);
173 radio_crc_configure(PDU_CRC_POLYNOMIAL,
174 sys_get_le24(lll->crc_init));
175 lll_chan_set(data_chan_use);
176
177 upd = 0U;
178 pdu = lll_adv_sync_data_latest_get(lll, NULL, &upd);
179 LL_ASSERT(pdu);
180
181 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
182 lll_df_cte_tx_enable(lll, pdu, &cte_len_us);
183 #else
184 cte_len_us = 0U;
185 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX) */
186
187 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
188 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
189 /* Set the last used auxiliary PDU for transmission */
190 lll->last_pdu = pdu;
191
192 /* Populate chan idx for AUX_ADV_IND PDU */
193 aux_ptr_chan_idx_set(lll, pdu);
194
195 radio_isr_set(isr_tx, lll);
196 radio_tmr_tifs_set(EVENT_SYNC_B2B_MAFS_US);
197 switch_radio_complete_and_b2b_tx(lll, phy_s);
198 } else {
199 /* No chain PDU */
200 lll->last_pdu = NULL;
201
202 #else /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
203 {
204 #endif /* !CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
205
206 radio_isr_set(isr_done, lll);
207 radio_switch_complete_and_disable();
208 }
209
210 #if defined(CONFIG_BT_CTLR_ADV_ISO) && defined(CONFIG_BT_TICKER_EXT_EXPIRE_INFO)
211 if (lll->iso) {
212 ull_adv_iso_lll_biginfo_fill(pdu, lll);
213 }
214 #endif /* CONFIG_BT_CTLR_ADV_ISO && CONFIG_BT_TICKER_EXT_EXPIRE_INFO */
215
216 /* Set the Radio Tx Packet */
217 radio_pkt_tx_set(pdu);
218
219 ticks_at_event = p->ticks_at_expire;
220 ull = HDR_LLL2ULL(lll);
221 ticks_at_event += lll_event_offset_get(ull);
222
223 ticks_at_start = ticks_at_event;
224 ticks_at_start += HAL_TICKER_US_TO_TICKS(EVENT_OVERHEAD_START_US);
225
226 remainder = p->remainder;
227 start_us = radio_tmr_start(1, ticks_at_start, remainder);
228
229 #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
230 defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
231 /* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating
232 * next PDU timestamp.
233 *
234 * In Periodic Advertising without chaining there is no need for LLL to
235 * get the end time from radio, hence there is no call to
236 * radio_tmr_end_capture() to capture the radio end time.
237 *
238 * With chaining the sw_switch used PPI/DPPI for back to back Tx, no
239 * radio end time capture is needed there either.
240 *
241 * For PA LNA (and ISR profiling), the radio end time is required to
242 * setup the GPIOTE using radio_gpio_pa_lna_enable which needs call to
243 * radio_tmr_tifs_base_get(), both PA/LNA and ISR profiling call
244 * radio_tmr_end_get().
245 */
246 radio_tmr_end_capture();
247 #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
248
249 #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
250 radio_gpio_pa_setup();
251
252 radio_gpio_pa_lna_enable(start_us + radio_tx_ready_delay_get(phy_s, 1) -
253 HAL_RADIO_GPIO_PA_OFFSET);
254 #else /* !HAL_RADIO_GPIO_HAVE_PA_PIN */
255 ARG_UNUSED(start_us);
256 #endif /* !HAL_RADIO_GPIO_HAVE_PA_PIN */
257
258 #if defined(CONFIG_BT_CTLR_XTAL_ADVANCED) && \
259 (EVENT_OVERHEAD_PREEMPT_US <= EVENT_OVERHEAD_PREEMPT_MIN_US)
260 uint32_t overhead;
261
262 overhead = lll_preempt_calc(ull, (TICKER_ID_ADV_SYNC_BASE +
263 ull_adv_sync_lll_handle_get(lll)), ticks_at_event);
264 /* check if preempt to start has changed */
265 if (overhead) {
266 LL_ASSERT_OVERHEAD(overhead);
267
268 radio_isr_set(lll_isr_abort, lll);
269 radio_disable();
270
271 return -ECANCELED;
272 }
273 #endif /* CONFIG_BT_CTLR_XTAL_ADVANCED */
274
275 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
276 /* Populate chan idx for AUX_CHAIN_IND PDU */
277 chain_pdu_aux_ptr_chan_idx_set(lll);
278 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
279
280 ret = lll_prepare_done(lll);
281 LL_ASSERT(!ret);
282
283 DEBUG_RADIO_START_A(1);
284
285 return 0;
286 }
287
288 static void abort_cb(struct lll_prepare_param *prepare_param, void *param)
289 {
290 struct lll_adv_sync *lll;
291 int err;
292
293 /* NOTE: This is not a prepare being cancelled */
294 if (!prepare_param) {
295 /* Perform event abort here.
296 * After event has been cleanly aborted, clean up resources
297 * and dispatch event done.
298 */
299 radio_isr_set(isr_done, param);
300 radio_disable();
301 return;
302 }
303
304 /* NOTE: Else clean the top half preparations of the aborted event
305 * currently in preparation pipeline.
306 */
307 err = lll_hfclock_off();
308 LL_ASSERT(err >= 0);
309
310 /* Accumulate the latency as event is aborted while being in pipeline */
311 lll = prepare_param->param;
312 lll->latency_prepare += (prepare_param->lazy + 1);
313
314 lll_done(param);
315 }
316
317 static void isr_done(void *param)
318 {
319 struct lll_adv_sync *lll = param;
320
321 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
322 if (lll->cte_started) {
323 lll_df_cte_tx_disable();
324 }
325 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
326
327 /* Signal thread mode to remove Channel Map Update Indication in the
328 * ACAD.
329 */
330 if ((lll->chm_first != lll->chm_last) &&
331 is_instant_or_past(lll->event_counter, lll->chm_instant)) {
332 struct node_rx_pdu *rx;
333
334 /* Allocate, prepare and dispatch Channel Map Update
335 * complete message towards ULL, then subsequently to
336 * the thread context.
337 */
338 rx = ull_pdu_rx_alloc();
339 LL_ASSERT(rx);
340
341 rx->hdr.type = NODE_RX_TYPE_SYNC_CHM_COMPLETE;
342 rx->rx_ftr.param = lll;
343
344 ull_rx_put_sched(rx->hdr.link, rx);
345 }
346
347 lll_isr_done(lll);
348 }
349
350 #if defined(CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK)
351 static void isr_tx(void *param)
352 {
353 struct pdu_adv_aux_ptr *aux_ptr;
354 struct lll_adv_sync *lll_sync;
355 struct pdu_adv *pdu;
356 struct lll_adv *lll;
357 uint32_t cte_len_us;
358 int err;
359
360 if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
361 lll_prof_latency_capture();
362 }
363
364 /* Clear radio tx status and events */
365 lll_isr_tx_status_reset();
366
367 /* Get reference to sync and primary advertising LLL contexts */
368 lll_sync = param;
369 lll = lll_sync->adv;
370
371 /* Get reference to aux pointer structure */
372 err = aux_ptr_get(lll_sync->last_pdu, &aux_ptr);
373 LL_ASSERT(!err && aux_ptr);
374
375 /* Use channel idx that was in aux_ptr */
376 lll_chan_set(aux_ptr->chan_idx);
377
378 /* Get reference to the auxiliary chain PDU */
379 pdu = lll_adv_pdu_linked_next_get(lll_sync->last_pdu);
380 LL_ASSERT(pdu);
381
382 /* Set the last used auxiliary PDU for transmission */
383 lll_sync->last_pdu = pdu;
384
385 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
386 lll_df_cte_tx_enable(lll_sync, pdu, &cte_len_us);
387 #else
388 cte_len_us = 0;
389 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
390
391 /* setup tIFS switching */
392 if (pdu->adv_ext_ind.ext_hdr_len && pdu->adv_ext_ind.ext_hdr.aux_ptr) {
393 radio_tmr_tifs_set(EVENT_SYNC_B2B_MAFS_US);
394 radio_isr_set(isr_tx, lll_sync);
395 switch_radio_complete_and_b2b_tx(lll_sync, lll->phy_s);
396 } else {
397 radio_isr_set(isr_done, lll_sync);
398 radio_switch_complete_and_b2b_tx_disable();
399 }
400
401 radio_pkt_tx_set(pdu);
402
403 /* assert if radio packet ptr is not set and radio started rx */
404 LL_ASSERT(!radio_is_ready());
405
406 if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
407 lll_prof_cputime_capture();
408 }
409
410 #if defined(CONFIG_BT_CTLR_PROFILE_ISR) || \
411 defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
412 /* capture end of AUX_SYNC_IND/AUX_CHAIN_IND PDU, used for calculating
413 * next PDU timestamp.
414 */
415 radio_tmr_end_capture();
416 #endif /* CONFIG_BT_CTLR_PROFILE_ISR */
417
418 #if defined(HAL_RADIO_GPIO_HAVE_PA_PIN)
419 if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
420 /* PA/LNA enable is overwriting packet end used in ISR
421 * profiling, hence back it up for later use.
422 */
423 lll_prof_radio_end_backup();
424 }
425
426 radio_gpio_pa_setup();
427 radio_gpio_pa_lna_enable(radio_tmr_tifs_base_get() +
428 EVENT_SYNC_B2B_MAFS_US -
429 (EVENT_CLOCK_JITTER_US << 1) + cte_len_us -
430 radio_tx_chain_delay_get(lll->phy_s, 0) -
431 HAL_RADIO_GPIO_PA_OFFSET);
432 #endif /* HAL_RADIO_GPIO_HAVE_PA_PIN */
433
434 /* Populate chan idx for AUX_CHAIN_IND PDU */
435 chain_pdu_aux_ptr_chan_idx_set(lll_sync);
436
437 if (IS_ENABLED(CONFIG_BT_CTLR_PROFILE_ISR)) {
438 lll_prof_send();
439 }
440 }
441
442 static int aux_ptr_get(struct pdu_adv *pdu, struct pdu_adv_aux_ptr **aux_ptr)
443 {
444 struct pdu_adv_com_ext_adv *com_hdr;
445 struct pdu_adv_ext_hdr *hdr;
446 uint8_t *dptr;
447
448 /* Get reference to common extended header */
449 com_hdr = (void *)&pdu->adv_ext_ind;
450 if (com_hdr->ext_hdr_len == 0U) {
451 return -EINVAL;
452 }
453
454 /* Get reference to extended header flags and header fields */
455 hdr = (void *)com_hdr->ext_hdr_adv_data;
456 dptr = hdr->data;
457
458 /* No traverse through of AdvA and TargetA.
459 * These are RFU for periodic advertising, is not set by local device.
460 */
461
462 /* traverse through CTEInfo flag, if present */
463 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
464 if (hdr->cte_info) {
465 dptr += sizeof(struct pdu_cte_info);
466 }
467 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
468
469 /* traverse through adi, if present */
470 if (hdr->adi) {
471 dptr += sizeof(struct pdu_adv_adi);
472 }
473
474 /* check for aux_ptr flag */
475 if (hdr->aux_ptr) {
476 /* Return reference to aux pointer structure */
477 *aux_ptr = (void *)dptr;
478 } else {
479 *aux_ptr = NULL;
480 }
481
482 return 0;
483 }
484
485 static void chain_pdu_aux_ptr_chan_idx_set(struct lll_adv_sync *lll)
486 {
487 struct pdu_adv *chain_pdu;
488
489 /* No chain PDU */
490 if (!lll->last_pdu) {
491 return;
492 }
493
494 /* Get reference to the auxiliary chain PDU */
495 chain_pdu = lll_adv_pdu_linked_next_get(lll->last_pdu);
496
497 /* Check if there is further chain PDU */
498 if (chain_pdu && chain_pdu->adv_ext_ind.ext_hdr_len &&
499 chain_pdu->adv_ext_ind.ext_hdr.aux_ptr) {
500 aux_ptr_chan_idx_set(lll, chain_pdu);
501 }
502 }
503
504 static void aux_ptr_chan_idx_set(struct lll_adv_sync *lll, struct pdu_adv *pdu)
505 {
506 struct pdu_adv_aux_ptr *aux_ptr;
507 uint8_t chan_idx;
508 int err;
509
510 /* Get reference to aux pointer structure */
511 err = aux_ptr_get(pdu, &aux_ptr);
512 LL_ASSERT(!err && aux_ptr);
513
514 /* Calculate a new channel index */
515 chan_idx = lll_chan_sel_2(lll->data_chan_counter, lll->data_chan_id,
516 lll->chm[lll->chm_first].data_chan_map,
517 lll->chm[lll->chm_first].data_chan_count);
518
519 /* Increment counter, for next channel index calculation */
520 lll->data_chan_counter++;
521
522 /* Set the channel index for the auxiliary chain PDU */
523 aux_ptr->chan_idx = chan_idx;
524 }
525 static void switch_radio_complete_and_b2b_tx(const struct lll_adv_sync *lll,
526 uint8_t phy_s)
527 {
528 #if defined(CONFIG_BT_CTLR_DF_ADV_CTE_TX)
529 if (lll->cte_started) {
530 radio_switch_complete_and_phy_end_b2b_tx(phy_s, 0, phy_s, 0);
531 } else
532 #endif /* CONFIG_BT_CTLR_DF_ADV_CTE_TX */
533 {
534 radio_switch_complete_and_b2b_tx(phy_s, 0, phy_s, 0);
535 }
536 }
537 #endif /* CONFIG_BT_CTLR_ADV_SYNC_PDU_BACK2BACK */
538