Path: blob/master/ALFA-W1F1/RTL8814AU/core/rtw_rm_fsm.c
1307 views
/******************************************************************************1*2* Copyright(c) 2007 - 2017 Realtek Corporation.3*4* This program is free software; you can redistribute it and/or modify it5* under the terms of version 2 of the GNU General Public License as6* published by the Free Software Foundation.7*8* This program is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for11* more details.12*13*****************************************************************************/1415#include <drv_types.h>16#include <hal_data.h>17#ifdef CONFIG_RTW_80211K18#include "rtw_rm_fsm.h"19#include "rtw_rm_util.h"2021struct fsm_state {22u8 *name;23int(*fsm_func)(struct rm_obj *prm, enum RM_EV_ID evid);24};2526static void rm_state_initial(struct rm_obj *prm);27static void rm_state_goto(struct rm_obj *prm, enum RM_STATE rm_state);28static void rm_state_run(struct rm_obj *prm, enum RM_EV_ID evid);29static struct rm_event *rm_dequeue_ev(_queue *queue);30static struct rm_obj *rm_dequeue_rm(_queue *queue);3132void rm_timer_callback(void *data)33{34int i;35_adapter *padapter = (_adapter *)data;36struct rm_priv *prmpriv = &padapter->rmpriv;37struct rm_clock *pclock;383940/* deal with clock */41for (i=0;i<RM_TIMER_NUM;i++) {42pclock = &prmpriv->clock[i];43if (pclock->prm == NULL44||(ATOMIC_READ(&(pclock->counter)) == 0))45continue;4647ATOMIC_DEC(&(pclock->counter));4849if (ATOMIC_READ(&(pclock->counter)) == 0)50rm_post_event(pclock->prm->psta->padapter,51pclock->prm->rmid, prmpriv->clock[i].evid);52}53_set_timer(&prmpriv->rm_timer, CLOCK_UNIT);54}5556int rtw_init_rm(_adapter *padapter)57{58struct rm_priv *prmpriv = &padapter->rmpriv;596061RTW_INFO("RM: %s\n",__func__);62_rtw_init_queue(&(prmpriv->rm_queue));63_rtw_init_queue(&(prmpriv->ev_queue));6465/* bit 0-7 */66prmpriv->rm_en_cap_def[0] = 067| BIT(RM_LINK_MEAS_CAP_EN)68| BIT(RM_NB_REP_CAP_EN)69/*| BIT(RM_PARAL_MEAS_CAP_EN)*/70| BIT(RM_REPEAT_MEAS_CAP_EN)71| BIT(RM_BCN_PASSIVE_MEAS_CAP_EN)72| BIT(RM_BCN_ACTIVE_MEAS_CAP_EN)73| BIT(RM_BCN_TABLE_MEAS_CAP_EN)74/*| BIT(RM_BCN_MEAS_REP_COND_CAP_EN)*/;7576/* bit 8-15 */77prmpriv->rm_en_cap_def[1] = 078/*| BIT(RM_FRAME_MEAS_CAP_EN - 8)*/79#ifdef CONFIG_RTW_ACS80| BIT(RM_CH_LOAD_CAP_EN - 8)81| BIT(RM_NOISE_HISTO_CAP_EN - 8)82#endif83/*| BIT(RM_STATIS_MEAS_CAP_EN - 8)*/84/*| BIT(RM_LCI_MEAS_CAP_EN - 8)*/85/*| BIT(RM_LCI_AMIMUTH_CAP_EN - 8)*/86/*| BIT(RM_TRANS_STREAM_CAT_MEAS_CAP_EN - 8)*/87/*| BIT(RM_TRIG_TRANS_STREAM_CAT_MEAS_CAP_EN - 8)*/;8889/* bit 16-23 */90prmpriv->rm_en_cap_def[2] = 091/*| BIT(RM_AP_CH_REP_CAP_EN - 16)*/92/*| BIT(RM_RM_MIB_CAP_EN - 16)*/93/*| BIT(RM_OP_CH_MAX_MEAS_DUR0 - 16)*/94/*| BIT(RM_OP_CH_MAX_MEAS_DUR1 - 16)*/95/*| BIT(RM_OP_CH_MAX_MEAS_DUR2 - 16)*/96/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR0 - 16)*/97/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR1 - 16)*/98/*| BIT(RM_NONOP_CH_MAX_MEAS_DUR2 - 16)*/;99100/* bit 24-31 */101prmpriv->rm_en_cap_def[3] = 0102/*| BIT(RM_MEAS_PILOT_CAP0 - 24)*/103/*| BIT(RM_MEAS_PILOT_CAP1 - 24)*/104/*| BIT(RM_MEAS_PILOT_CAP2 - 24)*/105/*| BIT(RM_MEAS_PILOT_TRANS_INFO_CAP_EN - 24)*/106/*| BIT(RM_NB_REP_TSF_OFFSET_CAP_EN - 24)*/107| BIT(RM_RCPI_MEAS_CAP_EN - 24)108| BIT(RM_RSNI_MEAS_CAP_EN - 24)109/*| BIT(RM_BSS_AVG_ACCESS_DELAY_CAP_EN - 24)*/;110111/* bit 32-39 */112prmpriv->rm_en_cap_def[4] = 0113/*| BIT(RM_BSS_AVG_ACCESS_DELAY_CAP_EN - 32)*/114/*| BIT(RM_AVALB_ADMIS_CAPACITY_CAP_EN - 32)*/115/*| BIT(RM_ANT_CAP_EN - 32)*/;116117prmpriv->enable = _TRUE;118119/* clock timer */120rtw_init_timer(&prmpriv->rm_timer,121padapter, rm_timer_callback, padapter);122_set_timer(&prmpriv->rm_timer, CLOCK_UNIT);123124return _SUCCESS;125}126127int rtw_deinit_rm(_adapter *padapter)128{129struct rm_priv *prmpriv = &padapter->rmpriv;130struct rm_obj *prm;131struct rm_event *pev;132133134RTW_INFO("RM: %s\n",__func__);135prmpriv->enable = _FALSE;136_cancel_timer_ex(&prmpriv->rm_timer);137138/* free all events and measurements */139while((pev = rm_dequeue_ev(&prmpriv->ev_queue)) != NULL)140rtw_mfree((void *)pev, sizeof(struct rm_event));141142while((prm = rm_dequeue_rm(&prmpriv->rm_queue)) != NULL)143rm_state_run(prm, RM_EV_cancel);144145_rtw_deinit_queue(&(prmpriv->rm_queue));146_rtw_deinit_queue(&(prmpriv->ev_queue));147148return _SUCCESS;149}150151int rtw_free_rm_priv(_adapter *padapter)152{153return rtw_deinit_rm(padapter);154}155156static int rm_enqueue_ev(_queue *queue, struct rm_event *obj, bool to_head)157{158_irqL irqL;159160161if (obj == NULL)162return _FAIL;163164_enter_critical(&queue->lock, &irqL);165166if (to_head)167rtw_list_insert_head(&obj->list, &queue->queue);168else169rtw_list_insert_tail(&obj->list, &queue->queue);170171_exit_critical(&queue->lock, &irqL);172173return _SUCCESS;174}175176static void rm_set_clock(struct rm_obj *prm, u32 ms, enum RM_EV_ID evid)177{178ATOMIC_SET(&(prm->pclock->counter), (ms/CLOCK_UNIT));179prm->pclock->evid = evid;180}181182static struct rm_clock *rm_alloc_clock(_adapter *padapter, struct rm_obj *prm)183{184int i;185struct rm_priv *prmpriv = &padapter->rmpriv;186struct rm_clock *pclock = NULL;187188189for (i=0;i<RM_TIMER_NUM;i++) {190pclock = &prmpriv->clock[i];191192if (pclock->prm == NULL) {193pclock->prm = prm;194ATOMIC_SET(&(pclock->counter), 0);195pclock->evid = RM_EV_max;196break;197}198}199return pclock;200}201202static void rm_cancel_clock(struct rm_obj *prm)203{204ATOMIC_SET(&(prm->pclock->counter), 0);205prm->pclock->evid = RM_EV_max;206}207208static void rm_free_clock(struct rm_clock *pclock)209{210pclock->prm = NULL;211ATOMIC_SET(&(pclock->counter), 0);212pclock->evid = RM_EV_max;213}214215static int is_list_linked(const struct list_head *head)216{217return head->prev != NULL;218}219220void rm_free_rmobj(struct rm_obj *prm)221{222if (is_list_linked(&prm->list))223rtw_list_delete(&prm->list);224225if (prm->q.pssid)226rtw_mfree(prm->q.pssid, strlen(prm->q.pssid)+1);227228if (prm->q.opt.bcn.req_start)229rtw_mfree(prm->q.opt.bcn.req_start,230prm->q.opt.bcn.req_len);231232if (prm->pclock)233rm_free_clock(prm->pclock);234235rtw_mfree((void *)prm, sizeof(struct rm_obj));236}237238struct rm_obj *rm_alloc_rmobj(_adapter *padapter)239{240struct rm_obj *prm;241242243prm = (struct rm_obj *)rtw_malloc(sizeof(struct rm_obj));244if (prm == NULL)245return NULL;246247_rtw_memset(prm, 0, sizeof(struct rm_obj));248249/* alloc timer */250if ((prm->pclock = rm_alloc_clock(padapter, prm)) == NULL) {251rm_free_rmobj(prm);252return NULL;253}254return prm;255}256257int rm_enqueue_rmobj(_adapter *padapter, struct rm_obj *prm, bool to_head)258{259_irqL irqL;260struct rm_priv *prmpriv = &padapter->rmpriv;261_queue *queue = &prmpriv->rm_queue;262263264if (prm == NULL)265return _FAIL;266267_enter_critical(&queue->lock, &irqL);268if (to_head)269rtw_list_insert_head(&prm->list, &queue->queue);270else271rtw_list_insert_tail(&prm->list, &queue->queue);272_exit_critical(&queue->lock, &irqL);273274rm_state_initial(prm);275276return _SUCCESS;277}278279static struct rm_obj *rm_dequeue_rm(_queue *queue)280{281_irqL irqL;282struct rm_obj *prm;283284285_enter_critical(&queue->lock, &irqL);286if (rtw_is_list_empty(&(queue->queue)))287prm = NULL;288else {289prm = LIST_CONTAINOR(get_next(&(queue->queue)),290struct rm_obj, list);291/* rtw_list_delete(&prm->list); */292}293_exit_critical(&queue->lock, &irqL);294295return prm;296}297298static struct rm_event *rm_dequeue_ev(_queue *queue)299{300_irqL irqL;301struct rm_event *ev;302303304_enter_critical(&queue->lock, &irqL);305if (rtw_is_list_empty(&(queue->queue)))306ev = NULL;307else {308ev = LIST_CONTAINOR(get_next(&(queue->queue)),309struct rm_event, list);310rtw_list_delete(&ev->list);311}312_exit_critical(&queue->lock, &irqL);313314return ev;315}316317static struct rm_obj *_rm_get_rmobj(_queue *queue, u32 rmid)318{319_irqL irqL;320_list *phead, *plist;321struct rm_obj *prm = NULL;322323324if (rmid == 0)325return NULL;326327_enter_critical(&queue->lock, &irqL);328329phead = get_list_head(queue);330plist = get_next(phead);331while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {332333prm = LIST_CONTAINOR(plist, struct rm_obj, list);334if (rmid == (prm->rmid)) {335_exit_critical(&queue->lock, &irqL);336return prm;337}338plist = get_next(plist);339}340_exit_critical(&queue->lock, &irqL);341342return NULL;343}344345struct sta_info *rm_get_psta(_adapter *padapter, u32 rmid)346{347struct rm_priv *prmpriv = &padapter->rmpriv;348struct rm_obj *prm;349350351prm = _rm_get_rmobj(&prmpriv->rm_queue, rmid);352353if (prm)354return prm->psta;355356return NULL;357}358359struct rm_obj *rm_get_rmobj(_adapter *padapter, u32 rmid)360{361struct rm_priv *prmpriv = &padapter->rmpriv;362363return _rm_get_rmobj(&prmpriv->rm_queue, rmid);364}365366u8 rtw_rm_post_envent_cmd(_adapter *padapter, u32 rmid, u8 evid)367{368struct cmd_obj *pcmd;369struct rm_event *pev;370struct cmd_priv *pcmdpriv = &padapter->cmdpriv;371u8 res = _SUCCESS;372373374pcmd = (struct cmd_obj *)rtw_zmalloc(sizeof(struct cmd_obj));375if (pcmd == NULL) {376res = _FAIL;377goto exit;378}379pev = (struct rm_event*)rtw_zmalloc(sizeof(struct rm_event));380381if (pev == NULL) {382rtw_mfree((u8 *) pcmd, sizeof(struct cmd_obj));383res = _FAIL;384goto exit;385}386pev->rmid = rmid;387pev->evid = evid;388389init_h2fwcmd_w_parm_no_rsp(pcmd, pev, GEN_CMD_CODE(_RM_POST_EVENT));390res = rtw_enqueue_cmd(pcmdpriv, pcmd);391exit:392return res;393}394395int rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid)396{397if (padapter->rmpriv.enable == _FALSE)398return _FALSE;399400RTW_INFO("RM: post asyn %s to rmid=%x\n", rm_event_name(evid), rmid);401rtw_rm_post_envent_cmd(padapter, rmid, evid);402return _SUCCESS;403}404405int _rm_post_event(_adapter *padapter, u32 rmid, enum RM_EV_ID evid)406{407struct rm_priv *prmpriv = &padapter->rmpriv;408struct rm_event *pev;409410if (evid >= RM_EV_max || rmid == 0)411return _FALSE;412413pev = (struct rm_event *)rtw_malloc(sizeof(struct rm_event));414if (pev == NULL)415return _FALSE;416417pev->rmid = rmid;418pev->evid = evid;419420RTW_INFO("RM: post sync %s to rmid=%x\n", rm_event_name(evid), rmid);421rm_enqueue_ev(&prmpriv->ev_queue, pev, FALSE);422423return _SUCCESS;424}425426static void rm_bcast_aid_handler(_adapter *padapter, struct rm_event *pev)427{428_irqL irqL;429_list *phead, *plist;430_queue *queue = &padapter->rmpriv.rm_queue;431struct rm_obj *prm;432433434_enter_critical(&queue->lock, &irqL);435phead = get_list_head(queue);436plist = get_next(phead);437while ((rtw_end_of_queue_search(phead, plist)) == _FALSE) {438439prm = LIST_CONTAINOR(plist, struct rm_obj, list);440plist = get_next(plist);441if (RM_GET_AID(pev->rmid) == RM_GET_AID(prm->rmid)) {442_exit_critical(&queue->lock, &irqL);443rm_state_run(prm, pev->evid);444_enter_critical(&queue->lock, &irqL);445}446}447_exit_critical(&queue->lock, &irqL);448return;449}450451/* main handler of RM (Resource Management) */452void rm_handler(_adapter *padapter, struct rm_event *pe)453{454int i;455struct rm_priv *prmpriv = &padapter->rmpriv;456struct rm_obj *prm;457struct rm_event *pev;458459460/* dequeue event */461while((pev = rm_dequeue_ev(&prmpriv->ev_queue)) != NULL)462{463if (RM_IS_ID_FOR_ALL(pev->rmid)) {464/* apply to all aid mateched measurement */465rm_bcast_aid_handler(padapter, pev);466rtw_mfree((void *)pev, sizeof(struct rm_event));467continue;468}469470/* retrieve rmobj */471prm = _rm_get_rmobj(&prmpriv->rm_queue, pev->rmid);472if (prm == NULL) {473RTW_ERR("RM: rmid=%x event=%s doesn't find rm obj\n",474pev->rmid, rm_event_name(pev->evid));475rtw_mfree((void *)pev, sizeof(struct rm_event));476return;477}478/* run state machine */479rm_state_run(prm, pev->evid);480rtw_mfree((void *)pev, sizeof(struct rm_event));481}482}483484static int rm_issue_meas_req(struct rm_obj *prm)485{486switch (prm->q.action_code) {487case RM_ACT_RADIO_MEAS_REQ:488switch (prm->q.m_type) {489case bcn_req:490case ch_load_req:491case noise_histo_req:492issue_radio_meas_req(prm);493break;494default:495break;496} /* meas_type */497break;498case RM_ACT_NB_REP_REQ:499/* issue neighbor request */500issue_nb_req(prm);501break;502case RM_ACT_LINK_MEAS_REQ:503issue_link_meas_req(prm);504break;505default:506return _FALSE;507} /* action_code */508509return _SUCCESS;510}511512/*513* RM state machine514*/515516static int rm_state_idle(struct rm_obj *prm, enum RM_EV_ID evid)517{518_adapter *padapter = prm->psta->padapter;519u8 val8;520u32 val32;521522523prm->p.category = RTW_WLAN_CATEGORY_RADIO_MEAS;524525switch (evid) {526case RM_EV_state_in:527switch (prm->q.action_code) {528case RM_ACT_RADIO_MEAS_REQ:529/* copy attrib from meas_req to meas_rep */530prm->p.action_code = RM_ACT_RADIO_MEAS_REP;531prm->p.diag_token = prm->q.diag_token;532prm->p.e_id = _MEAS_RSP_IE_;533prm->p.m_token = prm->q.m_token;534prm->p.m_type = prm->q.m_type;535prm->p.rpt = prm->q.rpt;536prm->p.ch_num = prm->q.ch_num;537prm->p.op_class = prm->q.op_class;538539if (prm->q.m_type == ch_load_req540|| prm->q.m_type == noise_histo_req) {541/*542* phydm measure current ch periodically543* scan current ch is not necessary544*/545val8 = padapter->mlmeextpriv.cur_channel;546if (prm->q.ch_num == val8)547prm->poll_mode = 1;548}549RTW_INFO("RM: rmid=%x %s switch in repeat=%u\n",550prm->rmid, rm_type_req_name(prm->q.m_type),551prm->q.rpt);552break;553case RM_ACT_NB_REP_REQ:554prm->p.action_code = RM_ACT_NB_REP_RESP;555RTW_INFO("RM: rmid=%x Neighbor request switch in\n",556prm->rmid);557break;558case RM_ACT_LINK_MEAS_REQ:559prm->p.diag_token = prm->q.diag_token;560prm->p.action_code = RM_ACT_LINK_MEAS_REP;561RTW_INFO("RM: rmid=%x Link meas switch in\n",562prm->rmid);563break;564default:565prm->p.action_code = prm->q.action_code;566rm_set_rep_mode(prm, MEAS_REP_MOD_INCAP);567RTW_INFO("RM: rmid=%x recv unknown action %d\n",568prm->rmid,prm->p.action_code);569break;570} /* switch() */571572if (prm->rmid & RM_MASTER) {573if (rm_issue_meas_req(prm) == _SUCCESS)574rm_state_goto(prm, RM_ST_WAIT_MEAS);575else576rm_state_goto(prm, RM_ST_END);577return _SUCCESS;578} else {579rm_state_goto(prm, RM_ST_DO_MEAS);580return _SUCCESS;581}582583if (prm->p.m_mode) {584issue_null_reply(prm);585rm_state_goto(prm, RM_ST_END);586return _SUCCESS;587}588if (prm->q.rand_intvl) {589/* get low tsf to generate random interval */590val32 = rtw_read32(padapter, REG_TSFTR);591val32 = val32 % prm->q.rand_intvl;592RTW_INFO("RM: rmid=%x rand_intval=%d, rand=%d\n",593prm->rmid, (int)prm->q.rand_intvl,val32);594rm_set_clock(prm, prm->q.rand_intvl,595RM_EV_delay_timer_expire);596return _SUCCESS;597}598break;599case RM_EV_delay_timer_expire:600rm_state_goto(prm, RM_ST_DO_MEAS);601break;602case RM_EV_cancel:603rm_state_goto(prm, RM_ST_END);604break;605case RM_EV_state_out:606rm_cancel_clock(prm);607break;608default:609break;610}611return _SUCCESS;612}613614/* we do the measuring */615static int rm_state_do_meas(struct rm_obj *prm, enum RM_EV_ID evid)616{617_adapter *padapter = prm->psta->padapter;618u8 val8;619u64 val64;620621622switch (evid) {623case RM_EV_state_in:624if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {625switch (prm->q.m_type) {626case bcn_req:627if (prm->q.m_mode == bcn_req_bcn_table) {628RTW_INFO("RM: rmid=%x Beacon table\n",629prm->rmid);630_rm_post_event(padapter, prm->rmid,631RM_EV_survey_done);632return _SUCCESS;633}634break;635case ch_load_req:636case noise_histo_req:637if (prm->poll_mode)638_rm_post_event(padapter, prm->rmid,639RM_EV_survey_done);640return _SUCCESS;641default:642rm_state_goto(prm, RM_ST_END);643return _SUCCESS;644}645646if (!ready_for_scan(prm)) {647prm->wait_busy = RM_BUSY_TRAFFIC_TIMES;648RTW_INFO("RM: wait busy traffic - %d\n",649prm->wait_busy);650rm_set_clock(prm, RM_WAIT_BUSY_TIMEOUT,651RM_EV_busy_timer_expire);652return _SUCCESS;653}654} else if (prm->q.action_code == RM_ACT_LINK_MEAS_REQ) {655; /* do nothing */656rm_state_goto(prm, RM_ST_SEND_REPORT);657return _SUCCESS;658}659_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);660break;661case RM_EV_start_meas:662if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {663/* resotre measurement start time */664prm->meas_start_time = rtw_hal_get_tsftr_by_port(padapter665, rtw_hal_get_port(padapter));666667switch (prm->q.m_type) {668case bcn_req:669val8 = 1; /* Enable free run counter */670rtw_hal_set_hwreg(padapter,671HW_VAR_FREECNT, &val8);672rm_sitesurvey(prm);673break;674case ch_load_req:675case noise_histo_req:676rm_sitesurvey(prm);677break;678default:679rm_state_goto(prm, RM_ST_END);680return _SUCCESS;681break;682}683}684/* handle measurement timeout */685rm_set_clock(prm, RM_MEAS_TIMEOUT, RM_EV_meas_timer_expire);686break;687case RM_EV_survey_done:688if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {689switch (prm->q.m_type) {690case bcn_req:691rm_cancel_clock(prm);692rm_state_goto(prm, RM_ST_SEND_REPORT);693return _SUCCESS;694case ch_load_req:695case noise_histo_req:696retrieve_radio_meas_result(prm);697698if (rm_radio_meas_report_cond(prm) == _SUCCESS)699rm_state_goto(prm, RM_ST_SEND_REPORT);700else701rm_set_clock(prm, RM_COND_INTVL,702RM_EV_retry_timer_expire);703break;704default:705rm_state_goto(prm, RM_ST_END);706return _SUCCESS;707}708}709break;710case RM_EV_meas_timer_expire:711RTW_INFO("RM: rmid=%x measurement timeount\n",prm->rmid);712rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);713issue_null_reply(prm);714rm_state_goto(prm, RM_ST_END);715break;716case RM_EV_busy_timer_expire:717if (!ready_for_scan(prm) && prm->wait_busy--) {718RTW_INFO("RM: wait busy - %d\n",prm->wait_busy);719rm_set_clock(prm, RM_WAIT_BUSY_TIMEOUT,720RM_EV_busy_timer_expire);721break;722}723else if (prm->wait_busy <= 0) {724RTW_INFO("RM: wait busy timeout\n");725rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);726issue_null_reply(prm);727rm_state_goto(prm, RM_ST_END);728return _SUCCESS;729}730_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);731break;732case RM_EV_request_timer_expire:733rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);734issue_null_reply(prm);735rm_state_goto(prm, RM_ST_END);736break;737case RM_EV_retry_timer_expire:738/* expired due to meas condition mismatch, meas again */739_rm_post_event(padapter, prm->rmid, RM_EV_start_meas);740break;741case RM_EV_cancel:742rm_set_rep_mode(prm, MEAS_REP_MOD_REFUSE);743issue_null_reply(prm);744rm_state_goto(prm, RM_ST_END);745break;746case RM_EV_state_out:747rm_cancel_clock(prm);748/* resotre measurement end time */749prm->meas_end_time = rtw_hal_get_tsftr_by_port(padapter750, rtw_hal_get_port(padapter));751752val8 = 0; /* Disable free run counter */753rtw_hal_set_hwreg(padapter, HW_VAR_FREECNT, &val8);754break;755default:756break;757}758759return _SUCCESS;760}761762static int rm_state_wait_meas(struct rm_obj *prm, enum RM_EV_ID evid)763{764u8 val8;765u64 val64;766767768switch (evid) {769case RM_EV_state_in:770/* we create meas_req, waiting for peer report */771rm_set_clock(prm, RM_REQ_TIMEOUT,772RM_EV_request_timer_expire);773break;774case RM_EV_recv_rep:775rm_state_goto(prm, RM_ST_RECV_REPORT);776break;777case RM_EV_request_timer_expire:778case RM_EV_cancel:779rm_state_goto(prm, RM_ST_END);780break;781case RM_EV_state_out:782rm_cancel_clock(prm);783break;784default:785break;786}787return _SUCCESS;788}789790static int rm_state_send_report(struct rm_obj *prm, enum RM_EV_ID evid)791{792u8 val8;793794795switch (evid) {796case RM_EV_state_in:797/* we have to issue report */798if (prm->q.action_code == RM_ACT_RADIO_MEAS_REQ) {799switch (prm->q.m_type) {800case bcn_req:801issue_beacon_rep(prm);802break;803case ch_load_req:804case noise_histo_req:805issue_radio_meas_rep(prm);806break;807default:808rm_state_goto(prm, RM_ST_END);809return _SUCCESS;810}811812} else if (prm->q.action_code == RM_ACT_LINK_MEAS_REQ) {813issue_link_meas_rep(prm);814rm_state_goto(prm, RM_ST_END);815return _SUCCESS;816817} else {818rm_state_goto(prm, RM_ST_END);819return _SUCCESS;820}821822/* check repeat */823if (prm->p.rpt) {824RTW_INFO("RM: rmid=%x repeat=%u/%u\n",825prm->rmid, prm->p.rpt,826prm->q.rpt);827prm->p.rpt--;828/*829* we recv meas_req,830* delay for a wihile and than meas again831*/832if (prm->poll_mode)833rm_set_clock(prm, RM_REPT_POLL_INTVL,834RM_EV_repeat_delay_expire);835else836rm_set_clock(prm, RM_REPT_SCAN_INTVL,837RM_EV_repeat_delay_expire);838return _SUCCESS;839}840/* we are done */841rm_state_goto(prm, RM_ST_END);842break;843case RM_EV_repeat_delay_expire:844rm_state_goto(prm, RM_ST_DO_MEAS);845break;846case RM_EV_cancel:847rm_state_goto(prm, RM_ST_END);848break;849case RM_EV_state_out:850rm_cancel_clock(prm);851break;852default:853break;854}855return _SUCCESS;856}857858static int rm_state_recv_report(struct rm_obj *prm, enum RM_EV_ID evid)859{860u8 val8;861862863switch (evid) {864case RM_EV_state_in:865/* we issue meas_req, got peer's meas report */866switch (prm->p.action_code) {867case RM_ACT_RADIO_MEAS_REP:868/* check refuse, incapable and repeat */869val8 = prm->p.m_mode;870if (val8) {871RTW_INFO("RM: rmid=%x peer reject (%s repeat=%d)\n",872prm->rmid,873val8|MEAS_REP_MOD_INCAP?"INCAP":874val8|MEAS_REP_MOD_REFUSE?"REFUSE":875val8|MEAS_REP_MOD_LATE?"LATE":"",876prm->p.rpt);877rm_state_goto(prm, RM_ST_END);878return _SUCCESS;879}880break;881case RM_ACT_NB_REP_RESP:882/* report to upper layer if needing */883rm_state_goto(prm, RM_ST_END);884return _SUCCESS;885default:886rm_state_goto(prm, RM_ST_END);887return _SUCCESS;888}889/* check repeat */890if (prm->p.rpt) {891RTW_INFO("RM: rmid=%x repeat=%u/%u\n",892prm->rmid, prm->p.rpt,893prm->q.rpt);894prm->p.rpt--;895/* waitting more report */896rm_state_goto(prm, RM_ST_WAIT_MEAS);897break;898}899/* we are done */900rm_state_goto(prm, RM_ST_END);901break;902case RM_EV_cancel:903rm_state_goto(prm, RM_ST_END);904break;905case RM_EV_state_out:906rm_cancel_clock(prm);907break;908default:909break;910}911return _SUCCESS;912}913914static int rm_state_end(struct rm_obj *prm, enum RM_EV_ID evid)915{916switch (evid) {917case RM_EV_state_in:918_rm_post_event(prm->psta->padapter, prm->rmid, RM_EV_state_out);919break;920921case RM_EV_cancel:922case RM_EV_state_out:923default:924rm_free_rmobj(prm);925break;926}927return _SUCCESS;928}929930struct fsm_state rm_fsm[] = {931{"RM_ST_IDLE", rm_state_idle},932{"RM_ST_DO_MEAS", rm_state_do_meas},933{"RM_ST_WAIT_MEAS", rm_state_wait_meas},934{"RM_ST_SEND_REPORT", rm_state_send_report},935{"RM_ST_RECV_REPORT", rm_state_recv_report},936{"RM_ST_END", rm_state_end}937};938939char *rm_state_name(enum RM_STATE state)940{941return rm_fsm[state].name;942}943944char *rm_event_name(enum RM_EV_ID evid)945{946switch(evid) {947case RM_EV_state_in:948return "RM_EV_state_in";949case RM_EV_busy_timer_expire:950return "RM_EV_busy_timer_expire";951case RM_EV_delay_timer_expire:952return "RM_EV_delay_timer_expire";953case RM_EV_meas_timer_expire:954return "RM_EV_meas_timer_expire";955case RM_EV_repeat_delay_expire:956return "RM_EV_repeat_delay_expire";957case RM_EV_retry_timer_expire:958return "RM_EV_retry_timer_expire";959case RM_EV_request_timer_expire:960return "RM_EV_request_timer_expire";961case RM_EV_wait_report:962return "RM_EV_wait_report";963case RM_EV_start_meas:964return "RM_EV_start_meas";965case RM_EV_survey_done:966return "RM_EV_survey_done";967case RM_EV_recv_rep:968return "RM_EV_recv_report";969case RM_EV_cancel:970return "RM_EV_cancel";971case RM_EV_state_out:972return "RM_EV_state_out";973case RM_EV_max:974return "RM_EV_max";975default:976return "RM_EV_unknown";977}978return "UNKNOWN";979}980981static void rm_state_initial(struct rm_obj *prm)982{983prm->state = RM_ST_IDLE;984985RTW_INFO("\n");986RTW_INFO("RM: rmid=%x %-18s -> %s\n",prm->rmid,987"new measurement", rm_fsm[prm->state].name);988989rm_post_event(prm->psta->padapter, prm->rmid, RM_EV_state_in);990}991992static void rm_state_run(struct rm_obj *prm, enum RM_EV_ID evid)993{994RTW_INFO("RM: rmid=%x %-18s %s\n",prm->rmid,995rm_fsm[prm->state].name,rm_event_name(evid));996997rm_fsm[prm->state].fsm_func(prm, evid);998}9991000static void rm_state_goto(struct rm_obj *prm, enum RM_STATE rm_state)1001{1002if (prm->state == rm_state)1003return;10041005rm_state_run(prm, RM_EV_state_out);10061007RTW_INFO("\n");1008RTW_INFO("RM: rmid=%x %-18s -> %s\n",prm->rmid,1009rm_fsm[prm->state].name, rm_fsm[rm_state].name);10101011prm->state = rm_state;1012rm_state_run(prm, RM_EV_state_in);1013}1014#endif /* CONFIG_RTW_80211K */101510161017