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
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
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
00110
00111
00112
00113 static void chan_switch_start(struct chan_ctxt_tag *ctxt);
00114 static void chan_switch_channel(void);
00115
00116
00117
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
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
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
00477
00478 while (read_counter--)
00479 {
00480
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
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
00568
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;
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
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
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
00724 ASSERT_ERR(nb_vif_oth_ctxt > 1);
00725 dur_merge = (dur * nb_vif_oth_ctxt) / (nb_vif_oth_ctxt - 1);
00726
00727
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;
00763 uint8_t noa_idx;
00764
00765 #if NX_BEACONING
00766
00767
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
00776 ap_next_tbtt = hal_machw_time() + (nxmac_next_tbtt_get() << 5);
00777
00778
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
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
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
00830 start_offset += CHAN_SWITCH_DELAY;
00831 start = noa[i].win.start - start_offset;
00832 dur = noa[i].dur + CHAN_SWITCH_DELAY;
00833
00834
00835
00836
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
00945
00946
00947
00948
00949
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
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
01268
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
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
01319 return false;
01320 *switch_date = p2p_next_present - CHAN_SWITCH_DELAY;
01321
01322
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
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
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
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
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
01519
01520
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
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
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
01681 if (chan_env.status & CO_BIT(CHAN_ENV_ROC_WAIT_BIT))
01682 {
01683
01684 ASSERT_ERR((chan_env.status & CO_BIT(CHAN_ENV_ROC_BIT)) == 0);
01685
01686
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
01692 else if (chan_env.status & CO_BIT(CHAN_ENV_SCAN_WAIT_BIT))
01693 {
01694
01695 ASSERT_ERR((chan_env.status & CO_BIT(CHAN_ENV_SCAN_BIT)) == 0);
01696
01697
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
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
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
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
01937 ASSERT_ERR(chan_env.cfm_cnt);
01938 chan_env.cfm_cnt--;
01939
01940
01941 if (chan_env.cfm_cnt == 0)
01942 {
01943
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
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
01969 return;
01970 }
01971 #endif //(NX_POWERSAVE)
01972
01973
01974 nxmac_pwr_mgt_setf(0);
01975
01976
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
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
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
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
02037 return 0;
02038 }
02039 #endif //(NX_POWERSAVE)
02040
02041
02042
02043 nxmac_pwr_mgt_setf(1);
02044
02045
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
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
02066
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
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
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
02106 mm_force_idle_req();
02107
02108
02109 if (chan_notify_absence())
02110 return;
02111
02112
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
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
02160 nxmac_rates_set(mm_env.basic_rates[chan->band]);
02161
02162
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
02169 chan_env.current_ctxt = ctxt;
02170
02171 chan_env.switch_ctxt = NULL;
02172
02173 chan_upd_ctxt_status(ctxt, CHAN_WAITING_END);
02174
02175
02176 if (ctxt->idx != CHAN_SCAN_CTXT_IDX)
02177 {
02178 if (ctxt->idx != CHAN_ROC_CTXT_IDX)
02179 {
02180
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
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
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
02216 nxmac_edca_cca_busy_set(0);
02217
02218
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
02226 GLOBAL_INT_DISABLE();
02227 ps_env.prevent_sleep |= PS_SCAN_ONGOING;
02228 GLOBAL_INT_RESTORE();
02229
02230
02231 chan_env.pm = nxmac_pwr_mgt_getf();
02232 nxmac_pwr_mgt_setf(0);
02233 }
02234 #endif //(NX_POWERSAVE)
02235
02236
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
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
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
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
02343
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
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
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
02476
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
02544
02545
02546 void chan_init(void)
02547 {
02548 memset(&chan_env, 0, sizeof(chan_env));
02549
02550
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
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
02577 chan_env.tmr_conn_less.cb = chan_conn_less_delay_evt;
02578
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
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
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
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
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
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
02720 ctxt->idx = CHAN_CTXT_UNUSED;
02721
02722
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
02746 if (chan_check_chan(chan_req, idx))
02747 {
02748
02749 return CO_OK;
02750 }
02751 #endif //(NX_UMAC_PRESENT)
02752
02753
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
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
02779 ASSERT_ERR(ctxt->idx != CHAN_CTXT_UNUSED);
02780
02781 ASSERT_ERR(ctxt->nb_linked_vif == 0);
02782
02783
02784 co_list_push_back(&chan_env.list_free_ctxt, &ctxt->list_hdr);
02785
02786
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
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
02803 vif->chan_ctxt = ctxt;
02804 vif->tbtt_switch.status = 0;
02805
02806
02807 ctxt->nb_linked_vif++;
02808
02809
02810 if (ctxt->nb_linked_vif == 1)
02811 {
02812
02813 ctxt->status = CHAN_NOT_PROG;
02814
02815
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
02825 co_list_push_back(&chan_env.list_sched_ctxt, &ctxt->list_hdr);
02826
02827
02828
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
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
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
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
02893 vif->chan_ctxt = NULL;
02894
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
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
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
02970 ctxt->channel = upd_req->chan;
02971
02972 if (chan_env.current_ctxt == ctxt)
02973 {
02974
02975
02976
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
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
03002 ASSERT_ERR(ctxt->status != CHAN_NOT_SCHEDULED);
03003
03004
03005 if (ctxt->status >= CHAN_WAITING_END)
03006 {
03007
03008 ke_msg_send_basic(MM_CHAN_CTXT_SCHED_CFM, taskid, TASK_MM);
03009 }
03010 else
03011 {
03012
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
03024 if (vif->chan_ctxt)
03025 {
03026
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
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
03114
03115
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
03152 return;
03153 }
03154 else if (tbtt->status & CHAN_TBTT_SKIPPED)
03155 {
03156
03157
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
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
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
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
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
03236
03237
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
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
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
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
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
03295
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
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
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
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
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
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
03405 if (chan_env.current_ctxt == ctxt)
03406 tpc_update_tx_power(ctxt->channel.tx_power);
03407 }
03408
03409 #endif //(NX_CHNL_CTXT)
03410