- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

# /space/home/slher/rel/Beken/v6_4_5/macsw/ip/lmac/src/chan/chan.c

Go to the documentation of this file.

    00001
    00026 #include "chan.h"
    00027 #include "mac_frame.h"
    00028 #include "mm.h"
    00029 #include "mm_timer.h"
    00030 #include "mm_bcn.h"
    00031 #include "co_endian.h"
    00032 #include "sta_mgmt.h"
    00033 #include "vif_mgmt.h"
    00034 #include "phy.h"
    00035 #include "dbg.h"
    00036 #include "rd.h"
    00037 #include "ps.h"
    00038 #include "txl_cntrl.h"
    00039 #include "txl_frame.h"
    00040 #include "rxl_hwdesc.h"
    00041 #include "hal_machw.h"
    00042 #include "td.h"
    00043 #include "scan.h"
    00044 #include "tpc.h"
    00045 #if (NX_UMAC_PRESENT)
    00046 #include "me.h"
    00047 #endif //(NX_UMAC_PRESENT)
    00048 #if (NX_MDM_VER >= 20)
    00049 #include "reg_riu.h"
    00050 #endif //(NX_MDM_VER >= 20)
    00051 #include "tdls.h"
    00052 #if (NX_P2P)
    00053 #include "p2p.h"
    00054 #endif //(NX_P2P)
    00055 #if NX_MAC_HE
    00056 #include "txl_he.h"
    00057 #endif
    00058
    00059
    00060 #if (NX_CHNL_CTXT)
    00061
    00062 /*
    00063  * DEFINES
    00064  ****************************************************************************************
    00065  */
    00067 #define CHAN_SWITCH_CNT  4
    00068
    00070 #define CHAN_MIN_PRES_DUR_US (5000)
    00071
    00074 #define CHAN_CONN_LESS_DELAY   (30000)
    00075
    00077 #define CHAN_ROC_SCAN_PENDING_MASK  (CO_BIT(CHAN_ENV_ROC_BIT) | CO_BIT(CHAN_ENV_SCAN_BIT))
    00078
    00080 #define CHAN_P2P_NOA_RESCHEDULE_THRESHOLD 2000
    00081
    00083 #define CHAN_P2P_NOA_RESYNC_THRESHOLD 200
    00084
    00086 struct chan_window
    00087 {
    00089     uint32_t start;
    00091     uint32_t end;
    00092 };
    00093
    00094 /*
    00095  * GLOBAL VARIABLES
    00096  ****************************************************************************************
    00097  */
    00098
    00100 struct chan_env_tag chan_env;
    00101
    00103 struct chan_ctxt_tag chan_ctxt_pool[CHAN_CHAN_CTXT_CNT];
    00104
    00106 struct chan_switch_tag chan_switch_pool[CHAN_SWITCH_CNT];
    00107
    00108 /*
    00109  * PRIVATE FUNCTIONS DECLARATION
    00110  ****************************************************************************************
    00111  */
    00112
    00113 static void chan_switch_start(struct chan_ctxt_tag *ctxt);
    00114 static void chan_switch_channel(void);
    00115
    00116 /*
    00117  * PRIVATE FUNCTIONS DEFINITION
    00118  ****************************************************************************************
    00119  */
    00127 __INLINE void chan_switch_set_timer(struct chan_switch_tag *ch_switch)
    00128 {
    00129     chan_env.tmr_switch.env = ch_switch;
    00130     if (ch_switch)
    00131     {
    00132         if (hal_machw_time_past(ch_switch->time - 20))
    00133             chan_env.tmr_switch.cb(ch_switch);
    00134         else
    00135             mm_timer_set(&chan_env.tmr_switch, ch_switch->time);
    00136     }
    00137 }
    00138
    00144 __INLINE void chan_switch_reset_timer(void)
    00145 {
    00146     mm_timer_clear(&chan_env.tmr_switch);
    00147     chan_env.tmr_switch.env = NULL;
    00148 }
    00149
    00157 __INLINE struct chan_switch_tag *chan_switch_pop(void)
    00158 {
    00159     return (struct chan_switch_tag *)co_list_pop_front(&chan_env.list_switch);
    00160 }
    00161
    00169 __INLINE struct chan_switch_tag *chan_switch_pick(void)
    00170 {
    00171     return (struct chan_switch_tag *)co_list_pick(&chan_env.list_switch);
    00172 }
    00173
    00181 __INLINE struct chan_switch_tag *chan_switch_last(void)
    00182 {
    00183     return (struct chan_switch_tag *)co_list_pick_last(&chan_env.list_switch);
    00184 }
    00185
    00193 __INLINE void chan_switch_push_back(struct chan_switch_tag *ch_switch)
    00194 {
    00195     co_list_push_back(&chan_env.list_switch, &ch_switch->list_hdr);
    00196 }
    00197
    00205 __INLINE bool chan_switch_no_schedule(void)
    00206 {
    00207     return co_list_is_empty(&chan_env.list_switch);
    00208 }
    00209
    00217 __INLINE struct chan_switch_tag *chan_switch_alloc(void)
    00218 {
    00219     struct chan_switch_tag *ch_switch;
    00220     ch_switch = (struct chan_switch_tag *)co_list_pop_front(&chan_env.list_free_switch);
    00221     ASSERT_ERR(ch_switch != NULL);
    00222     return ch_switch;
    00223 }
    00224
    00232 __INLINE void chan_switch_free(struct chan_switch_tag *ch_switch)
    00233 {
    00234     co_list_push_back(&chan_env.list_free_switch, &ch_switch->list_hdr);
    00235 }
    00236
    00244 __INLINE struct chan_tbtt_tag *chan_tbtt_pick(void)
    00245 {
    00246     return (struct chan_tbtt_tag *)co_list_pick(&chan_env.list_tbtt);
    00247 }
    00248
    00257 __INLINE struct chan_tbtt_tag *chan_tbtt_next(struct chan_tbtt_tag *tbtt)
    00258 {
    00259     return (struct chan_tbtt_tag *)tbtt->list_hdr.next;
    00260 }
    00261
    00269 __INLINE void chan_tbtt_remove(struct chan_tbtt_tag * tbtt)
    00270 {
    00271     co_list_extract(&chan_env.list_tbtt, &tbtt->list_hdr);
    00272     tbtt->status &= ~CHAN_TBTT_PROG;
    00273 }
    00274
    00283 __INLINE void chan_tbtt_insert_before(struct chan_tbtt_tag *tbtt,
    00284                                       struct chan_tbtt_tag *tbtt_next)
    00285 {
    00286     co_list_insert_before(&chan_env.list_tbtt, &tbtt_next->list_hdr, &tbtt->list_hdr);
    00287     tbtt->status |= CHAN_TBTT_PROG;
    00288 }
    00289
    00298 static uint32_t chan_vif_tbtt_intv(struct vif_info_tag *vif)
    00299 {
    00300     if (vif->type == VIF_STA)
    00301     {
    00302         return sta_info_tab[vif->u.sta.ap_id].bcn_int;
    00303     }
    00304     #if NX_BCN_AUTONOMOUS_TX
    00305     else if (vif->type == VIF_AP)
    00306     {
    00307         return vif->u.ap.bcn_int << 10;
    00308     }
    00309     #endif
    00310
    00311     TRACE_CHAN(ERR, "TODO: chan_vif_tbtt_intv");
    00312     return 100 * 1024;
    00313 }
    00314
    00325 static uint32_t chan_vif_tbtt_dur(struct vif_info_tag *vif)
    00326 {
    00327     return VIF_MGMT_BCN_TO_DUR;
    00328 }
    00329
    00338 static void chan_upd_ctxt_status(struct chan_ctxt_tag *ctxt, uint8_t status)
    00339 {
    00340     ctxt->status = status;
    00341     TRACE_CHAN(STATUS, "{CTXT-%d} Update status %d", ctxt->idx, status);
    00342 }
    00343
    00351 static struct chan_ctxt_tag *chan_get_first_traf_ctxt(void)
    00352 {
    00353     int idx;
    00354
    00355     for (idx = 0; idx < CHAN_TRAF_CTXT_CNT; idx++)
    00356     {
    00357         if (chan_ctxt_pool[idx].idx != CHAN_CTXT_UNUSED)
    00358             return &chan_ctxt_pool[idx];
    00359     }
    00360
    00361     return NULL;
    00362 }
    00363
    00375 static struct chan_ctxt_tag *chan_get_next_traf_ctxt(struct chan_ctxt_tag *ctxt)
    00376 {
    00377     int nb = CHAN_TRAF_CTXT_CNT - 1;
    00378     int idx = ctxt->idx + 1;
    00379
    00380     while (nb > 0)
    00381     {
    00382         if (idx == CHAN_TRAF_CTXT_CNT)
    00383             idx = 0;
    00384
    00385         if (chan_ctxt_pool[idx].idx != CHAN_CTXT_UNUSED)
    00386             return &chan_ctxt_pool[idx];
    00387
    00388         nb--;
    00389         idx++;
    00390     }
    00391
    00392     return NULL;
    00393 }
    00394
    00404 static void chan_send_pre_switch_ind(struct chan_ctxt_tag *old_ctxt)
    00405 {
    00406     struct mm_channel_pre_switch_ind *ind;
    00407
    00408     if (old_ctxt->idx == CHAN_SCAN_CTXT_IDX)
    00409         return;
    00410
    00411     ind = KE_MSG_ALLOC(MM_CHANNEL_PRE_SWITCH_IND, TASK_API, TASK_MM,
    00412                        mm_channel_pre_switch_ind);
    00413
    00414     ind->chan_index = old_ctxt->idx;
    00415
    00416     ke_msg_send(ind);
    00417 }
    00418
    00428 static void chan_send_switch_ind(struct chan_ctxt_tag *new_ctxt)
    00429 {
    00430     struct mm_channel_switch_ind *ind;
    00431
    00432     if (new_ctxt->idx == CHAN_SCAN_CTXT_IDX)
    00433         return;
    00434
    00435     ind = KE_MSG_ALLOC(MM_CHANNEL_SWITCH_IND, TASK_API,
    00436                        TASK_MM, mm_channel_switch_ind);
    00437
    00438     ind->chan_index = new_ctxt->idx;
    00439     // If ROC triggered internally, do not notify driver
    00440     #if NX_UMAC_PRESENT && NX_TDLS
    00441     ind->roc = ((new_ctxt->idx == CHAN_ROC_CTXT_IDX) && (new_ctxt->taskid != TASK_MM) && (new_ctxt->taskid != TASK_TDLS));
    00442     ind->roc_tdls = new_ctxt->roc_tdls;
    00443     #else
    00444     ind->roc = ((new_ctxt->idx == CHAN_ROC_CTXT_IDX) && (new_ctxt->taskid != TASK_MM));
    00445     ind->roc_tdls = 0;
    00446     #endif
    00447     ind->vif_index = new_ctxt->vif_index;
    00448
    00449     ke_msg_send(ind);
    00450 }
    00451
    00452 #if (NX_HW_SCAN)
    00453
    00459 static void chan_send_survey_ind(void)
    00460 {
    00461     struct mac_chan_def const *scan_chan = scan_get_chan();
    00462     struct mm_channel_survey_ind *ind = KE_MSG_ALLOC(MM_CHANNEL_SURVEY_IND,
    00463                                                      TASK_API, TASK_MM,
    00464                                                      mm_channel_survey_ind);
    00465     #if (NX_MDM_VER >= 20)
    00466     uint8_t read_counter = 10;
    00467     #endif //(NX_MDM_VER >= 20)
    00468
    00469     ind->freq = scan_chan->freq;
    00470     ind->chan_time_ms = ((scan_chan->flags & CHAN_NO_IR) ? SCAN_PASSIVE_DURATION : SCAN_ACTIVE_DURATION) / 1000;
    00471     // Time values read in register are in units of us (-> /1000)
    00472     ind->chan_time_busy_ms = nxmac_edca_cca_busy_get() / 1000;
    00473     ind->noise_dbm = 0;
    00474
    00475     #if (NX_MDM_VER >= 20)
    00476     // If read noise value is 0, value is not valid because of re-sync between AGC clock
    00477     // and AHB clock. Register value is updated once AGC is in listen state.
    00478     while (read_counter--)
    00479     {
    00480         // During scan, config used is 1x1, noise has to be read to antenna 0
    00481         int8_t reg_noise = (int8_t)riu_inbdpow20pnoisedbm0_getf();
    00482
    00483         if (reg_noise != 0)
    00484         {
    00485             ind->noise_dbm = reg_noise;
    00486             break;
    00487         }
    00488     }
    00489     #endif //(NX_MDM_VER >= 20)
    00490
    00491     ke_msg_send(ind);
    00492 }
    00493 #endif //(NX_HW_SCAN)
    00494
    00504 static void chan_send_roc_exp_ind(struct chan_ctxt_tag *ctxt)
    00505 {
    00506     struct mm_remain_on_channel_exp_ind *ind = KE_MSG_ALLOC(MM_REMAIN_ON_CHANNEL_EXP_IND,
    00507                                                             ctxt->taskid, TASK_MM,
    00508                                                             mm_remain_on_channel_exp_ind);
    00509
    00510     ind->chan_ctxt_index = ctxt->idx;
    00511     ind->vif_index       = ctxt->vif_index;
    00512
    00513     ke_msg_send(ind);
    00514 }
    00515
    00516 #if (NX_P2P_GO)
    00517
    00525 __INLINE bool chan_is_p2p_go(struct vif_info_tag *vif)
    00526 {
    00527     return ((vif->p2p) &&
    00528             (p2p_info_tab[vif->p2p_index].role == P2P_ROLE_GO));
    00529 }
    00530
    00546 static uint32_t chan_window_merge_duration(struct chan_window *w1,
    00547                                            struct chan_window *w2,
    00548                                            struct chan_window *w_res,
    00549                                            uint32_t interval)
    00550 {
    00551     struct chan_window *w;
    00552     uint32_t duration;
    00553     uint32_t delta;
    00554
    00555     // Need to align window timestamp in the same interval
    00556     if (hal_machw_time_cmp(w1->start, w2->start))
    00557     {
    00558         w = w1;
    00559         delta = w2->start - w1->start;
    00560     }
    00561     else
    00562     {
    00563         w = w2;
    00564         delta = w1->start - w2->start;
    00565     }
    00566
    00567     // Use loop instead of % as in most cases it will only take a few iterations
    00568     // which is faster than %
    00569     while (delta > interval) {
    00570         delta -= interval;
    00571         w->start += interval;
    00572         w->end += interval;
    00573     }
    00574     if (delta > (interval / 2))
    00575     {
    00576         w->start += interval;
    00577         w->end += interval;
    00578     }
    00579
    00580     if (hal_machw_time_cmp(w1->end, w2->end))
    00581     {
    00582         duration = w2->end;
    00583         if (w_res)
    00584             w_res->end = w2->end;
    00585     }
    00586     else
    00587     {
    00588         duration = w1->end;
    00589         if (w_res)
    00590             w_res->end = w1->end;
    00591     }
    00592
    00593     if (hal_machw_time_cmp(w1->start, w2->start))
    00594     {
    00595         duration -= w1->start;
    00596         if (w_res)
    00597             w_res->start = w1->start;
    00598     }
    00599     else
    00600     {
    00601         duration -= w2->start;
    00602         if (w_res)
    00603             w_res->start = w2->start;
    00604     }
    00605
    00606     return duration;
    00607 }
    00608
    00616 static void chan_stop_p2pgo_noa(struct vif_info_tag *p2pgo_vif)
    00617 {
    00618     struct p2p_info_tag *p2p = &p2p_info_tab[p2pgo_vif->p2p_index];
    00619     struct vif_info_tag *vif;
    00620     int i;
    00621
    00622     for (i = 0; i < P2P_NOA_NB_MAX; i ++)
    00623     {
    00624         if ((p2p->noa[i].noa_type == P2P_NOA_TYPE_CONCURRENT) &&
    00625             (p2p->noa[i].noa_status != P2P_NOA_TIMER_NOT_STARTED))
    00626             p2p_go_noa_stop(p2pgo_vif, i, false);
    00627     }
    00628
    00629     vif = vif_mgmt_first_used();
    00630     while (vif)
    00631     {
    00632         if (vif->tbtt_switch.p2p_noa_vif_index == p2pgo_vif->index)
    00633         {
    00634             vif->tbtt_switch.p2p_noa_vif_index = INVALID_VIF_IDX;
    00635         }
    00636         vif = vif_mgmt_next(vif);
    00637     }
    00638 }
    00639
    00659 static void chan_start_p2pgo_noa(struct vif_info_tag *p2pgo_vif)
    00660 {
    00661     struct vif_info_tag *vif;
    00662     struct chan_noa {
    00663         uint32_t intv;
    00664         uint32_t dur;
    00665         struct chan_window win;
    00666         uint32_t vifs;
    00667     } noa[P2P_NOA_NB_MAX];
    00668     int noa_idx = 0;
    00669     uint32_t p2p_intv;
    00670     #if NX_BEACONING
    00671     bool ap_tbtt_moved = false;
    00672     int32_t ap_tbtt_move_min = 0, ap_tbtt_move_max = 0;
    00673     #endif
    00674     struct chan_ctxt_tag *oth_ctxt = NULL;
    00675     uint32_t nb_vif_oth_ctxt = 0;
    00676
    00677     if (chan_env.nb_sched_ctxt < 2)
    00678         return;
    00679
    00680     ASSERT_ERR((p2pgo_vif->chan_ctxt->p2pgo_vif_index == INVALID_VIF_IDX) ||
    00681                (p2pgo_vif->chan_ctxt->p2pgo_vif_index == p2pgo_vif->index));
    00682     chan_stop_p2pgo_noa(p2pgo_vif);
    00683     p2pgo_vif->chan_ctxt->p2pgo_vif_index = p2pgo_vif->index;
    00684
    00685     p2p_intv = chan_vif_tbtt_intv(p2pgo_vif);
    00686     oth_ctxt = chan_get_next_traf_ctxt(p2pgo_vif->chan_ctxt);
    00687     ASSERT_ERR(oth_ctxt);
    00688     nb_vif_oth_ctxt = oth_ctxt->nb_linked_vif;
    00689
    00690     vif = vif_mgmt_first_used();
    00691     while (vif)
    00692     {
    00693         if (vif->chan_ctxt && (vif->chan_ctxt != p2pgo_vif->chan_ctxt))
    00694         {
    00695             uint32_t dur, intv;
    00696             bool merged = false;
    00697
    00698             intv = chan_vif_tbtt_intv(vif);
    00699             if (intv >= (2 * p2p_intv))
    00700             {
    00701                 intv = intv / (intv / p2p_intv);
    00702             }
    00703             dur = intv / 2; // For 50-50 repartition
    00704             dur = dur / nb_vif_oth_ctxt;
    00705             if (dur < (CHAN_SWITCH_DELAY + chan_vif_tbtt_dur(vif)))
    00706                 dur = CHAN_SWITCH_DELAY + chan_vif_tbtt_dur(vif);
    00707
    00708             // Merge with previous NOA if possible
    00709             for (int i = 0 ; i < noa_idx; i ++)
    00710             {
    00711                 struct chan_window win1, win2;
    00712                 uint32_t win_dur, dur_merge;
    00713
    00714                 // can only merge NOA with same intv
    00715                 if (noa[i].intv != intv)
    00716                     continue;
    00717
    00718                 win1.start = vif->tbtt_timer.time;
    00719                 win1.end = win1.start + chan_vif_tbtt_dur(vif);
    00720                 win2 = noa[i].win;
    00721                 win_dur = chan_window_merge_duration(&win1, &win2, &win1, intv);
    00722
    00723                 // Merging NOA is like removing one vif (from sharing time point of view)
    00724                 ASSERT_ERR(nb_vif_oth_ctxt > 1);
    00725                 dur_merge = (dur * nb_vif_oth_ctxt) / (nb_vif_oth_ctxt - 1);
    00726                 // TBTTs cannot be to far apart as the NOA must include one switch
    00727                 // The second switch is taken out of P2P channel time.
    00728                 dur_merge -= CHAN_SWITCH_DELAY;
    00729                 if (dur_merge < noa[i].dur)
    00730                     dur_merge = noa[i].dur;
    00731
    00732                 if (win_dur < dur_merge)
    00733                 {
    00734                     merged = true;
    00735                     noa[i].dur = dur_merge + CHAN_SWITCH_DELAY;
    00736                     noa[i].win = win1;
    00737                     noa[i].vifs |= CO_BIT(vif->index);
    00738                     break;
    00739                 }
    00740             }
    00741
    00742             if (!merged)
    00743             {
    00744                 ASSERT_ERR(noa_idx < P2P_NOA_NB_MAX);
    00745
    00746                 noa[noa_idx].intv = intv;
    00747                 noa[noa_idx].dur = dur;
    00748                 noa[noa_idx].win.start = vif->tbtt_timer.time;
    00749                 noa[noa_idx].win.end = noa[noa_idx].win.start + chan_vif_tbtt_dur(vif);
    00750                 ASSERT_ERR(vif->index < 32);
    00751                 noa[noa_idx].vifs = CO_BIT(vif->index);
    00752                 noa_idx++;
    00753             }
    00754         }
    00755         vif = vif_mgmt_next(vif);
    00756     }
    00757
    00758     for (int i = 0 ; i < noa_idx; i++)
    00759     {
    00760         struct chan_window win;
    00761         uint32_t start, dur;
    00762         uint32_t start_offset = 2000; // Start 2ms before TBTT to handle drift
    00763         uint8_t noa_idx;
    00764
    00765         #if NX_BEACONING
    00766         // If p2pgo and "controlling" vifs have a multiple beacon period, updating AP TBTT
    00767         // will allow to have p2p TBTT in a presence period.
    00768         if ((noa[i].intv % p2p_intv) == 0)
    00769         {
    00770             uint32_t intv = co_min(noa[i].intv, p2p_intv);
    00771             uint32_t ap_next_tbtt;
    00772             int32_t  time_after_tbtt, tbtt_move;
    00773             int32_t tbtt_move_min, tbtt_move_max;
    00774
    00775             // At this point beacon interval may not be programmed yet
    00776             ap_next_tbtt = hal_machw_time() + (nxmac_next_tbtt_get() << 5);
    00777
    00778             // compute time after end on last TBTT in NOA and TBTT of P2P-GO
    00779             win.start = ap_next_tbtt;
    00780             win.end = win.start + chan_vif_tbtt_dur(p2pgo_vif);
    00781             time_after_tbtt = chan_window_merge_duration(&noa[i].win, &win, NULL, intv);
    00782             if (hal_machw_time_cmp(noa[i].win.start , win.start))
    00783                 time_after_tbtt = win.start - noa[i].win.end;
    00784             else
    00785                 time_after_tbtt = intv - time_after_tbtt;
    00786
    00787             // NOA duration from the end of the sta TBTT
    00788             tbtt_move = (noa[i].dur - (noa[i].win.end - noa[i].win.start) - start_offset);
    00789             if (tbtt_move < (int32_t)CHAN_SWITCH_DELAY)
    00790                 tbtt_move = (int32_t)CHAN_SWITCH_DELAY;
    00791
    00792             tbtt_move_min = tbtt_move - time_after_tbtt;
    00793             tbtt_move_max = tbtt_move_min + (noa[i].intv - noa[i].dur
    00794                                              - CHAN_SWITCH_DELAY - chan_vif_tbtt_dur(p2pgo_vif));
    00795
    00796
    00797             if (ap_tbtt_moved)
    00798             {
    00799                 // See if there is a value that would fit all NOA.
    00800                 if (tbtt_move_min > ap_tbtt_move_max)
    00801                 {
    00802                     tbtt_move_min -= p2p_intv;
    00803                     tbtt_move_max -= p2p_intv;
    00804                 }
    00805                 else if (ap_tbtt_move_min > tbtt_move_max)
    00806                 {
    00807                     tbtt_move_max += p2p_intv;
    00808                     tbtt_move_min += p2p_intv;
    00809                 }
    00810
    00811                 if ((ap_tbtt_move_max >= tbtt_move_min) &&
    00812                     (tbtt_move_max >= ap_tbtt_move_min))
    00813                 {
    00814                     if (tbtt_move_min > ap_tbtt_move_min)
    00815                         ap_tbtt_move_min = tbtt_move_min;
    00816                     if (tbtt_move_max < ap_tbtt_move_max)
    00817                         ap_tbtt_move_max = tbtt_move_max;
    00818                 }
    00819             }
    00820             else
    00821             {
    00822                 ap_tbtt_move_min = tbtt_move_min;
    00823                 ap_tbtt_move_max = tbtt_move_max;
    00824                 ap_tbtt_moved = true;
    00825             }
    00826         }
    00827         #endif //NX_BEACONING
    00828
    00829         // Need to include switching time in the NOA duration
    00830         start_offset += CHAN_SWITCH_DELAY;
    00831         start = noa[i].win.start - start_offset;
    00832         dur = noa[i].dur + CHAN_SWITCH_DELAY;
    00833
    00834         // Need to re-adjust start date to start on next iteration
    00835         // Would be more compact using div/modulo but not faster as in most cases
    00836         // while loop will have 0 iterations ()
    00837         if (hal_machw_time_past(start))
    00838         {
    00839             start += noa[i].intv;
    00840             while (hal_machw_time_past(start))
    00841                 start += noa[i].intv;
    00842         }
    00843         else if (!hal_machw_time_past(start - noa[i].intv))
    00844         {
    00845             start -= noa[i].intv;
    00846             while (!hal_machw_time_past(start - noa[i].intv))
    00847                 start -= noa[i].intv;
    00848         }
    00849
    00850         noa_idx = p2p_go_noa_start(p2pgo_vif, true, false, P2P_NOA_CONTINUOUS_COUNTER,
    00851                                    noa[i].intv, dur, start);
    00852
    00853         noa[i].win.start = start;
    00854         noa[i].win.end = start + dur;
    00855         for (int j = 0; j < NX_VIRT_DEV_MAX; j++)
    00856         {
    00857             if (!(noa[i].vifs & CO_BIT(j)))
    00858                 continue;
    00859             vif = &vif_info_tab[j];
    00860
    00861             win.start = vif->tbtt_timer.time;
    00862             win.end = win.start + chan_vif_tbtt_dur(vif);
    00863             chan_window_merge_duration(&noa[i].win, &win, NULL, noa[i].intv);
    00864
    00865             ASSERT_ERR(vif->tbtt_switch.p2p_noa_vif_index == INVALID_VIF_IDX);
    00866             vif->tbtt_switch.p2p_noa_vif_index = p2pgo_vif->index;
    00867             vif->tbtt_switch.p2p_noa_index = noa_idx;
    00868             vif->tbtt_switch.p2p_noa_tbtt_to_end = noa[i].win.end - win.start;
    00869             vif->tbtt_switch.p2p_noa_drift = 0;
    00870         }
    00871
    00872         TRACE_CHAN(NOA, "{VIF-%d}{CTXT-%d} Start periodic NOA for TBTT on vifs %x"
    00873                    ": duration=%ldus interval=%ldus start %t",
    00874                    p2pgo_vif->index, p2pgo_vif->chan_ctxt->idx, noa[i].vifs, TR_32(dur),
    00875                    TR_32(noa[i].intv), TR_32(start));
    00876     }
    00877
    00878     #if NX_BEACONING
    00879     if (ap_tbtt_moved)
    00880     {
    00881         int32_t tbtt_move = ap_tbtt_move_min + 5000;
    00882         if (tbtt_move > ap_tbtt_move_max)
    00883             tbtt_move = ap_tbtt_move_max;
    00884
    00885         if (tbtt_move > ((int32_t)p2p_intv / 2))
    00886             tbtt_move -= p2p_intv;
    00887         else if (tbtt_move < (-1 * ((int32_t)p2p_intv / 2)))
    00888             tbtt_move += p2p_intv;
    00889
    00890         p2pgo_vif->tbtt_switch.p2p_noa_tsf_update = mm_ap_tbtt_move(tbtt_move);
    00891         p2pgo_vif->tbtt_switch.status |= CHAN_TBTT_P2P_NOA_TSF_UPDATE;
    00892     }
    00893     #endif //NX_BEACONING
    00894 }
    00895
    00904 __INLINE bool chan_get_p2pgo(struct vif_info_tag **p2pgo_vif)
    00905 {
    00906     for (int ctxt_idx = 0; ctxt_idx < CHAN_TRAF_CTXT_CNT; ctxt_idx++)
    00907     {
    00908         struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[ctxt_idx];
    00909
    00910         if ((ctxt->idx != CHAN_CTXT_UNUSED) &&
    00911             (ctxt->p2pgo_vif_index != INVALID_VIF_IDX))
    00912         {
    00913             *p2pgo_vif = &vif_info_tab[ctxt->p2pgo_vif_index];
    00914             return true;
    00915         }
    00916     }
    00917     return false;
    00918 }
    00919
    00933 static bool chan_start_p2pgo_single_noa(struct vif_info_tag *vif, uint32_t start,
    00934                                         struct chan_tbtt_tag *tbtt)
    00935 {
    00936     struct vif_info_tag *p2pgo_vif = vif;
    00937     uint32_t duration;
    00938
    00939     if (!p2pgo_vif && !chan_get_p2pgo(&p2pgo_vif))
    00940         return false;
    00941
    00942     if (tbtt && (tbtt->p2p_noa_vif_index != INVALID_VIF_IDX))
    00943     {
    00944         // If a TBTT induce this NOA, then we already have a concurrent NOA
    00945         // that should cover this TBTT. But because of drift or CHAN_SWITCH_DELAY
    00946         // the periodic NOA may end a little before the requested single NOA.
    00947         // If this is the case, a channel switch will be scheduled during the short
    00948         // presence period. To avoid this start single NOA earlier so that both NOA
    00949         // overlap
    00950         struct vif_info_tag *vif_noa =  &vif_info_tab[tbtt->vif_index];
    00951         uint32_t cc_noa_end;
    00952         uint32_t cc_noa_intv = chan_vif_tbtt_intv(vif_noa);
    00953         uint32_t noa_end = tbtt->time + chan_vif_tbtt_dur(vif_noa) + CHAN_SWITCH_DELAY;
    00954
    00955         cc_noa_end = p2p_go_get_next_noa_end_date(vif, tbtt->p2p_noa_index);
    00956         while (hal_machw_time_cmp(cc_noa_end + (cc_noa_intv / 2), start))
    00957         {
    00958             cc_noa_end += cc_noa_intv;
    00959         }
    00960         if (hal_machw_time_cmp(cc_noa_end, start))
    00961         {
    00962             start = cc_noa_end - 1;
    00963         }
    00964
    00965         if (hal_machw_time_cmp(noa_end + 5000, start))
    00966             duration = 5000;
    00967         else
    00968             duration = noa_end - start;
    00969     }
    00970     else
    00971     {
    00972         duration = chan_vif_tbtt_dur(vif) + CHAN_SWITCH_DELAY;
    00973     }
    00974
    00975     return (p2p_go_noa_start(p2pgo_vif, true, false, 1,
    00976                              0, duration, start) != P2P_INVALID_IDX);
    00977 }
    00978 #endif //(NX_P2P_GO)
    00979
    00989 static bool chan_tbtt_overlap(struct chan_tbtt_tag *tbtt1, struct chan_tbtt_tag *tbtt2)
    00990 {
    00991     struct vif_info_tag *vif1 = &vif_info_tab[tbtt1->vif_index];
    00992     struct vif_info_tag *vif2 = &vif_info_tab[tbtt2->vif_index];
    00993     uint32_t start1, end1, start2, end2;
    00994
    00995     if (vif1->chan_ctxt == vif2->chan_ctxt)
    00996         return false;
    00997
    00998     start1 = tbtt1->time;
    00999     end1 = start1 + chan_vif_tbtt_dur(vif1) + CHAN_SWITCH_DELAY;
    01000     start2 = tbtt2->time;
    01001     end2 = start2 + chan_vif_tbtt_dur(vif2) + CHAN_SWITCH_DELAY;
    01002
    01003     if ((hal_machw_time_cmp(start1, start2) && hal_machw_time_cmp(start2, end1)) ||
    01004         (hal_machw_time_cmp(start2, start1) && hal_machw_time_cmp(start1, end2)) ||
    01005         (start2 == start1)) {
    01006         return true;
    01007     }
    01008
    01009     return false;
    01010 }
    01011
    01045 __INLINE bool chan_tbtt_skip_fix_ctxt(uint32_t tbtt_time, struct chan_ctxt_tag *ctxt)
    01046 {
    01047     if (!chan_switch_no_schedule())
    01048     {
    01049         struct chan_switch_tag *ch_switch = chan_switch_last();
    01050         uint32_t date = ch_switch->time + CHAN_SWITCH_DELAY;
    01051
    01052         if (ch_switch->ctxt != ctxt)
    01053         {
    01054             date += CHAN_SWITCH_DELAY;
    01055             if (ch_switch->tbtt)
    01056             {
    01057                 date += chan_vif_tbtt_dur(&vif_info_tab[ch_switch->tbtt->vif_index]);
    01058             }
    01059         }
    01060         return hal_machw_time_cmp(tbtt_time, date);
    01061     }
    01062     else if (chan_env.fix_ctxt &&
    01063              (chan_env.fix_ctxt != ctxt))
    01064     {
    01065         return hal_machw_time_cmp(tbtt_time, chan_env.fix_until + CHAN_SWITCH_DELAY);
    01066     }
    01067
    01068     return false;
    01069 }
    01070
    01087 static void chan_add_next_tbtt(struct vif_info_tag *vif, uint32_t tbtt_time,
    01088                                uint32_t skip_cnt)
    01089 {
    01090     struct chan_tbtt_tag *elem = NULL, *tbtt = &vif->tbtt_switch;
    01091     bool skip_it = false;
    01092     uint32_t end_tbtt;
    01093
    01094     if ((skip_cnt == 0) && (tbtt->status & CHAN_TBTT_PROG))
    01095         chan_tbtt_remove(tbtt);
    01096
    01097     if (chan_tbtt_skip_fix_ctxt(tbtt_time, vif->chan_ctxt))
    01098     {
    01099         skip_it = true;
    01100     }
    01101     else
    01102     {
    01103         tbtt->time = tbtt_time;
    01104         // -1 because hal_machw_time_cmp use < and not <=
    01105         end_tbtt = tbtt->time + chan_vif_tbtt_dur(vif) + CHAN_SWITCH_DELAY - 1;
    01106
    01107         elem = chan_tbtt_pick();
    01108         while (elem)
    01109         {
    01110             if (hal_machw_time_cmp(end_tbtt, elem->time))
    01111                 break;
    01112
    01113             if (chan_tbtt_overlap(tbtt, elem))
    01114             {
    01115                 skip_it = true;
    01116                 break;
    01117             }
    01118             else if (hal_machw_time_cmp(tbtt_time, elem->time))
    01119             {
    01120                 break;
    01121             }
    01122
    01123             elem = chan_tbtt_next(elem);
    01124         }
    01125     }
    01126
    01127     if (skip_it)
    01128     {
    01129         #if (NX_P2P_GO)
    01130         if (chan_is_p2p_go(vif))
    01131         {
    01132             chan_start_p2pgo_single_noa(vif, tbtt_time, elem);
    01133         }
    01134         #endif //(NX_P2P_GO)
    01135         return chan_add_next_tbtt(vif, tbtt_time + chan_vif_tbtt_intv(vif), skip_cnt + 1);
    01136     }
    01137
    01138     chan_tbtt_insert_before(tbtt, elem);
    01139     TRACE_CHAN(TBTT, "{VIF-%d} schedule next TBTT %t (skip=%d)", vif->index,
    01140                TR_32(tbtt_time), skip_cnt);
    01141 }
    01142
    01156 static uint32_t chan_share_medium(int32_t dur_to_split, uint32_t dur_spent, uint32_t now)
    01157 {
    01158     uint32_t split_dur = (dur_to_split + dur_spent) / 2;
    01159     if (split_dur < dur_spent)
    01160         split_dur = 0;
    01161     else
    01162         split_dur -= dur_spent;
    01163     return now + split_dur;
    01164 }
    01165
    01175 static void chan_schedule_one_switch(uint32_t date, struct chan_ctxt_tag *ctxt,
    01176                                      struct chan_tbtt_tag *tbtt)
    01177 {
    01178     struct chan_switch_tag *ch_switch = chan_switch_alloc();
    01179     bool set_timer = chan_switch_no_schedule();
    01180     TRACE_CHAN(SWITCH, "{CTXT-%d} schedule switch at %t",
    01181                ctxt ? ctxt->idx : 255, TR_32(date));
    01182     ch_switch->time = date;
    01183     ch_switch->ctxt = ctxt;
    01184     ch_switch->tbtt = tbtt;
    01185
    01186     chan_switch_push_back(ch_switch);
    01187     if (set_timer)
    01188         chan_switch_set_timer(ch_switch);
    01189 }
    01190
    01191 #if NX_P2P_GO
    01192
    01220 static bool chan_schedule_extra_switch_from_p2pgo_ctxt(int p2p_vif_index,
    01221                                                        uint32_t now,
    01222                                                        uint32_t *switch_date,
    01223                                                        uint32_t *return_date)
    01224 {
    01225     struct vif_info_tag *p2p_vif = &vif_info_tab[p2p_vif_index];
    01226     uint32_t p2p_next_present, p2p_next_absent;
    01227     bool p2p_present =  p2p_go_get_next_NOA_date(p2p_vif,
    01228                                                  &p2p_next_present,
    01229                                                  &p2p_next_absent);
    01230     bool switch_scheduled = false;
    01231     uint32_t tbtt_return_date = *return_date;
    01232
    01233     if (p2p_present)
    01234     {
    01235         *switch_date = p2p_next_absent;
    01236         if (hal_machw_time_cmp((p2p_next_present - CHAN_SWITCH_DELAY), *return_date))
    01237             *return_date = p2p_next_present - CHAN_SWITCH_DELAY;
    01238         if (hal_machw_time_cmp(*return_date,
    01239                                *switch_date + CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US))
    01240         {
    01241             return false;
    01242         }
    01243     }
    01244     else
    01245     {
    01246         if (hal_machw_time_cmp(now + 2 * CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US,
    01247                                p2p_next_present))
    01248         {
    01249             *switch_date = now;
    01250             if (hal_machw_time_cmp((p2p_next_present - CHAN_SWITCH_DELAY), *return_date))
    01251                 *return_date = p2p_next_present - CHAN_SWITCH_DELAY;
    01252
    01253             switch_scheduled = true;
    01254         }
    01255
    01256         if (hal_machw_time_cmp(p2p_next_absent + CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US,
    01257                                tbtt_return_date))
    01258         {
    01259             if(switch_scheduled)
    01260             {
    01261                 chan_schedule_one_switch(now, chan_get_next_traf_ctxt(p2p_vif->chan_ctxt),
    01262                                          NULL);
    01263                 chan_schedule_one_switch(*return_date, p2p_vif->chan_ctxt, NULL);
    01264                 *return_date = tbtt_return_date;
    01265             }
    01266
    01267             // Assume that p2p_next_next_presence date is after return date (may not
    01268             // always be the case if non concurrent NOA are scheduled)
    01269             *switch_date = p2p_next_absent;
    01270         }
    01271         else if (!switch_scheduled)
    01272         {
    01273             return false;
    01274         }
    01275     }
    01276     return true;
    01277 }
    01278
    01279
    01301 static bool chan_schedule_extra_switch_to_p2pgo_ctxt(int p2p_vif_index,
    01302                                                      uint32_t *switch_date,
    01303                                                      uint32_t *return_date)
    01304 {
    01305     struct vif_info_tag *p2p_vif = &vif_info_tab[p2p_vif_index];
    01306     uint32_t p2p_next_present, p2p_next_absent;
    01307     bool p2p_present =  p2p_go_get_next_NOA_date(p2p_vif,
    01308                                                  &p2p_next_present,
    01309                                                  &p2p_next_absent);
    01310     // sanity check
    01311     if (p2p_present)
    01312     {
    01313         TRACE_CHAN(ERR, "P2P GO present while processing TBTT on another ctxt ..."
    01314                    "next absent %t", TR_32(p2p_next_absent));
    01315     }
    01316
    01317     if (hal_machw_time_cmp(*return_date, p2p_next_present - CHAN_SWITCH_DELAY))
    01318         // No P2P go presence before next TBTT, don't schedule any switch
    01319         return false;
    01320     *switch_date = p2p_next_present - CHAN_SWITCH_DELAY;
    01321
    01322     // sanity check
    01323     if (hal_machw_time_cmp(*return_date, p2p_next_absent))
    01324     {
    01325         TRACE_CHAN(ERR, "P2P GO absence %t happens after next TBTT %t",
    01326                    TR_32(p2p_next_absent), TR_32(*return_date));
    01327         // TODO rescheduled NOA ?
    01328     }
    01329     else
    01330     {
    01331         *return_date = p2p_next_absent;
    01332     }
    01333
    01334     return true;
    01335 }
    01336
    01355 static void chan_schedule_switch_from_p2pgo_ctxt(int p2p_vif_index,
    01356                                                  struct chan_ctxt_tag *next_ctxt,
    01357                                                  uint32_t now,
    01358                                                  uint32_t *switch_date)
    01359 {
    01360     struct vif_info_tag *p2p_vif = &vif_info_tab[p2p_vif_index];
    01361     uint32_t p2p_next_present, p2p_next_absent;
    01362     bool p2p_present =  p2p_go_get_next_NOA_date(p2p_vif,
    01363                                                  &p2p_next_present,
    01364                                                  &p2p_next_absent);
    01365
    01366     if (p2p_present)
    01367     {
    01368         if (hal_machw_time_cmp(*switch_date, p2p_next_absent))
    01369         {
    01370             TRACE_CHAN(ERR, "P2P GO next absence [%t..%t] happens after next TBTT %t",
    01371                        TR_32(p2p_next_absent), TR_32(p2p_next_present),
    01372                        TR_32(*switch_date));
    01373             // TODO rescheduled NOA ?
    01374             return;
    01375         }
    01376         else if (hal_machw_time_cmp(p2p_next_present, *switch_date))
    01377         {
    01378             if ((p2p_next_present - p2p_next_absent) > CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US)
    01379             {
    01380                 chan_schedule_one_switch(p2p_next_absent, next_ctxt, NULL);
    01381                 chan_schedule_one_switch(p2p_next_present - CHAN_SWITCH_DELAY,
    01382                                          p2p_vif->chan_ctxt, NULL);
    01383             }
    01384         }
    01385         else
    01386             *switch_date = p2p_next_absent;
    01387     }
    01388     else
    01389     {
    01390         if (hal_machw_time_cmp(*switch_date, p2p_next_present))
    01391             *switch_date = now;
    01392         else
    01393         {
    01394             if ((p2p_next_present - now) > CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US)
    01395             {
    01396                 chan_schedule_one_switch(now, next_ctxt, NULL);
    01397                 chan_schedule_one_switch(p2p_next_present - CHAN_SWITCH_DELAY,
    01398                                          p2p_vif->chan_ctxt, NULL);
    01399             }
    01400
    01401             if (hal_machw_time_cmp(*switch_date, p2p_next_absent))
    01402             {
    01403                 TRACE_CHAN(ERR, "P2P GO presence [%t..%t] will overlap with next TBTT %t",
    01404                            TR_32(p2p_next_present), TR_32(p2p_next_absent),
    01405                            TR_32(*switch_date));
    01406                 // TODO rescheduled NOA ?
    01407                 return;
    01408             }
    01409             *switch_date = p2p_next_absent;
    01410         }
    01411     }
    01412 }
    01413
    01431 static void chan_schedule_switch_to_p2pgo_ctxt(int p2p_vif_index,
    01432                                                struct chan_ctxt_tag *ctxt,
    01433                                                uint32_t now, uint32_t *switch_date)
    01434 {
    01435     struct vif_info_tag *p2p_vif = &vif_info_tab[p2p_vif_index];
    01436     uint32_t p2p_next_present, p2p_next_absent;
    01437     bool p2p_present =  p2p_go_get_next_NOA_date(p2p_vif,
    01438                                                  &p2p_next_present,
    01439                                                  &p2p_next_absent);
    01440     uint32_t tbtt_switch_date = *switch_date;
    01441
    01442     p2p_next_present -= CHAN_SWITCH_DELAY;
    01443     if (p2p_present)
    01444     {
    01445         TRACE_CHAN(ERR, "P2P GO present while processing TBTT on another ctxt ..."
    01446                    "next absent %t", TR_32(p2p_next_absent));
    01447
    01448         *switch_date = now;
    01449     }
    01450     else if (hal_machw_time_cmp(p2p_next_present, *switch_date))
    01451     {
    01452         *switch_date = p2p_next_present;
    01453     }
    01454
    01455     if (hal_machw_time_cmp(p2p_next_absent + CHAN_SWITCH_DELAY + CHAN_MIN_PRES_DUR_US,
    01456                            tbtt_switch_date))
    01457     {
    01458         chan_schedule_one_switch(*switch_date, p2p_vif->chan_ctxt, NULL);
    01459         chan_schedule_one_switch(p2p_next_absent, ctxt, NULL);
    01460
    01461         if (p2p_present && hal_machw_time_cmp(p2p_next_present, tbtt_switch_date))
    01462             *switch_date = p2p_next_present;
    01463         else
    01464             *switch_date = tbtt_switch_date;
    01465     }
    01466
    01467 }
    01468
    01469 #endif //NX_P2P_GO
    01470
    01499 static void chan_schedule_next_switch(struct vif_info_tag *vif, uint32_t now,
    01500                                       uint32_t tbtt_dur)
    01501 {
    01502     struct chan_ctxt_tag *ctxt = vif->chan_ctxt;
    01503     struct chan_tbtt_tag *tbtt_next = chan_tbtt_pick();
    01504     struct vif_info_tag *vif_next = &vif_info_tab[tbtt_next->vif_index];
    01505     int32_t dur_to_split = tbtt_next->time - now - CHAN_SWITCH_DELAY;
    01506
    01507     // sanity check
    01508     if (chan_env.current_ctxt != ctxt)
    01509     {
    01510         TRACE_CHAN(ERR, "Schedule switch: not on expected channel."
    01511                    " current_ctxt=%d expected_channel=%d status=%d",
    01512                    chan_env.current_ctxt ? chan_env.current_ctxt->idx: -1,
    01513                    ctxt->idx, ctxt->status);
    01514     }
    01515
    01516     if (ctxt == vif_next->chan_ctxt)
    01517     {
    01518         // Next TBTT is on the same ctxt, check if we can spent at at least
    01519         // CHAN_MIN_PRES_DUR_US on the other channel before it.
    01520         // This means two channel switches so take it into account when sharing medium
    01521         uint32_t switch_date = now, return_date;
    01522
    01523         dur_to_split -= CHAN_SWITCH_DELAY;
    01524         if (dur_to_split < CHAN_MIN_PRES_DUR_US)
    01525             return;
    01526
    01527         return_date = tbtt_next->time - CHAN_SWITCH_DELAY;
    01528
    01529         #if (NX_P2P_GO)
    01530         if (ctxt->p2pgo_vif_index != INVALID_VIF_IDX)
    01531         {
    01532             if (!chan_schedule_extra_switch_from_p2pgo_ctxt(ctxt->p2pgo_vif_index,
    01533                                                             now, &switch_date,
    01534                                                             &return_date))
    01535                 return ;
    01536         }
    01537         else if (vif->tbtt_switch.p2p_noa_vif_index != INVALID_VIF_IDX)
    01538         {
    01539             if (!chan_schedule_extra_switch_to_p2pgo_ctxt(vif->tbtt_switch.p2p_noa_vif_index,
    01540                                                           &switch_date,
    01541                                                           &return_date))
    01542                 return ;
    01543         }
    01544         else
    01545         #endif // (NX_P2P_GO)
    01546         {
    01547             switch_date = chan_share_medium(dur_to_split, tbtt_dur, now);
    01548         }
    01549
    01550         chan_schedule_one_switch(switch_date, chan_get_next_traf_ctxt(ctxt), NULL);
    01551         chan_schedule_one_switch(return_date, ctxt, tbtt_next);
    01552     }
    01553     else
    01554     {
    01555         // next TBTT on the other channel, prepare just one switch
    01556         uint32_t switch_date = tbtt_next->time - CHAN_SWITCH_DELAY;
    01557
    01558         #if (NX_P2P_GO)
    01559         if (ctxt->p2pgo_vif_index != INVALID_VIF_IDX)
    01560         {
    01561             chan_schedule_switch_from_p2pgo_ctxt(ctxt->p2pgo_vif_index,
    01562                                                  vif_next->chan_ctxt,
    01563                                                  now, &switch_date);
    01564         }
    01565         else if (vif->tbtt_switch.p2p_noa_vif_index != INVALID_VIF_IDX)
    01566         {
    01567             chan_schedule_switch_to_p2pgo_ctxt(vif->tbtt_switch.p2p_noa_vif_index,
    01568                                                ctxt, now, &switch_date);
    01569         }
    01570         else
    01571         #endif // (NX_P2P_GO)
    01572         {
    01573             switch_date = chan_share_medium(dur_to_split, tbtt_dur, now);
    01574         }
    01575
    01576         chan_schedule_one_switch(switch_date, vif_next->chan_ctxt, tbtt_next);
    01577     }
    01578 }
    01579
    01585 static void chan_cancel_all_switch(void)
    01586 {
    01587     struct chan_switch_tag *ch_switch;
    01588
    01589     ch_switch = chan_switch_pop();
    01590     if (ch_switch)
    01591     {
    01592         chan_switch_reset_timer();
    01593         while (ch_switch)
    01594         {
    01595             chan_switch_free(ch_switch);
    01596             ch_switch = chan_switch_pop();
    01597         }
    01598     }
    01599 }
    01600
    01622 static void chan_fix_ctxt_until(struct chan_ctxt_tag *ctxt)
    01623 {
    01624     struct chan_tbtt_tag *tbtt;
    01625     uint32_t time = hal_machw_time() + ctxt->duration_us;
    01626
    01627     if (ctxt != chan_env.current_ctxt)
    01628         time += CHAN_SWITCH_DELAY;
    01629
    01630     chan_env.fix_ctxt = ctxt;
    01631     chan_env.fix_until = time;
    01632
    01633     if (chan_env.nb_active_tbtt)
    01634     {
    01635         TRACE_CHAN(SWITCH, "Delay fixed channel while in TBTT window");
    01636         chan_env.status |= CO_BIT(CHAN_ENV_FIX_CTXT_PENDING_BIT);
    01637         return;
    01638     }
    01639     TRACE_CHAN(SWITCH, "Fix {CTXT-%d} until %t", ctxt->idx, TR_32(time));
    01640
    01641     chan_env.status &= ~CO_BIT(CHAN_ENV_FIX_CTXT_PENDING_BIT);
    01642     chan_cancel_all_switch();
    01643     chan_schedule_one_switch(time, NULL, NULL);
    01644
    01645     // Need to delay all TBTT already scheduled before the end of the fixed period
    01646     tbtt = chan_tbtt_pick();
    01647     if (tbtt)
    01648     {
    01649         while (tbtt && hal_machw_time_cmp(tbtt->time, time + CHAN_SWITCH_DELAY))
    01650         {
    01651             struct vif_info_tag *vif = &vif_info_tab[tbtt->vif_index];
    01652             chan_add_next_tbtt(vif, tbtt->time + chan_vif_tbtt_intv(vif), 0);
    01653             tbtt = chan_tbtt_pick();
    01654         }
    01655     }
    01656
    01657     if (!chan_env.switch_ctxt)
    01658     {
    01659         chan_switch_start(ctxt);
    01660     }
    01661     else
    01662     {
    01663         ASSERT_ERR(chan_env.status & CHAN_ROC_SCAN_PENDING_MASK);
    01664     }
    01665 }
    01666
    01675 static void chan_conn_less_delay_evt(void *env)
    01676 {
    01677     struct chan_ctxt_tag *ctxt = NULL;
    01678     TRACE_CHAN(CON_LESS, "{CON-LESS} delay timer expired. status = %x", chan_env.status);
    01679
    01680     // In waiting, start RoC in priority
    01681     if (chan_env.status & CO_BIT(CHAN_ENV_ROC_WAIT_BIT))
    01682     {
    01683         // Sanity check, no RoC should be in progress here
    01684         ASSERT_ERR((chan_env.status & CO_BIT(CHAN_ENV_ROC_BIT)) == 0);
    01685
    01686         // Update status
    01687         chan_env.status &= ~CO_BIT(CHAN_ENV_ROC_WAIT_BIT);
    01688         chan_env.status |= CO_BIT(CHAN_ENV_ROC_BIT);
    01689         ctxt = &chan_ctxt_pool[CHAN_ROC_CTXT_IDX];
    01690     }
    01691     // else start Scan
    01692     else if (chan_env.status & CO_BIT(CHAN_ENV_SCAN_WAIT_BIT))
    01693     {
    01694         // Sanity check, no Scan should be in progress here
    01695         ASSERT_ERR((chan_env.status & CO_BIT(CHAN_ENV_SCAN_BIT)) == 0);
    01696
    01697         // Update status
    01698         chan_env.status &= ~CO_BIT(CHAN_ENV_SCAN_WAIT_BIT);
    01699         chan_env.status |= CO_BIT(CHAN_ENV_SCAN_BIT);
    01700         ctxt = &chan_ctxt_pool[CHAN_SCAN_CTXT_IDX];
    01701     }
    01702     else
    01703     {
    01704         ASSERT_WARN("No SCAN/ROC pending");
    01705         return;
    01706     }
    01707
    01708     chan_fix_ctxt_until(ctxt);
    01709 }
    01710
    01717 static void chan_conn_less_delay_prog(void)
    01718 {
    01719     TRACE_CHAN(CON_LESS, "{CON-LESS} Start delay timer. status = %x", chan_env.status);
    01720
    01721     if (chan_env.status & CO_BIT(CHAN_ENV_DELAY_PROG_BIT))
    01722         return;
    01723
    01724     chan_env.status |= CO_BIT(CHAN_ENV_DELAY_PROG_BIT);
    01725
    01726     if (chan_env.nb_sched_ctxt)
    01727     {
    01728         mm_timer_set(&chan_env.tmr_conn_less, ke_time() + CHAN_CONN_LESS_DELAY);
    01729     }
    01730     else
    01731     {
    01732         chan_conn_less_delay_evt(NULL);
    01733     }
    01734 }
    01735
    01748 static void chan_conn_less_ctxt_end(struct chan_ctxt_tag *ctxt)
    01749 {
    01750     chan_env.current_ctxt = NULL;
    01751
    01752     #if (NX_POWERSAVE)
    01753     GLOBAL_INT_DISABLE();
    01754     ps_env.prevent_sleep &= ~PS_SCAN_ONGOING;
    01755     GLOBAL_INT_RESTORE();
    01756     nxmac_pwr_mgt_setf(chan_env.pm);
    01757     #endif //(NX_POWERSAVE)
    01758
    01759     if (ctxt->idx == CHAN_SCAN_CTXT_IDX)
    01760     {
    01761         chan_env.status &= ~CO_BIT(CHAN_ENV_SCAN_BIT);
    01762         #if (NX_HW_SCAN)
    01763         chan_send_survey_ind();
    01764         #endif //(NX_HW_SCAN)
    01765         ke_msg_send_basic(MM_SCAN_CHANNEL_END_IND, TASK_SCAN, TASK_NONE);
    01766     }
    01767     else if (ctxt->idx == CHAN_ROC_CTXT_IDX)
    01768     {
    01769         chan_env.status &= ~CO_BIT(CHAN_ENV_ROC_BIT);
    01770
    01771         if (ctxt->taskid != TASK_MM)
    01772         {
    01773             #if NX_UMAC_PRESENT && NX_TDLS
    01774             if (ctxt->taskid == TASK_TDLS)
    01775             {
    01776                 tdls_send_chan_switch_base_ind(ctxt);
    01777             }
    01778             else
    01779             #endif //NX_UMAC_PRESENT && NX_TDLS
    01780             {
    01781                 chan_send_roc_exp_ind(ctxt);
    01782             }
    01783         }
    01784         else
    01785         {
    01786             chan_env.status &= ~CO_BIT(CHAN_ENV_BCN_DETECT_BIT);
    01787         }
    01788     }
    01789
    01790     ctxt->idx = CHAN_CTXT_UNUSED;
    01791     chan_env.status &= ~CO_BIT(CHAN_ENV_DELAY_PROG_BIT);
    01792
    01793     if (chan_env.status & (CO_BIT(CHAN_ENV_ROC_WAIT_BIT) | CO_BIT(CHAN_ENV_SCAN_WAIT_BIT)))
    01794     {
    01795         chan_conn_less_delay_prog();
    01796     }
    01797
    01798     if (!chan_env.switch_ctxt)
    01799     {
    01800         mm_force_idle_req();
    01801         mm_back_to_host_idle();
    01802     }
    01803 }
    01804
    01817 static struct chan_ctxt_tag *chan_fix_ctxt_end(void)
    01818 {
    01819     chan_env.fix_ctxt = NULL;
    01820
    01821     if (chan_env.nb_sched_ctxt == 0)
    01822     {
    01823         return NULL;
    01824     }
    01825     else if (chan_env.nb_sched_ctxt == 1)
    01826     {
    01827         return chan_get_first_traf_ctxt();
    01828     }
    01829     else
    01830     {
    01831         struct chan_tbtt_tag *tbtt = chan_tbtt_pick();
    01832         if (!tbtt)
    01833         {
    01834             return chan_get_first_traf_ctxt();
    01835         }
    01836         else
    01837         {
    01838             return vif_info_tab[tbtt->vif_index].chan_ctxt;
    01839         }
    01840     }
    01841 }
    01842
    01856 static void chan_tmr_switch_cb(void *env)
    01857 {
    01858     struct chan_switch_tag *ch_switch = chan_switch_pop();
    01859     ASSERT_ERR((void *)ch_switch == env);
    01860     ASSERT_ERR(chan_env.current_ctxt);
    01861
    01862     chan_upd_ctxt_status(chan_env.current_ctxt, CHAN_NOT_PROG);
    01863
    01864     if (chan_env.fix_ctxt)
    01865         ch_switch->ctxt = chan_fix_ctxt_end();
    01866
    01867     if (ch_switch->ctxt)
    01868         chan_switch_start(ch_switch->ctxt);
    01869
    01870     chan_switch_free(ch_switch);
    01871
    01872     if (chan_env.current_ctxt->idx >= CHAN_TRAF_CTXT_CNT)
    01873         chan_conn_less_ctxt_end(chan_env.current_ctxt);
    01874
    01875     chan_switch_set_timer(chan_switch_pick());
    01876 }
    01877
    01885 static void chan_pre_switch_channel(void)
    01886 {
    01887     struct chan_ctxt_tag *new_ctxt = NULL;
    01888
    01889     if (chan_env.status & CO_BIT(CHAN_ENV_SCAN_BIT))
    01890     {
    01891         // If a Scan Request is pending, jump on Scan channel
    01892         new_ctxt = &chan_ctxt_pool[CHAN_SCAN_CTXT_IDX];
    01893     }
    01894     else if (chan_env.status & CO_BIT(CHAN_ENV_ROC_BIT))
    01895     {
    01896         // If a RoC Request is pending, jump on RoC Channel
    01897         new_ctxt = &chan_ctxt_pool[CHAN_ROC_CTXT_IDX];
    01898     }
    01899
    01900     if (new_ctxt && (new_ctxt != chan_env.switch_ctxt))
    01901     {
    01902        if (chan_env.switch_ctxt)
    01903        {
    01904            chan_upd_ctxt_status(chan_env.switch_ctxt, CHAN_NOT_PROG);
    01905        }
    01906        chan_env.switch_ctxt = new_ctxt;
    01907     }
    01908
    01909     if (chan_env.switch_ctxt == NULL)
    01910     {
    01911         TRACE_CHAN(ERR, "No ctxt scheduled in chan_pre_switch_channel");
    01912         return;
    01913     }
    01914
    01915     // Finally go on new channel
    01916     chan_switch_channel();
    01917 }
    01918
    01931 static void chan_tx_cfm(void *dummy, uint32_t status)
    01932 {
    01933     TRACE_CHAN(NOA, "absence notification confirmed status=%lx (remains %d)",
    01934                TR_32(status), chan_env.cfm_cnt - 1);
    01935
    01936     // Sanity check - We shall be waiting for at least 1 TX confirmation
    01937     ASSERT_ERR(chan_env.cfm_cnt);
    01938     chan_env.cfm_cnt--;
    01939
    01940     // Check if all confirmations have been received
    01941     if (chan_env.cfm_cnt == 0)
    01942     {
    01943         // Request to go to IDLE again, so that we can perform the channel switch
    01944         mm_force_idle_req();
    01945         chan_pre_switch_channel();
    01946     }
    01947 }
    01948
    01955 static void chan_notify_presence(void)
    01956 {
    01957     struct vif_info_tag *vif = vif_mgmt_first_used();
    01958     struct chan_ctxt_tag *cur_ctxt = chan_env.current_ctxt;
    01959
    01960     #if NX_MAC_HE
    01961     // Restart the HE TB operation
    01962     txl_he_tb_enable();
    01963     #endif
    01964
    01965     #if (NX_POWERSAVE)
    01966     if ((ps_env.ps_on) && !(ps_env.prevent_sleep & PS_PSM_PAUSED))
    01967     {
    01968         // STA VIFs are not active, so no need to indicate our presence
    01969         return;
    01970     }
    01971     #endif //(NX_POWERSAVE)
    01972
    01973     // Reset the PwrMgt bit in all frames
    01974     nxmac_pwr_mgt_setf(0);
    01975
    01976     // Go through all the active VIFs
    01977     while (vif != NULL)
    01978     {
    01979         if (vif->chan_ctxt == cur_ctxt)
    01980         {
    01981             if ((vif->type == VIF_STA) && vif->active)
    01982             {
    01983                 #if (NX_P2P)
    01984                 bool send = true;
    01985
    01986                 // If VIF is for P2P, check that GO is present
    01987                 if (vif->p2p)
    01988                 {
    01989                     send = p2p_info_tab[vif->p2p_index].is_go_present;
    01990                 }
    01991
    01992                 if (send)
    01993                 #endif //(NX_P2P)
    01994                 {
    01995                     // Send a NULL frame to indicate the AP we are back on the channel
    01996                     txl_frame_send_null_frame(vif->u.sta.ap_id, NULL, NULL);
    01997                     TRACE_CHAN(NOA, "{VIF-%d} presence notification sent", vif->index);
    01998                 }
    01999             }
    02000         }
    02001
    02002         vif = vif_mgmt_next(vif);
    02003     }
    02004 }
    02005
    02014 static int chan_notify_absence(void)
    02015 {
    02016     int cfm_cnt = 0;
    02017     struct vif_info_tag *vif = vif_mgmt_first_used();
    02018     struct chan_ctxt_tag *cur_ctxt;
    02019     uint8_t prev_status;
    02020
    02021     #if NX_MAC_HE
    02022     // Stop the HE TB operation
    02023     txl_he_tb_disable();
    02024     #endif
    02025
    02026     if (chan_env.current_ctxt == NULL)
    02027     {
    02028         return 0;
    02029     }
    02030
    02031     cur_ctxt = chan_env.current_ctxt;
    02032
    02033     #if (NX_POWERSAVE)
    02034     if ((ps_env.ps_on) && !(ps_env.prevent_sleep & PS_PSM_PAUSED))
    02035     {
    02036         // STA VIFs are already in PS-mode, so no need to indicate our absence
    02037         return 0;
    02038     }
    02039     #endif //(NX_POWERSAVE)
    02040
    02041
    02042     // Set the PwrMgt bit in all frames
    02043     nxmac_pwr_mgt_setf(1);
    02044
    02045     // Go through all the active VIFs
    02046     while (vif != NULL)
    02047     {
    02048         if (vif->chan_ctxt == cur_ctxt)
    02049         {
    02050             if ((vif->type == VIF_STA) && vif->active &&
    02051                 (vif->u.sta.ap_id != INVALID_STA_IDX))
    02052             {
    02053                 #if (NX_P2P)
    02054                 bool send = true;
    02055
    02056                 // If VIF is for P2P, check that GO is present
    02057                 if (vif->p2p)
    02058                 {
    02059                     send = p2p_info_tab[vif->p2p_index].is_go_present;
    02060                 }
    02061
    02062                 if (send)
    02063                 #endif //(NX_P2P)
    02064                 {
    02065                     // Send a NULL frame to indicate to the AP that we are leaving the
    02066                     // channel and update status to allow frame transmission.
    02067                     prev_status = cur_ctxt->status;
    02068                     cur_ctxt->status = CHAN_SENDING_NOA;
    02069                     if (txl_frame_send_null_frame(vif->u.sta.ap_id, chan_tx_cfm, NULL) == CO_OK)
    02070                     {
    02071                         cfm_cnt++;
    02072                     }
    02073                     TRACE_CHAN(NOA, "{VIF-%d} absence notification sent", vif->index);
    02074                     cur_ctxt->status = prev_status;
    02075                 }
    02076             }
    02077         }
    02078
    02079         vif = vif_mgmt_next(vif);
    02080     }
    02081
    02082     // Save the number of TX confirmation expected
    02083     chan_env.cfm_cnt = cfm_cnt;
    02084
    02085     if (cfm_cnt)
    02086     {
    02087         chan_upd_ctxt_status(chan_env.switch_ctxt, CHAN_WAIT_NOA_CFM);
    02088         // NULL frames programmed, we need to reactivate the HW
    02089         mm_active();
    02090     }
    02091
    02092     return (cfm_cnt);
    02093 }
    02094
    02101 static void chan_goto_idle_cb(void)
    02102 {
    02103     TRACE_CHAN(SWITCH, "HW entered idle state");
    02104
    02105     // Flush all the TX and RX queues
    02106     mm_force_idle_req();
    02107
    02108     // Check if we need to notify the absence of the local VIFs to the peers
    02109     if (chan_notify_absence())
    02110         return;
    02111
    02112     // Switch on a new channel
    02113     chan_pre_switch_channel();
    02114 }
    02115
    02122 static void chan_send_force_idle(void)
    02123 {
    02124     struct mm_force_idle_req *req = KE_MSG_ALLOC(MM_FORCE_IDLE_REQ,
    02125                                                  TASK_MM, TASK_NONE,
    02126                                                  mm_force_idle_req);
    02127
    02128     req->cb = chan_goto_idle_cb;
    02129
    02130     ke_msg_send(req);
    02131 }
    02132
    02141 static void chan_switch_channel(void)
    02142 {
    02143     struct chan_ctxt_tag *ctxt = chan_env.switch_ctxt;
    02144     struct mac_chan_op *chan = &ctxt->channel;
    02145
    02146     PROF_CHAN_CTXT_SWITCH_CLR();
    02147     PROF_MM_SET_CHANNEL_SET();
    02148
    02149     TRACE_CHAN(INF, "{CTXT-%d} switch to channel freq=%dMHz bw=%dMHz", ctxt->idx,
    02150                chan->prim20_freq, (1 <<  chan->type) * 20);
    02151
    02152     // Program the RF with the new channel
    02153     phy_set_channel(chan, PHY_PRIM);
    02154     tpc_update_tx_power(chan->tx_power);
    02155
    02156     PROF_MM_SET_CHANNEL_CLR();
    02157     PROF_CHAN_CTXT_IDX_SET(ctxt->idx);
    02158
    02159     // Set the basic rates in the HW according to the band
    02160     nxmac_rates_set(mm_env.basic_rates[chan->band]);
    02161
    02162     // Indicate to the upper layers that a channel switch has occurred
    02163     chan_send_switch_ind(ctxt);
    02164
    02165     if (chan_env.current_ctxt)
    02166         chan_upd_ctxt_status(chan_env.current_ctxt, CHAN_NOT_PROG);
    02167
    02168     // Store the current channel to the environment
    02169     chan_env.current_ctxt = ctxt;
    02170     // Channel switch is now complete
    02171     chan_env.switch_ctxt = NULL;
    02172
    02173     chan_upd_ctxt_status(ctxt, CHAN_WAITING_END);
    02174
    02175     // Check if we switch to an operating channel (Traffic or RoC), or a scanning one
    02176     if (ctxt->idx != CHAN_SCAN_CTXT_IDX)
    02177     {
    02178         if (ctxt->idx != CHAN_ROC_CTXT_IDX)
    02179         {
    02180             // Notify to the peer devices that we are back
    02181             chan_notify_presence();
    02182         }
    02183
    02184         if (ctxt->idx < CHAN_TRAF_CTXT_CNT)
    02185         {
    02186             struct vif_info_tag *vif = vif_mgmt_first_used();
    02187
    02188             while (vif)
    02189             {
    02190                 if (vif->chan_ctxt == ctxt)
    02191                 {
    02192                     #if (NX_TD)
    02193                     // Keep in mind that we have been present on the traffic channel
    02194                     td_env_tab[vif->index].has_active_chan = true;
    02195                     #endif //(NX_TD)
    02196
    02197                     vif_mgmt_send_postponed_frame(vif);
    02198                 }
    02199
    02200                 vif = (struct vif_info_tag *)co_list_next(&vif->list_hdr);
    02201             }
    02202
    02203             #if (!NX_UMAC_PRESENT)
    02204             if (ctxt->taskid != TASK_NONE)
    02205             {
    02206                 // Inform the host as required
    02207                 ke_msg_send_basic(MM_CHAN_CTXT_SCHED_CFM, ctxt->taskid, TASK_MM);
    02208                 ctxt->taskid = TASK_NONE;
    02209             }
    02210             #endif //(!NX_UMAC_PRESENT)
    02211         }
    02212     }
    02213     else
    02214     {
    02215         // Clear CCA busy register (see MM_CHANNEL_SURVEY_IND use)
    02216         nxmac_edca_cca_busy_set(0);
    02217
    02218         // Confirm the channel switch to the scanning module
    02219         ke_msg_send_basic(MM_SCAN_CHANNEL_START_IND, TASK_SCAN, TASK_NONE);
    02220     }
    02221
    02222     #if (NX_POWERSAVE)
    02223     if (ctxt->idx >= CHAN_SCAN_CTXT_IDX)
    02224     {
    02225         // Disable PS while we are scanning
    02226         GLOBAL_INT_DISABLE();
    02227         ps_env.prevent_sleep |= PS_SCAN_ONGOING;
    02228         GLOBAL_INT_RESTORE();
    02229
    02230         // No PM bit set in ProbeReq
    02231         chan_env.pm = nxmac_pwr_mgt_getf();
    02232         nxmac_pwr_mgt_setf(0);
    02233     }
    02234     #endif //(NX_POWERSAVE)
    02235
    02236     // Go to active state
    02237     mm_active();
    02238 }
    02239
    02250 static void chan_switch_start(struct chan_ctxt_tag *ctxt)
    02251 {
    02252     TRACE_CHAN(SWITCH, "{CTXT-%d} Start switch", ctxt->idx);
    02253
    02254     if (chan_env.switch_ctxt)
    02255     {
    02256         TRACE_CHAN(SWITCH, "Switch to {CTXT-%d} replaced by switch to {CTXT-%d}",
    02257                    chan_env.switch_ctxt->idx, ctxt->idx);
    02258         chan_env.switch_ctxt = ctxt;
    02259         return;
    02260     }
    02261
    02262     if (chan_env.current_ctxt == ctxt)
    02263     {
    02264         TRACE_CHAN(SWITCH, "skip: already current channel");
    02265         chan_upd_ctxt_status(chan_env.current_ctxt, CHAN_WAITING_END);
    02266         return;
    02267     }
    02268
    02269     PROF_CHAN_CTXT_WAIT_END_CLR();
    02270
    02271     if (chan_env.current_ctxt)
    02272     {
    02273         // Indicate to the upper layers that a channel switch will occur soon
    02274         chan_send_pre_switch_ind(chan_env.current_ctxt);
    02275     }
    02276
    02277     #if NX_BCN_AUTONOMOUS_TX
    02278     if (mm_bcn_transmitting())
    02279     {
    02280         TRACE_CHAN(ERR, "Channel switch while beacon are being transmitted");
    02281         GLOBAL_INT_DISABLE();
    02282         txl_cntrl_halt_ac(AC_BCN);
    02283         txl_cntrl_flush_ac(AC_BCN, DESC_DONE_SW_TX_BIT);
    02284         GLOBAL_INT_RESTORE();
    02285     }
    02286     #endif //NX_BCN_AUTONOMOUS_TX
    02287
    02288     chan_env.switch_ctxt = ctxt;
    02289     chan_upd_ctxt_status(ctxt, CHAN_GOTO_IDLE);
    02290     chan_send_force_idle();
    02291 }
    02292
    02293 #if (NX_UMAC_PRESENT)
    02294
    02312 static bool chan_check_chan(struct mac_chan_op const *chan_req, uint8_t *idx)
    02313 {
    02314     bool found = false;
    02315
    02316     for (int ctxt_idx = 0; ctxt_idx < CHAN_TRAF_CTXT_CNT; ctxt_idx++)
    02317     {
    02318         struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[ctxt_idx];
    02319         struct mac_chan_op *chan;
    02320
    02321         // Only consider added channel contexts
    02322         if (ctxt->idx == CHAN_CTXT_UNUSED)
    02323             continue;
    02324
    02325         chan = &ctxt->channel;
    02326
    02327         if ((chan->band == chan_req->band) &&
    02328             (chan->prim20_freq == chan_req->prim20_freq))
    02329         {
    02330             if ((chan->type == chan_req->type) &&
    02331                 ((chan->center1_freq == chan_req->center1_freq) &&
    02332                  (chan->center2_freq == chan_req->center2_freq)))
    02333             {
    02334                 // Exact same configuration
    02335                 *idx = ctxt_idx;
    02336                 found = true;
    02337                 break;
    02338             }
    02339             else if ((chan->type < chan_req->type) &&
    02340                      (chan->type != PHY_CHNL_BW_160))
    02341             {
    02342                 // Requested channel configuration "include" current configuration.
    02343                 // Update current configuration.
    02344                 chan->type = chan_req->type;
    02345                 chan->center1_freq = chan_req->center1_freq;
    02346                 chan->center2_freq = chan_req->center2_freq;
    02347
    02348                 TRACE_CHAN(CREATE, "{CTXT-%d} Update channel config freq=%dMHz bw=%dMHz",
    02349                            ctxt->idx, chan->prim20_freq, (1 <<  chan->type) * 20);
    02350
    02351                 // Need to re-configure now if there is only one channel context active
    02352                 if ((chan_env.current_ctxt == ctxt) &&
    02353                     (chan_env.nb_sched_ctxt == 1))
    02354                 {
    02355                     phy_set_channel(chan, PHY_PRIM);
    02356                 }
    02357
    02358                 *idx = ctxt_idx;
    02359                 found = true;
    02360                 break;
    02361             }
    02362             else if ((chan->type > chan_req->type) &&
    02363                      (chan_req->type != PHY_CHNL_BW_160))
    02364             {
    02365                 // Requested channel configuration is included in current configuration
    02366                 *idx = ctxt_idx;
    02367                 found = true;
    02368                 break;
    02369             }
    02370         }
    02371     }
    02372
    02373     return (found);
    02374 }
    02375 #endif //(NX_UMAC_PRESENT)
    02376
    02377
    02378 #if (NX_P2P_GO && NX_BEACONING)
    02379
    02393 static void chan_p2p_noa_resync(struct vif_info_tag *vif)
    02394 {
    02395     vif->tbtt_switch.p2p_noa_tsf_update = mm_ap_tbtt_move(vif->tbtt_switch.p2p_noa_tsf_update);
    02396     p2p_go_noa_concurrent_move(vif, vif->tbtt_switch.p2p_noa_tsf_update);
    02397     vif->tbtt_switch.status &= ~(CHAN_TBTT_P2P_NOA_RESYNC);
    02398     vif->tbtt_switch.status |= CHAN_TBTT_P2P_NOA_TSF_UPDATE;
    02399 }
    02400
    02416 static void chan_p2p_noa_tsf_updated(struct vif_info_tag *vif)
    02417 {
    02418     struct chan_tbtt_tag *tbtt = &vif->tbtt_switch;
    02419
    02420     mm_timer_set(&vif->tbtt_timer, vif->tbtt_timer.time + tbtt->p2p_noa_tsf_update);
    02421
    02422     tbtt->status &= ~(CHAN_TBTT_P2P_NOA_TSF_UPDATE);
    02423     if (tbtt->status & CHAN_TBTT_PROG)
    02424     {
    02425         struct chan_switch_tag *ch_switch = chan_switch_last();
    02426         if (ch_switch && (ch_switch->tbtt == tbtt))
    02427         {
    02428             chan_cancel_all_switch();
    02429             chan_add_next_tbtt(vif, vif->tbtt_timer.time, 0);
    02430             chan_schedule_next_switch(vif, hal_machw_time(), 0);
    02431         }
    02432         else
    02433         {
    02434             chan_add_next_tbtt(vif, vif->tbtt_timer.time, 0);
    02435         }
    02436     }
    02437 }
    02438
    02457 static void chan_p2p_noa_resync_check(struct vif_info_tag *vif, uint32_t tbtt_time)
    02458 {
    02459     struct chan_tbtt_tag *tbtt = &vif->tbtt_switch;
    02460     struct vif_info_tag *p2pgo_vif;
    02461     uint32_t tbtt_to_end;
    02462
    02463     p2pgo_vif = &vif_info_tab[tbtt->p2p_noa_vif_index];
    02464
    02465     if (p2pgo_vif->tbtt_switch.status & (CHAN_TBTT_P2P_NOA_TSF_UPDATE |
    02466                                          CHAN_TBTT_P2P_NOA_RESYNC))
    02467         return;
    02468
    02469     tbtt_to_end = (p2p_go_get_next_noa_end_date(p2pgo_vif, tbtt->p2p_noa_index) -
    02470                    tbtt_time);
    02471     tbtt->p2p_noa_drift = tbtt->p2p_noa_tbtt_to_end - tbtt_to_end;
    02472
    02473     if (co_abs(tbtt->p2p_noa_drift) > CHAN_P2P_NOA_RESCHEDULE_THRESHOLD)
    02474     {
    02475         // For some reason we were not able to resync NOA, so simply reschedule them
    02476         // on next TBTT of P2P GO interface
    02477         p2pgo_vif->tbtt_switch.status &= ~(CHAN_TBTT_P2P_NOA_RESYNC);
    02478         p2pgo_vif->tbtt_switch.status |= CHAN_TBTT_SCHEDULE_P2P_NOA;
    02479     }
    02480     else if (co_abs(tbtt->p2p_noa_drift) > CHAN_P2P_NOA_RESYNC_THRESHOLD)
    02481     {
    02482         int16_t min = 0, max = 0;
    02483         struct vif_info_tag *_vif;
    02484         _vif = vif_mgmt_first_used();
    02485         while (_vif)
    02486         {
    02487             if (_vif->tbtt_switch.p2p_noa_vif_index == p2pgo_vif->index)
    02488             {
    02489                 if (_vif->tbtt_switch.p2p_noa_drift < min)
    02490                     min = _vif->tbtt_switch.p2p_noa_drift;
    02491                 if (_vif->tbtt_switch.p2p_noa_drift > max)
    02492                     max = _vif->tbtt_switch.p2p_noa_drift;
    02493             }
    02494             _vif = vif_mgmt_next(_vif);
    02495         }
    02496
    02497         if ((min >= 0 && max >= 0) ||
    02498             (min <= 0 && max <= 0))
    02499         {
    02500             p2pgo_vif->tbtt_switch.status |= CHAN_TBTT_P2P_NOA_RESYNC;
    02501             p2pgo_vif->tbtt_switch.p2p_noa_tsf_update = (min + max) / 2;
    02502         }
    02503     }
    02504 }
    02505
    02506 #endif //(NX_P2P_GO && NX_BEACONING)
    02507
    02513 static void chan_reset_tbtt_list(void)
    02514 {
    02515     int i;
    02516     co_list_init(&chan_env.list_tbtt);
    02517
    02518     for (i = 0 ; i < NX_VIRT_DEV_MAX; i++) {
    02519         struct vif_info_tag *vif = &vif_info_tab[i];
    02520         vif->tbtt_switch.status &= ~(CHAN_TBTT_PROG);
    02521     }
    02522 }
    02523
    02531 static void chan_ctxt_init(struct chan_ctxt_tag *ctxt)
    02532 {
    02533     memset(ctxt, 0, sizeof(struct chan_ctxt_tag));
    02534
    02535     ctxt->taskid = TASK_NONE;
    02536     ctxt->idx    = CHAN_CTXT_UNUSED;
    02537     #if (NX_P2P)
    02538     ctxt->p2pgo_vif_index = INVALID_VIF_IDX;
    02539     #endif //(NX_P2P)
    02540 }
    02541
    02542 /*
    02543  * PUBLIC FUNCTIONS DEFINITION
    02544  ****************************************************************************************
    02545  */
    02546 void chan_init(void)
    02547 {
    02548     memset(&chan_env, 0, sizeof(chan_env));
    02549
    02550     // Initialize the free channel context list
    02551     for (int i = 0; i < CHAN_CHAN_CTXT_CNT; i++)
    02552     {
    02553         struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[i];
    02554
    02555         chan_ctxt_init(ctxt);
    02556
    02557         if (i < NX_CHAN_CTXT_CNT)
    02558         {
    02559             // Add it to the free channel context list
    02560             co_list_push_back(&chan_env.list_free_ctxt, &ctxt->list_hdr);
    02561         }
    02562         else if (i == CHAN_SCAN_CTXT_IDX)
    02563         {
    02564             ctxt->channel.center2_freq = 0;
    02565             ctxt->channel.type = PHY_CHNL_BW_20;
    02566         }
    02567     }
    02568
    02569     co_list_init(&chan_env.list_free_switch);
    02570     co_list_init(&chan_env.list_switch);
    02571     for (int i = 0; i < CHAN_SWITCH_CNT; i++)
    02572     {
    02573         chan_switch_free(&chan_switch_pool[i]);
    02574     }
    02575
    02576     // Set Connection Less Delay Time callback
    02577     chan_env.tmr_conn_less.cb = chan_conn_less_delay_evt;
    02578     // Set Channel Switch Timer callback
    02579     chan_env.tmr_switch.cb = chan_tmr_switch_cb;
    02580     chan_env.tmr_switch.env = NULL;
    02581 }
    02582
    02583 #if (NX_HW_SCAN)
    02584 void chan_scan_req(uint8_t band, uint16_t freq, int8_t pwr, uint32_t duration_us,
    02585                    uint8_t flags, uint8_t vif_index)
    02586 {
    02587     struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[CHAN_SCAN_CTXT_IDX];
    02588
    02589     TRACE_CHAN(CON_LESS, "{VIF-%d} Start scan freq=%dMHz duration=%ldus pwr=%ddBm",
    02590                vif_index, freq, TR_32(duration_us), pwr);
    02591
    02592     ASSERT_ERR(ctxt->idx == CHAN_CTXT_UNUSED);
    02593
    02594     ctxt->idx                  = CHAN_SCAN_CTXT_IDX;
    02595     ctxt->taskid               = TASK_NONE;
    02596     ctxt->channel.band         = band;
    02597     ctxt->channel.center1_freq = freq;
    02598     ctxt->channel.prim20_freq  = freq;
    02599     ctxt->channel.tx_power     = pwr;
    02600     ctxt->channel.flags        = flags;
    02601     ctxt->vif_index            = vif_index;
    02602     ctxt->status               = CHAN_NOT_PROG;
    02603     ctxt->duration_us          = duration_us;
    02604
    02605     chan_env.status |= CO_BIT(CHAN_ENV_SCAN_WAIT_BIT);
    02606
    02607     // Check if we can start the Connection Less Delay Timer
    02608     if (!(chan_env.status & CO_BIT(CHAN_ENV_DELAY_PROG_BIT)))
    02609     {
    02610         chan_conn_less_delay_prog();
    02611     }
    02612 }
    02613 #endif //(NX_HW_SCAN)
    02614
    02615 uint8_t chan_roc_req(struct mm_remain_on_channel_req const *req, ke_task_id_t taskid)
    02616 {
    02617     uint8_t status = CO_FAIL;
    02618     struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[CHAN_ROC_CTXT_IDX];
    02619
    02620     TRACE_CHAN(CON_LESS, "ROC op=%d freq=%d MHz duration=%dms pwr=%ddBm",
    02621                req->op_code, req->chan.prim20_freq, req->duration_ms, req->chan.tx_power);
    02622
    02623     switch (req->op_code)
    02624     {
    02625         case (MM_ROC_OP_START):
    02626         {
    02627             // Check if a remain on channel is in progress
    02628             if (ctxt->idx != CHAN_CTXT_UNUSED)
    02629             {
    02630                 break;
    02631             }
    02632
    02633             ctxt->idx = CHAN_ROC_CTXT_IDX;
    02634             ctxt->channel = req->chan;
    02635             ctxt->taskid = taskid;
    02636             ctxt->status = CHAN_NOT_PROG;
    02637             ctxt->duration_us = (req->duration_ms * 1000);
    02638             ctxt->vif_index = req->vif_index;
    02639
    02640             // If internal RoC (use for beacon detection), do not delay
    02641             #if NX_UMAC_PRESENT && NX_TDLS
    02642             if ((taskid == TASK_MM) || (taskid == TASK_TDLS))
    02643             #else
    02644             if (taskid == TASK_MM)
    02645             #endif
    02646             {
    02647                 chan_env.status |= CO_BIT(CHAN_ENV_ROC_BIT);
    02648                 #if NX_UMAC_PRESENT && NX_TDLS
    02649                 if (taskid == TASK_TDLS)
    02650                 {
    02651                     ctxt->roc_tdls = true;
    02652                 }
    02653                 #endif
    02654
    02655                 chan_fix_ctxt_until(ctxt);
    02656             }
    02657             else
    02658             {
    02659                 chan_env.status |= CO_BIT(CHAN_ENV_ROC_WAIT_BIT);
    02660                 chan_conn_less_delay_prog();
    02661             }
    02662
    02663             status = CO_OK;
    02664         } break;
    02665
    02666         case (MM_ROC_OP_CANCEL):
    02667         {
    02668             // Check if a remain on channel context is used
    02669             if (ctxt->idx == CHAN_CTXT_UNUSED)
    02670             {
    02671                 status = CO_OK;
    02672                 break;
    02673             }
    02674
    02675             #if NX_UMAC_PRESENT && NX_TDLS
    02676             if (taskid == TASK_TDLS)
    02677             {
    02678                 ctxt->roc_tdls = false;
    02679             }
    02680             #endif
    02681
    02682             // React depending on the current context state
    02683             switch (ctxt->status)
    02684             {
    02685                 case (CHAN_NOT_PROG):
    02686                 {
    02687                     chan_env.status &= ~CO_BIT(CHAN_ENV_ROC_WAIT_BIT);
    02688
    02689                     #if NX_UMAC_PRESENT && NX_TDLS
    02690                     if (taskid == TASK_TDLS)
    02691                     {
    02692                         tdls_send_chan_switch_base_ind(ctxt);
    02693                     }
    02694                     else
    02695                     #endif
    02696                     {
    02697                         chan_send_roc_exp_ind(ctxt);
    02698                     }
    02699                 } break;
    02700
    02701                 case (CHAN_GOTO_IDLE):
    02702                 case (CHAN_WAIT_NOA_CFM):
    02703                 {
    02704                     chan_env.status &= ~CO_BIT(CHAN_ENV_ROC_BIT);
    02705                     chan_env.switch_ctxt = NULL;
    02706                 } break;
    02707
    02708                 case (CHAN_WAITING_END):
    02709                 {
    02710                     chan_switch_reset_timer();
    02711                     chan_tmr_switch_cb(chan_switch_pick());
    02712                 } break;
    02713
    02714                 default:
    02715                 {
    02716                 } break;
    02717             }
    02718
    02719             // Reset the index
    02720             ctxt->idx = CHAN_CTXT_UNUSED;
    02721
    02722             // Check if we have to stop the delay timer
    02723             if ((chan_env.status & CO_BIT(CHAN_ENV_DELAY_PROG_BIT)) &&
    02724                 ((chan_env.status & CO_BIT(CHAN_ENV_SCAN_WAIT_BIT)) == 0))
    02725             {
    02726                 chan_env.status &= ~CO_BIT(CHAN_ENV_DELAY_PROG_BIT);
    02727                 mm_timer_clear(&chan_env.tmr_conn_less);
    02728             }
    02729
    02730             status = CO_OK;
    02731         } break;
    02732
    02733         default:
    02734             break;
    02735     }
    02736
    02737     return (status);
    02738 }
    02739
    02740 uint8_t chan_ctxt_add(struct mac_chan_op const *chan_req, uint8_t *idx)
    02741 {
    02742     struct chan_ctxt_tag *ctxt;
    02743
    02744     #if (NX_UMAC_PRESENT)
    02745     // Check if a channel with the provided parameters as already been added
    02746     if (chan_check_chan(chan_req, idx))
    02747     {
    02748         // Channel already exists, allocation is successful
    02749         return CO_OK;
    02750     }
    02751     #endif //(NX_UMAC_PRESENT)
    02752
    02753     // Allocate a channel context from the list
    02754     ctxt = (struct chan_ctxt_tag *)co_list_pop_front(&chan_env.list_free_ctxt);
    02755     if (ctxt == NULL)
    02756     {
    02757         TRACE_CHAN(ERR, "No more channel context freq=%dMHz bw=%dMHz",
    02758                    chan_req->prim20_freq, (1 << chan_req->type) * 20 );
    02759         return CO_FAIL;
    02760     }
    02761
    02762     // Initialize the operating channel context structure
    02763     *idx = ctxt->idx = CO_GET_INDEX(ctxt, chan_ctxt_pool);
    02764     ctxt->channel = *chan_req;
    02765
    02766     TRACE_CHAN(CREATE, "{CTXT-%d} Create channel context: freq=%dMHz bw=%dMHz pwr=%ddBm",
    02767                *idx, chan_req->prim20_freq, (1 << chan_req->type) * 20,  chan_req->tx_power);
    02768
    02769     return CO_OK;
    02770 }
    02771
    02772 void chan_ctxt_del(uint8_t chan_idx)
    02773 {
    02774     struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[chan_idx];
    02775
    02776     TRACE_CHAN(CREATE, "{CTXT-%d} Delete channel context",  chan_idx);
    02777
    02778     // Sanity checks - An unused channel should not be freed
    02779     ASSERT_ERR(ctxt->idx != CHAN_CTXT_UNUSED);
    02780     // Sanity checks - No more VIFs should be linked with the channel
    02781     ASSERT_ERR(ctxt->nb_linked_vif == 0);
    02782
    02783     // Push back the channel context in the free list
    02784     co_list_push_back(&chan_env.list_free_ctxt, &ctxt->list_hdr);
    02785
    02786     // Reset channel context information
    02787     chan_ctxt_init(ctxt);
    02788 }
    02789
    02790 void chan_ctxt_link(uint8_t vif_idx, uint8_t ctxt_idx)
    02791 {
    02792     struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[ctxt_idx];
    02793     struct vif_info_tag *vif   = &vif_info_tab[vif_idx];
    02794
    02795     // Sanity checks
    02796     ASSERT_ERR(vif->chan_ctxt == NULL);
    02797     ASSERT_ERR(ctxt->idx != CHAN_CTXT_UNUSED);
    02798
    02799     TRACE_CHAN(CREATE, "{CTXT-%d} link to {VIF-%d}: status=%d nb_vif=%d",
    02800                ctxt_idx, vif_idx, ctxt->status, ctxt->nb_linked_vif);
    02801
    02802     // Channel context will now be linked to VIF
    02803     vif->chan_ctxt = ctxt;
    02804     vif->tbtt_switch.status = 0;
    02805
    02806     // Increase number of VIFs linked with the channel context
    02807     ctxt->nb_linked_vif++;
    02808
    02809     // Schedule the channel if first link
    02810     if (ctxt->nb_linked_vif == 1)
    02811     {
    02812         // Update channel status
    02813         ctxt->status = CHAN_NOT_PROG;
    02814
    02815         // Increase number of scheduled contexts
    02816         chan_env.nb_sched_ctxt++;
    02817         ASSERT_ERR(chan_env.nb_sched_ctxt <= 2);
    02818
    02819         if (chan_env.nb_sched_ctxt == 2)
    02820         {
    02821             chan_reset_tbtt_list();
    02822         }
    02823
    02824         // Insert the context in the list of scheduled contexts
    02825         co_list_push_back(&chan_env.list_sched_ctxt, &ctxt->list_hdr);
    02826
    02827         // Switch to this new channel as soon as posible.
    02828         // Mandatory for STA in order to finish connection.
    02829         if (chan_env.status & CHAN_ROC_SCAN_PENDING_MASK)
    02830         {
    02831             struct chan_switch_tag *ch_switch = chan_switch_pick();
    02832             ASSERT_ERR(ch_switch);
    02833             ch_switch->ctxt = ctxt;
    02834         }
    02835         else if (chan_env.switch_ctxt)
    02836         {
    02837             chan_env.switch_ctxt = ctxt;
    02838         }
    02839         else
    02840         {
    02841             chan_switch_start(ctxt);
    02842         }
    02843     }
    02844
    02845     #if (NX_P2P_GO)
    02846     vif->tbtt_switch.p2p_noa_vif_index = INVALID_VIF_IDX;
    02847
    02848     if (chan_is_p2p_go(vif))
    02849     {
    02850         vif->tbtt_switch.status |= CHAN_TBTT_SCHEDULE_P2P_NOA;
    02851     }
    02852     else
    02853     {
    02854         struct vif_info_tag *p2pgo_vif;
    02855         if (chan_get_p2pgo(&p2pgo_vif) &&
    02856             (p2pgo_vif->chan_ctxt != ctxt))
    02857         {
    02858             // Cannot start NOA here as TBTT date is probably not known yet for this vif
    02859             vif->tbtt_switch.status |= CHAN_TBTT_SCHEDULE_P2P_NOA;
    02860         }
    02861
    02862     }
    02863
    02864     #endif //(NX_P2P_GO)
    02865
    02866     chan_update_tx_power(ctxt);
    02867
    02868     #if NX_MON_DATA
    02869     if (vif_mgmt_env.monitor_vif != vif_idx && vif_mgmt_env.monitor_vif != INVALID_STA_IDX)
    02870     {
    02871         chan_ctxt_link_monitor(ctxt_idx);
    02872     }
    02873     #endif
    02874 }
    02875
    02876 void chan_ctxt_unlink(uint8_t vif_idx)
    02877 {
    02878     struct vif_info_tag *vif = &vif_info_tab[vif_idx];
    02879     struct chan_ctxt_tag *ctxt = vif->chan_ctxt;
    02880
    02881     // Sanity checks
    02882     ASSERT_ERR(ctxt != NULL);
    02883     TRACE_CHAN(CREATE, "{CTXT-%d} unlink from {VIF-%d}: status=%d nb_vif=%d",
    02884                ctxt->idx, vif_idx, ctxt->status, ctxt->nb_linked_vif);
    02885
    02886     // Remove TBTT Switch element and reset status
    02887     chan_tbtt_remove(&vif->tbtt_switch);
    02888     if (vif->tbtt_switch.status & CHAN_TBTT_WAIT_TO)
    02889         chan_env.nb_active_tbtt--;
    02890     vif->tbtt_switch.status = 0;
    02891
    02892     // Channel context will now be linked to VIF
    02893     vif->chan_ctxt = NULL;
    02894     // Decrease number of VIFs linked with the channel context
    02895     ctxt->nb_linked_vif--;
    02896
    02897     if (ctxt->status != CHAN_NOT_SCHEDULED)
    02898     {
    02899         #if (NX_P2P_GO)
    02900         struct vif_info_tag *p2pgo_vif;
    02901
    02902         if (ctxt->p2pgo_vif_index == vif->index)
    02903         {
    02904             chan_stop_p2pgo_noa(vif);
    02905             ctxt->p2pgo_vif_index = INVALID_VIF_IDX;
    02906         }
    02907         else if (chan_get_p2pgo(&p2pgo_vif) &&
    02908                  (p2pgo_vif->chan_ctxt != ctxt))
    02909         {
    02910             if (ctxt->nb_linked_vif)
    02911                 chan_start_p2pgo_noa(p2pgo_vif);
    02912             else
    02913                 chan_stop_p2pgo_noa(p2pgo_vif);
    02914         }
    02915         #endif //(NX_P2P_GO)
    02916
    02917         // If no more VIFs are linked with the channel, unschedule it
    02918         if (!ctxt->nb_linked_vif)
    02919         {
    02920             co_list_extract(&chan_env.list_sched_ctxt, &ctxt->list_hdr);
    02921             chan_upd_ctxt_status(ctxt, CHAN_NOT_SCHEDULED);
    02922
    02923             // Decrease number of scheduled channels
    02924             chan_env.nb_sched_ctxt--;
    02925             ASSERT_ERR(chan_env.nb_sched_ctxt <= 1);
    02926
    02927             if (chan_env.nb_sched_ctxt)
    02928             {
    02929                 chan_reset_tbtt_list();
    02930                 if (!chan_env.fix_ctxt)
    02931                     chan_cancel_all_switch();
    02932             }
    02933
    02934             if (chan_env.current_ctxt == ctxt)
    02935             {
    02936                 chan_env.current_ctxt = NULL;
    02937
    02938                 if (chan_env.nb_sched_ctxt)
    02939                 {
    02940                     chan_switch_start(chan_get_next_traf_ctxt(ctxt));
    02941                 }
    02942             }
    02943             else if (chan_env.switch_ctxt == ctxt)
    02944             {
    02945                 chan_env.switch_ctxt = chan_get_next_traf_ctxt(ctxt);
    02946             }
    02947         }
    02948     }
    02949
    02950     #if (NX_UMAC_PRESENT)
    02951     if (ctxt->nb_linked_vif == 0)
    02952     {
    02953         chan_ctxt_del(ctxt->idx);
    02954     }
    02955     #endif //(NX_UMAC_PRESENT)
    02956
    02957     chan_update_tx_power(ctxt);
    02958 }
    02959
    02960 void chan_ctxt_update(struct mm_chan_ctxt_update_req const *upd_req)
    02961 {
    02962     struct chan_ctxt_tag *ctxt = &chan_ctxt_pool[upd_req->chan_index];
    02963     struct mac_chan_op const *chan = &upd_req->chan;
    02964
    02965     TRACE_CHAN(CREATE, "{CTXT-%d} update config: freq=%dMHz bw=%dMHz pwr=%ddBm",
    02966                upd_req->chan_index, chan->prim20_freq, (1 << chan->type) * 20,
    02967                chan->tx_power);
    02968
    02969     // Update the channel context
    02970     ctxt->channel = upd_req->chan;
    02971
    02972     if (chan_env.current_ctxt == ctxt)
    02973     {
    02974         // Handle the packets already in the RX queue to ensure that the channel info
    02975         // indicated to the upper MAC is correct. This has to be done with interrupts
    02976         // disabled, as the normal handling of the packets is done under interrupt.
    02977         GLOBAL_INT_DISABLE();
    02978         rxl_mpdu_isr();
    02979         rxl_cntrl_evt(0);
    02980         GLOBAL_INT_RESTORE();
    02981
    02982         PROF_MM_SET_CHANNEL_SET();
    02983
    02984         // Program the RF with the new channel
    02985         phy_set_channel(chan, PHY_PRIM);
    02986         tpc_update_tx_power(ctxt->channel.tx_power);
    02987
    02988         PROF_MM_SET_CHANNEL_CLR();
    02989     }
    02990 }
    02991
    02992 #if (!NX_UMAC_PRESENT)
    02993 void chan_ctxt_sched(struct mm_chan_ctxt_sched_req const *sched_req, ke_task_id_t taskid)
    02994 {
    02995     struct chan_ctxt_tag *ctxt;
    02996
    02997     TRACE_CHAN(SWITCH, "{CTXT-%d} schedule requested", sched_req->chan_index);
    02998
    02999     ctxt = &chan_ctxt_pool[sched_req->chan_index];
    03000
    03001     // Sanity check
    03002     ASSERT_ERR(ctxt->status != CHAN_NOT_SCHEDULED);
    03003
    03004     // Check if we already are on the channel
    03005     if (ctxt->status >= CHAN_WAITING_END)
    03006     {
    03007         // Send the confirmation immediately
    03008         ke_msg_send_basic(MM_CHAN_CTXT_SCHED_CFM, taskid, TASK_MM);
    03009     }
    03010     else
    03011     {
    03012         // Store the task id, CHAN_CTXT_SCHED_CFM will be sent next time we jump on the channel
    03013         ctxt->taskid = taskid;
    03014     }
    03015 }
    03016 #endif //(!NX_UMAC_PRESENT)
    03017
    03018 #if (NX_UMAC_PRESENT)
    03019 void chan_ctxt_link_monitor(uint8_t ctxt_idx)
    03020 {
    03021     struct vif_info_tag *vif = &vif_info_tab[vif_mgmt_env.monitor_vif];
    03022
    03023     // Check if monitor channel is already linked
    03024     if (vif->chan_ctxt)
    03025     {
    03026         // Unlink monitor channel
    03027         chan_ctxt_unlink(vif_mgmt_env.monitor_vif);
    03028     }
    03029     else
    03030     {
    03031         struct me_set_active_req *idle =  KE_MSG_ALLOC(ME_SET_ACTIVE_REQ, TASK_ME,
    03032                                                        TASK_ME, me_set_active_req);
    03033
    03034         idle->active = true;
    03035         idle->vif_idx = vif->index;
    03036         ke_msg_send(idle);
    03037     }
    03038
    03039     // Link monitor channel
    03040     chan_ctxt_link(vif_mgmt_env.monitor_vif, ctxt_idx);
    03041 }
    03042 #endif //(NX_UMAC_PRESENT)
    03043
    03044 int chan_tbtt_start(struct vif_info_tag *vif, uint32_t tbtt_time, uint32_t next_tbtt_time)
    03045 {
    03046     struct chan_tbtt_tag *tbtt = &vif->tbtt_switch;
    03047     struct chan_tbtt_tag *tbtt_scheduled = chan_tbtt_pick();
    03048     bool skip = (!tbtt_scheduled ||
    03049                  tbtt_scheduled->time != tbtt_time);
    03050     bool on_channel = (vif->chan_ctxt == chan_env.current_ctxt);
    03051
    03052
    03053     while (skip && tbtt_scheduled &&
    03054            hal_machw_time_cmp(tbtt_scheduled->time, tbtt_time))
    03055     {
    03056         chan_tbtt_remove(tbtt_scheduled);
    03057         TRACE_CHAN(ERR, "Drop next scheduled {VIF-%d} %t in the past",
    03058                    tbtt_scheduled->vif_index, TR_32(tbtt_scheduled->time));
    03059         tbtt_scheduled = chan_tbtt_pick();
    03060         skip = (!tbtt_scheduled ||
    03061                  tbtt_scheduled->time != tbtt_time);
    03062     }
    03063
    03064     TRACE_CHAN(TBTT, "{VIF-%d}{CTXT-%d} TBTT start skip_it=%d, current_ctxt=%d, tbtt_time=%t",
    03065                vif->index, vif->chan_ctxt->idx, skip,
    03066                chan_env.current_ctxt ? chan_env.current_ctxt->idx : -1, TR_32(tbtt_time));
    03067
    03068     if (chan_env.nb_sched_ctxt < 2)
    03069     {
    03070         tbtt->status |= CHAN_TBTT_WAIT_TO;
    03071         chan_env.nb_active_tbtt++;
    03072         return !on_channel;
    03073     }
    03074
    03075
    03076     #if (NX_P2P_GO && NX_BEACONING)
    03077     if (tbtt->p2p_noa_vif_index != INVALID_VIF_IDX)
    03078     {
    03079         chan_p2p_noa_resync_check(vif, tbtt_time);
    03080     }
    03081     else if (chan_is_p2p_go(vif))
    03082     {
    03083         if (tbtt->status & CHAN_TBTT_SCHEDULE_P2P_NOA)
    03084         {
    03085             chan_start_p2pgo_noa(vif);
    03086             tbtt->status &= ~(CHAN_TBTT_SCHEDULE_P2P_NOA);
    03087         }
    03088         else if (tbtt->status & CHAN_TBTT_P2P_NOA_RESYNC)
    03089         {
    03090             chan_p2p_noa_resync(vif);
    03091         }
    03092     }
    03093     #endif //(NX_P2P_GO)
    03094
    03095     if (skip)
    03096     {
    03097         tbtt->status |= CHAN_TBTT_SKIPPED;
    03098         #if (NX_P2P_GO)
    03099         if (chan_is_p2p_go(vif))
    03100         {
    03101             if ((tbtt->time != next_tbtt_time) &&
    03102                 hal_machw_time_cmp(tbtt->time, next_tbtt_time + 50) &&
    03103                 hal_machw_time_cmp(next_tbtt_time, tbtt->time + 50))
    03104                 tbtt->time = next_tbtt_time;
    03105         }
    03106         #endif //(NX_P2P_GO)
    03107     }
    03108     else
    03109     {
    03110         #if (NX_P2P_GO)
    03111         if (chan_is_p2p_go(vif))
    03112         {
    03113             // Need to add it now, to set single NOA in beacon if next TBTT
    03114             // need to be skip. Moreoever, contrary to STA/P2P cli vifs tbbt time
    03115             // won't change when chan_bcn_to_evt is called so it's ok to do it now.
    03116             chan_add_next_tbtt(vif, next_tbtt_time, 0);
    03117             tbtt->status |= CHAN_TBTT_ALREADY_ADDED;
    03118         }
    03119         else
    03120         #endif //(NX_P2P_GO)
    03121         {
    03122             chan_tbtt_remove(tbtt);
    03123         }
    03124         tbtt->status |= CHAN_TBTT_WAIT_TO;
    03125         chan_env.nb_active_tbtt++;
    03126     }
    03127
    03128     return !on_channel;
    03129 }
    03130
    03131 void chan_tbtt_updated(struct vif_info_tag *vif)
    03132 {
    03133     struct chan_tbtt_tag *tbtt = &vif->tbtt_switch;
    03134     struct chan_switch_tag *ch_switch;
    03135
    03136     if (chan_env.nb_sched_ctxt < 2)
    03137         return;
    03138
    03139     #if (NX_P2P_GO)
    03140     if (tbtt->status & CHAN_TBTT_SCHEDULE_P2P_NOA)
    03141     {
    03142         struct vif_info_tag *p2pgo_vif;
    03143         if (chan_get_p2pgo(&p2pgo_vif))
    03144             chan_start_p2pgo_noa(p2pgo_vif);
    03145         tbtt->status &= ~(CHAN_TBTT_SCHEDULE_P2P_NOA);
    03146     }
    03147     #endif //(NX_P2P_GO)
    03148
    03149     if (tbtt->status & CHAN_TBTT_WAIT_TO)
    03150     {
    03151         // This will be taken into account in chan_bcn_to_evt()
    03152         return;
    03153     }
    03154     else if (tbtt->status & CHAN_TBTT_SKIPPED)
    03155     {
    03156         // Even if TBTT is skipped if beacon is received need to update its next TBTT date
    03157         // Remove SKIPPED status not to re-add the TBTT in chan_bcn_to_evt.
    03158         tbtt->status &= ~(CHAN_TBTT_SKIPPED);
    03159     }
    03160
    03161     TRACE_CHAN(TBTT, "{VIF-%d} Beacon received outside of TBTT window", vif->index);
    03162
    03163     ch_switch = chan_switch_last();
    03164     if (ch_switch && (ch_switch->tbtt == tbtt))
    03165     {
    03166         // Channel switches have been scheduled based on previous TBTT, need to update
    03167         if ((hal_machw_time_cmp(tbtt->time, vif->tbtt_timer.time) &&
    03168              hal_machw_time_cmp(vif->tbtt_timer.time, tbtt->time + CHAN_SWITCH_DELAY)) ||
    03169             (hal_machw_time_cmp(vif->tbtt_timer.time, tbtt->time) &&
    03170              hal_machw_time_cmp(tbtt->time, vif->tbtt_timer.time + CHAN_SWITCH_DELAY)))
    03171         {
    03172             // Delta is small, simply update switch timer
    03173             tbtt->time = vif->tbtt_timer.time;
    03174             if (hal_machw_time_cmp(tbtt->time - CHAN_SWITCH_DELAY, ch_switch->time))
    03175             {
    03176                 ch_switch->time = tbtt->time - CHAN_SWITCH_DELAY;
    03177                 if (ch_switch == chan_env.tmr_switch.env)
    03178                 {
    03179                     chan_switch_reset_timer();
    03180                     chan_switch_set_timer(ch_switch);
    03181                 }
    03182             }
    03183         }
    03184         else
    03185         {
    03186             // Delta is significant, need to re-schedule switches
    03187             chan_cancel_all_switch();
    03188             chan_add_next_tbtt(vif, vif->tbtt_timer.time, 0);
    03189             chan_schedule_next_switch(vif, hal_machw_time(), 0);
    03190         }
    03191     }
    03192     else
    03193     {
    03194         // This TBTT hasn't been used to schedule channel switches, simply update it
    03195         chan_add_next_tbtt(vif, vif->tbtt_timer.time, 0);
    03196     }
    03197 }
    03198
    03199 void chan_bcn_to_evt(struct vif_info_tag *vif)
    03200 {
    03201     struct chan_tbtt_tag *tbtt = &vif->tbtt_switch;
    03202     bool sched_switch = true;
    03203     uint32_t next_tbtt_time, prev_tbtt_time;
    03204
    03205     TRACE_CHAN(TBTT, "{VIF-%d}{CTXT-%d} BCN TimeOut status = %d beacon_lost = %d",
    03206                tbtt->vif_index, vif->chan_ctxt->idx, tbtt->status,
    03207                #if NX_CONNECTION_MONITOR
    03208                vif->u.sta.beacon_loss_cnt
    03209                #else
    03210                -1
    03211                #endif
    03212                );
    03213
    03214     if (chan_env.nb_sched_ctxt < 2)
    03215     {
    03216         if ((tbtt->status & CHAN_TBTT_WAIT_TO))
    03217         {
    03218             tbtt->status &= ~(CHAN_TBTT_WAIT_TO);
    03219             chan_env.nb_active_tbtt--;
    03220             if (!chan_env.nb_active_tbtt &&
    03221                 (chan_env.status & CO_BIT(CHAN_ENV_FIX_CTXT_PENDING_BIT)))
    03222                 chan_fix_ctxt_until(chan_env.fix_ctxt);
    03223         }
    03224         return;
    03225     }
    03226
    03227     #if (NX_P2P_GO && NX_BEACONING)
    03228     if ((tbtt->status & CHAN_TBTT_P2P_NOA_TSF_UPDATE))
    03229         chan_p2p_noa_tsf_updated(vif);
    03230     #endif //(NX_P2P_GO && NX_BEACONING)
    03231
    03232     next_tbtt_time = vif->tbtt_timer.time;
    03233     if (tbtt->status & CHAN_TBTT_SKIPPED)
    03234     {
    03235         // This TBTT has been skipped by CHAN module, and no beacon has been received
    03236         // (otherwise chan_tbtt_updated would have reset the SKIPPED status).
    03237         // In some cases TBTT may not be present in the list, so re-add it if needed.
    03238         if (!(tbtt->status & CHAN_TBTT_PROG))
    03239             chan_add_next_tbtt(vif, next_tbtt_time, 0);
    03240         tbtt->status &= ~(CHAN_TBTT_SKIPPED);
    03241         return;
    03242     }
    03243     else if (!(tbtt->status & CHAN_TBTT_WAIT_TO))
    03244     {
    03245         return;
    03246     }
    03247
    03248     tbtt->status &= ~(CHAN_TBTT_WAIT_TO);
    03249
    03250     // Scheduled fixed context if any pending (Do it before adding TBTT)
    03251     chan_env.nb_active_tbtt--;
    03252     if (!chan_env.nb_active_tbtt &&
    03253         (chan_env.status & CO_BIT(CHAN_ENV_FIX_CTXT_PENDING_BIT)))
    03254     {
    03255         chan_fix_ctxt_until(chan_env.fix_ctxt);
    03256         sched_switch = false;
    03257     }
    03258     else if (chan_env.nb_active_tbtt)
    03259     {
    03260         sched_switch = false;
    03261     }
    03262
    03263     // Add next TBTT unless it has already been added
    03264     prev_tbtt_time = tbtt->time;
    03265     if (tbtt->status & CHAN_TBTT_ALREADY_ADDED)
    03266     {
    03267         tbtt->status &= ~(CHAN_TBTT_ALREADY_ADDED);
    03268         prev_tbtt_time -= chan_vif_tbtt_intv(vif);
    03269     }
    03270     else
    03271     {
    03272         chan_add_next_tbtt(vif, next_tbtt_time, 0);
    03273     }
    03274
    03275     // And schedule switches unless a Fixed context has been configured.
    03276     if (sched_switch)
    03277     {
    03278         uint32_t now = hal_machw_time();
    03279         uint32_t tbtt_dur = now - prev_tbtt_time;
    03280         chan_schedule_next_switch(vif, now, tbtt_dur);
    03281     }
    03282 }
    03283
    03284 void chan_bcn_detect_start(struct vif_info_tag *vif)
    03285 {
    03286     struct chan_ctxt_tag *ctxt = vif->chan_ctxt;
    03287
    03288     // Sanity check
    03289     ASSERT_ERR(ctxt);
    03290
    03291     TRACE_CHAN(TBTT, "{CTXT-%d} Start Beacon detection procedure for {VIF-%d}",
    03292                ctxt->idx, vif->index);
    03293
    03294     // TODO [LT] - Beacon Detection status should be kept by VIF
    03295     // TODO [LT] - Once beacon is received we could use Cancel Remain on Channel
    03296     if (!(chan_env.status & CO_BIT(CHAN_ENV_BCN_DETECT_BIT)) &&
    03297         (chan_env.nb_sched_ctxt > 1))
    03298     {
    03299         struct sta_info_tag *sta = &sta_info_tab[vif->u.sta.ap_id];
    03300
    03301         // Start a remain on channel procedure in order to received all the beacons
    03302         struct mm_remain_on_channel_req *req = KE_MSG_ALLOC(MM_REMAIN_ON_CHANNEL_REQ,
    03303                                                             TASK_MM, TASK_MM,
    03304                                                             mm_remain_on_channel_req);
    03305
    03306         // Fill request parameters
    03307         req->op_code   = MM_ROC_OP_START;
    03308         req->vif_index = vif->index;
    03309         req->chan      = ctxt->channel;
    03310         req->duration_ms  = (sta->bcn_int - 5000) / 1000;
    03311
    03312         ke_msg_send(req);
    03313
    03314         // Set Beacon Detection bit in environment status
    03315         chan_env.status |= CO_BIT(CHAN_ENV_BCN_DETECT_BIT);
    03316     }
    03317 }
    03318
    03319 #if (NX_P2P)
    03320 void chan_p2p_absence_update(struct chan_ctxt_tag *ctxt, bool absence)
    03321 {
    03322     // TODO
    03323 }
    03324 #endif //(NX_P2P)
    03325
    03326 bool chan_is_on_channel(struct vif_info_tag *vif)
    03327 {
    03328     bool is_on_channel = false;
    03329
    03330     if (chan_env.current_ctxt)
    03331     {
    03332         if (chan_env.current_ctxt->idx < CHAN_SCAN_CTXT_IDX)
    03333         {
    03334             is_on_channel = (vif->chan_ctxt == chan_env.current_ctxt);
    03335         }
    03336         else
    03337         {
    03338             is_on_channel = (chan_env.current_ctxt->vif_index == vif->index);
    03339         }
    03340     }
    03341
    03342     return (is_on_channel);
    03343 }
    03344
    03345 bool chan_is_tx_allowed(struct vif_info_tag *vif)
    03346 {
    03347     if ((!chan_is_on_channel(vif)) ||
    03348         (chan_env.switch_ctxt &&
    03349          (chan_env.current_ctxt->status != CHAN_SENDING_NOA)))
    03350     {
    03351         return false;
    03352     }
    03353
    03354     return true;
    03355 }
    03356
    03357 bool chan_is_on_operational_channel(struct vif_info_tag *vif)
    03358 {
    03359     bool is_on_channel = false;
    03360
    03361     if (chan_env.current_ctxt)
    03362     {
    03363         if (chan_env.current_ctxt->idx < CHAN_SCAN_CTXT_IDX)
    03364         {
    03365             is_on_channel = (vif->chan_ctxt == chan_env.current_ctxt);
    03366         }
    03367     }
    03368
    03369     return (is_on_channel);
    03370 }
    03371
    03372 void chan_update_tx_power(struct chan_ctxt_tag *ctxt)
    03373 {
    03374     int8_t i, min_pwr = VIF_UNDEF_POWER;
    03375
    03376     if (ctxt->nb_linked_vif)
    03377     {
    03378         for (i = 0 ; i < NX_VIRT_DEV_MAX; i++) {
    03379             struct vif_info_tag *vif = &vif_info_tab[i];
    03380
    03381             if (vif->chan_ctxt == ctxt)
    03382             {
    03383                 #if NX_UMAC_PRESENT
    03384                 if (vif->user_tx_power < min_pwr)
    03385                     min_pwr = vif->user_tx_power;
    03386                 #endif
    03387                 if (vif->tx_power < min_pwr)
    03388                     min_pwr = vif->tx_power;
    03389
    03390                 break;
    03391             }
    03392         }
    03393     }
    03394
    03395     if (min_pwr != VIF_UNDEF_POWER)
    03396         ctxt->channel.tx_power = min_pwr;
    03397     else
    03398         // Should only be true when no vif is linked to the context
    03399         ctxt->channel.tx_power = MM_DEFAULT_TX_POWER;
    03400
    03401     TRACE_LMAC(TPC, "{CTXT-%d} updated channel context tx_power: %ddBm",
    03402                ctxt->idx, ctxt->channel.tx_power);
    03403
    03404     // apply update immediately if this is the active channel
    03405     if (chan_env.current_ctxt == ctxt)
    03406         tpc_update_tx_power(ctxt->channel.tx_power);
    03407 }
    03408
    03409 #endif //(NX_CHNL_CTXT)
    03410