@@ -134,6 +134,8 @@ static struct {
134134
135135 uint8_t volatile ticker_id_prepare ;
136136 uint8_t volatile ticker_id_event ;
137+ uint8_t volatile ticker_id_stop ;
138+
137139 enum role volatile role ;
138140 enum state state ;
139141
@@ -214,6 +216,10 @@ static uint16_t const gc_lookup_ppm[] = { 500, 250, 150, 100, 75, 50, 30, 20 };
214216
215217static void common_init (void );
216218static void ticker_success_assert (uint32_t status , void * params );
219+ static void ticker_stop_adv_assert (uint32_t status , void * params );
220+ static void ticker_stop_obs_assert (uint32_t status , void * params );
221+ static void ticker_update_adv_assert (uint32_t status , void * params );
222+ static void ticker_update_slave_assert (uint32_t status , void * params );
217223static void event_inactive (uint32_t ticks_at_expire , uint32_t remainder ,
218224 uint16_t lazy , void * context );
219225static void adv_setup (void );
@@ -694,23 +700,21 @@ static inline uint32_t isr_rx_adv(uint8_t devmatch_ok, uint8_t irkmatch_ok,
694700 ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
695701 RADIO_TICKER_USER_ID_WORKER ,
696702 RADIO_TICKER_ID_ADV ,
697- ticker_success_assert , ( void * ) __LINE__ );
698- LL_ASSERT (( ticker_status == TICKER_STATUS_SUCCESS ) ||
699- (ticker_status == TICKER_STATUS_BUSY ) );
703+ ticker_stop_adv_assert ,
704+ ( void * ) __LINE__ );
705+ ticker_stop_adv_assert (ticker_status , ( void * ) __LINE__ );
700706
701707 /* Stop Direct Adv Stopper */
702708 _pdu_adv = (struct pdu_adv * )& _radio .advertiser .adv_data .data
703709 [_radio .advertiser .adv_data .first ][0 ];
704710 if (_pdu_adv -> type == PDU_ADV_TYPE_DIRECT_IND ) {
705- ticker_status =
706- ticker_stop (
707- RADIO_TICKER_INSTANCE_ID_RADIO ,
708- RADIO_TICKER_USER_ID_WORKER ,
709- RADIO_TICKER_ID_ADV_STOP ,
710- 0 , /* @todo ticker_success_assert */
711- 0 /* @todo (void *) __LINE__*/ );
712- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
713- (ticker_status == TICKER_STATUS_BUSY ));
711+ /* Advertiser stop can expire while here in this ISR.
712+ * Deferred attempt to stop can fail as it would have
713+ * expired, hence ignore failure.
714+ */
715+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
716+ RADIO_TICKER_USER_ID_WORKER ,
717+ RADIO_TICKER_ID_ADV_STOP , NULL , NULL );
714718 }
715719
716720 /* Start Slave */
@@ -901,21 +905,23 @@ static inline uint32_t isr_rx_obs(uint8_t irkmatch_id, uint8_t rssi_ready)
901905 conn -> hdr .ticks_xtal_to_start :
902906 conn -> hdr .ticks_active_to_start ;
903907
904- /* Stop Observer and start Master */
908+ /* Stop Observer */
905909 ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
906910 RADIO_TICKER_USER_ID_WORKER ,
907911 RADIO_TICKER_ID_OBS ,
908- ticker_success_assert ,
912+ ticker_stop_obs_assert ,
909913 (void * )__LINE__ );
910- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
911- (ticker_status == TICKER_STATUS_BUSY ));
912- ticker_status = ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
913- RADIO_TICKER_USER_ID_WORKER ,
914- RADIO_TICKER_ID_OBS_STOP ,
915- 0 , /* @todo ticker_success_assert */
916- 0 /* @todo (void *) __LINE__ */ );
917- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
918- (ticker_status == TICKER_STATUS_BUSY ));
914+ ticker_stop_obs_assert (ticker_status , (void * )__LINE__ );
915+
916+ /* Observer stop can expire while here in this ISR.
917+ * Deferred attempt to stop can fail as it would have
918+ * expired, hence ignore failure.
919+ */
920+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
921+ RADIO_TICKER_USER_ID_WORKER ,
922+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
923+
924+ /* Start master */
919925 ticker_status =
920926 ticker_start (RADIO_TICKER_INSTANCE_ID_RADIO ,
921927 RADIO_TICKER_USER_ID_WORKER ,
@@ -2102,16 +2108,25 @@ static inline uint32_t isr_close_adv(void)
21022108 /** @todo use random 0-10 */
21032109 random_delay = 10 ;
21042110
2111+ /* Call to ticker_update can fail under the race
2112+ * condition where in the Adv role is being stopped but
2113+ * at the same time it is preempted by Adv event that
2114+ * gets into close state. Accept failure when Adv role
2115+ * is being stopped.
2116+ */
21052117 ticker_status =
21062118 ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
21072119 RADIO_TICKER_USER_ID_WORKER ,
21082120 RADIO_TICKER_ID_ADV ,
2109- TICKER_US_TO_TICKS (random_delay * 1000 ),
2121+ TICKER_US_TO_TICKS (random_delay *
2122+ 1000 ),
21102123 0 , 0 , 0 , 0 , 0 ,
2111- ticker_success_assert ,
2124+ ticker_update_adv_assert ,
21122125 (void * )__LINE__ );
21132126 LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2114- (ticker_status == TICKER_STATUS_BUSY ));
2127+ (ticker_status == TICKER_STATUS_BUSY ) ||
2128+ (_radio .ticker_id_stop ==
2129+ RADIO_TICKER_ID_ADV ));
21152130 }
21162131 }
21172132
@@ -2139,20 +2154,16 @@ static inline uint32_t isr_close_obs(void)
21392154
21402155 radio_tmr_end_capture ();
21412156 } else {
2142- uint32_t ticker_status ;
2143-
21442157 radio_filter_disable ();
21452158
21462159 if (_radio .state == STATE_ABORT ) {
2147- ticker_status =
2148- ticker_stop (
2149- RADIO_TICKER_INSTANCE_ID_RADIO ,
2150- RADIO_TICKER_USER_ID_WORKER ,
2151- RADIO_TICKER_ID_OBS_STOP ,
2152- 0 /** @todo ticker_success_assert */ ,
2153- 0 /** @todo (void *) __LINE__ */ );
2154- LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2155- (ticker_status == TICKER_STATUS_BUSY ));
2160+ /* Observer stop can expire while here in this ISR.
2161+ * Deferred attempt to stop can fail as it would have
2162+ * expired, hence ignore failure.
2163+ */
2164+ ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
2165+ RADIO_TICKER_USER_ID_WORKER ,
2166+ RADIO_TICKER_ID_OBS_STOP , NULL , NULL );
21562167 }
21572168 }
21582169
@@ -2423,18 +2434,25 @@ static inline void isr_close_conn(void)
24232434 if ((ticks_drift_plus != 0 ) || (ticks_drift_minus != 0 ) ||
24242435 (lazy != 0 ) || (force != 0 )) {
24252436 uint32_t ticker_status ;
2426-
2437+ uint8_t ticker_id = RADIO_TICKER_ID_FIRST_CONNECTION +
2438+ _radio .conn_curr -> handle ;
2439+
2440+ /* Call to ticker_update can fail under the race
2441+ * condition where in the Slave role is being stopped but
2442+ * at the same time it is preempted by Slave event that
2443+ * gets into close state. Accept failure when Slave role
2444+ * is being stopped.
2445+ */
24272446 ticker_status =
24282447 ticker_update (RADIO_TICKER_INSTANCE_ID_RADIO ,
24292448 RADIO_TICKER_USER_ID_WORKER ,
2430- RADIO_TICKER_ID_FIRST_CONNECTION +
2431- _radio .conn_curr -> handle ,
2449+ ticker_id ,
24322450 ticks_drift_plus , ticks_drift_minus , 0 , 0 ,
2433- lazy , force ,
2434- 0 /** @todo ticker_success_assert */ ,
2435- 0 /** @todo (void *) __LINE__ */ );
2451+ lazy , force , ticker_update_slave_assert ,
2452+ (void * )(uint32_t )ticker_id );
24362453 LL_ASSERT ((ticker_status == TICKER_STATUS_SUCCESS ) ||
2437- (ticker_status == TICKER_STATUS_BUSY ));
2454+ (ticker_status == TICKER_STATUS_BUSY ) ||
2455+ (_radio .ticker_id_stop == ticker_id ));
24382456 }
24392457}
24402458
@@ -2457,6 +2475,20 @@ static inline void isr_radio_state_close(void)
24572475 break ;
24582476
24592477 case ROLE_NONE :
2478+ /* If a role closes graceful while it is being stopped, then
2479+ * Radio ISR will be triggered to process the stop state with
2480+ * no active role at that instance in time.
2481+ * Just reset the state to none. The role has gracefully closed
2482+ * before this ISR run.
2483+ * The above applies to aborting a role event too.
2484+ */
2485+ LL_ASSERT ((_radio .state == STATE_STOP ) ||
2486+ (_radio .state == STATE_ABORT ));
2487+
2488+ _radio .state = STATE_NONE ;
2489+
2490+ return ;
2491+
24602492 default :
24612493 LL_ASSERT (0 );
24622494 break ;
@@ -2569,6 +2601,60 @@ static void ticker_success_assert(uint32_t status, void *params)
25692601 LL_ASSERT (status == TICKER_STATUS_SUCCESS );
25702602}
25712603
2604+ static void ticker_stop_adv_assert (uint32_t status , void * params )
2605+ {
2606+ ARG_UNUSED (params );
2607+
2608+ if (status == TICKER_STATUS_FAILURE ) {
2609+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ) {
2610+ /* ticker_stop failed due to race condition
2611+ * while in role_disable. Let the role_disable
2612+ * be made aware of, so it can return failure
2613+ * (to stop Adv role as it is now transitioned
2614+ * to Slave role).
2615+ */
2616+ _radio .ticker_id_stop = 0 ;
2617+ } else {
2618+ LL_ASSERT (0 );
2619+ }
2620+ }
2621+ }
2622+
2623+ static void ticker_stop_obs_assert (uint32_t status , void * params )
2624+ {
2625+ ARG_UNUSED (params );
2626+
2627+ if (status == TICKER_STATUS_FAILURE ) {
2628+ if (_radio .ticker_id_stop == RADIO_TICKER_ID_OBS ) {
2629+ /* ticker_stop failed due to race condition
2630+ * while in role_disable. Let the role_disable
2631+ * be made aware of, so it can return failure
2632+ * (to stop Obs role as it is now transitioned
2633+ * to Master role).
2634+ */
2635+ _radio .ticker_id_stop = 0 ;
2636+ } else {
2637+ LL_ASSERT (0 );
2638+ }
2639+ }
2640+ }
2641+
2642+ static void ticker_update_adv_assert (uint32_t status , void * params )
2643+ {
2644+ ARG_UNUSED (params );
2645+
2646+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2647+ (_radio .ticker_id_stop == RADIO_TICKER_ID_ADV ));
2648+ }
2649+
2650+ static void ticker_update_slave_assert (uint32_t status , void * params )
2651+ {
2652+ uint8_t ticker_id = (uint32_t )params & 0xFF ;
2653+
2654+ LL_ASSERT ((status == TICKER_STATUS_SUCCESS ) ||
2655+ (_radio .ticker_id_stop == ticker_id ));
2656+ }
2657+
25722658static void work_radio_active (void * params )
25732659{
25742660 static uint8_t s_active ;
@@ -3534,7 +3620,7 @@ static void event_common_prepare(uint32_t ticks_at_expire,
35343620#endif
35353621#undef RADIO_DEFERRED_PREEMPT
35363622
3537- /** Handle change in _ticks_active_to_start */
3623+ /** Handle change in _ticks_active_to_start */
35383624 if (_radio .ticks_active_to_start != _ticks_active_to_start ) {
35393625 uint32_t ticks_to_start_new =
35403626 ((_radio .ticks_active_to_start <
@@ -6585,6 +6671,10 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
65856671 break ;
65866672 }
65876673
6674+ LL_ASSERT (!_radio .ticker_id_stop );
6675+
6676+ _radio .ticker_id_stop = ticker_id_primary ;
6677+
65886678 /* Step 1: Is Primary started? Stop the Primary ticker */
65896679 ticker_status =
65906680 ticker_stop (RADIO_TICKER_INSTANCE_ID_RADIO ,
@@ -6605,7 +6695,7 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
66056695 }
66066696
66076697 if (ticker_status != TICKER_STATUS_SUCCESS ) {
6608- return 1 ;
6698+ goto role_disable_cleanup ;
66096699 }
66106700
66116701 /* Inside our event, gracefully handle XTAL and Radio actives */
@@ -6616,7 +6706,14 @@ static uint32_t role_disable(uint8_t ticker_id_primary,
66166706 ticks_xtal_to_start , ticks_active_to_start );
66176707 }
66186708
6619- return 0 ;
6709+ if (!_radio .ticker_id_stop ) {
6710+ ticker_status = TICKER_STATUS_FAILURE ;
6711+ }
6712+
6713+ role_disable_cleanup :
6714+ _radio .ticker_id_stop = 0 ;
6715+
6716+ return ticker_status ;
66206717}
66216718
66226719uint32_t radio_adv_enable (uint16_t interval , uint8_t chl_map ,
0 commit comments