/******************************************************************************
|
*
|
* Copyright(c) 2019 - 2020 Realtek Corporation.
|
*
|
* This program is free software; you can redistribute it and/or modify it
|
* under the terms of version 2 of the GNU General Public License as
|
* published by the Free Software Foundation.
|
*
|
* This program is distributed in the hope that it will be useful, but WITHOUT
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
* more details.
|
*
|
* Author: vincent_fann@realtek.com
|
*
|
*****************************************************************************/
|
#define _PHL_CMD_SCAN_C_
|
#include "phl_headers.h"
|
#include "phl_scan.h"
|
#include "phl_scanofld.h"
|
|
#define param_to_phlcom(_param) (_param->wifi_role->phl_com)
|
#define wrole_to_phl(_wrole) ((struct phl_info_t *)(_wrole->phl_com->phl_priv))
|
#define sctrl_to_rlink(_sctrl, _idx) (&(_sctrl->wrole->rlink[_idx]))
|
|
#ifdef CONFIG_PHL_CMD_SCAN
|
|
#define DEF_PROBE_PERIOD 20
|
|
static void _cmd_scan_req_deinit(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param);
|
static void _cmd_scan_timer(void *context);
|
|
#define DBG_SCAN_CHAN_DUMP
|
|
|
u8 phl_cmd_scan_ctrl(struct rtw_phl_scan_param *param, u8 band_idx,
|
struct cmd_scan_ctrl **sctrl)
|
{
|
struct cmd_scan_ctrl *_sctrl = NULL;
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
u8 sctrl_idx = 0;
|
|
for(sctrl_idx = 0; sctrl_idx < param->sctrl_num; sctrl_idx++) {
|
_sctrl = ¶m->sctrl[sctrl_idx];
|
rlink = sctrl_to_rlink(_sctrl, RTW_RLINK_PRIMARY);
|
|
if(rlink->hw_band == band_idx)
|
break;
|
}
|
|
if(sctrl_idx == param->sctrl_num) {
|
PHL_ASSERT("%s: sctrl doesn't support this band_idx(%d)\n", __func__, band_idx);
|
_sctrl = NULL;
|
}
|
|
*sctrl = _sctrl;
|
return sctrl_idx;
|
}
|
|
#ifdef DBG_SCAN_CHAN_DUMP
|
static void
|
_cmd_estimated_swch_seq(void *drv, struct rtw_phl_scan_param *param, u8 op_num, u8 sctrl_idx)
|
{
|
struct cmd_scan_ctrl *sctrl = ¶m->sctrl[sctrl_idx];
|
u8 chidx = 0;
|
u8 opidx = 0;
|
u8 total_ch_num = 0;
|
struct phl_scan_channel *ch;
|
_os_list *node = NULL;
|
|
if ((param->back_op.mode == SCAN_BKOP_CNT) &&
|
(param->back_op.ch_intv == 0)) {
|
PHL_ERR("%s bkop_cnt == 0\n", __func__);
|
_os_warn_on(1);
|
return;
|
}
|
|
if (pq_get_front(drv, &sctrl->chlist, &node, _ps) == false)
|
return;
|
|
/*swicth channel sequence by cmd_scan's estimated */
|
PHL_INFO("%s:: Estimated channel sequence:\n", __func__);
|
|
if (param->back_op.mode == SCAN_BKOP_CNT) {
|
PHL_INFO("[SCAN_BKOP_CNT]:: sctrl[%d]\n", sctrl_idx);
|
|
do {
|
ch = (struct phl_scan_channel*)node;
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "%3d, ", ch->channel);
|
total_ch_num++;
|
if(!((chidx + 1) % param->back_op.ch_intv)) {
|
if (op_num) {
|
for(opidx = 0; opidx < op_num; opidx++) {
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_,
|
"[%3d], ", sctrl->back_op_ch[opidx].channel);
|
total_ch_num++;
|
}
|
}
|
}
|
if(!((chidx + 1) % (param->back_op.ch_intv * 2)))
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
|
chidx++;
|
} while(pq_get_next(drv, &sctrl->chlist, node, &node, _ps));
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
|
|
}
|
#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
|
else if (param->back_op.mode == SCAN_BKOP_TIMER) {
|
u16 ch_dur = 0;
|
|
PHL_INFO("[SCAN_BKOP_TIMER]:: sctrl_idx[%d]\n", sctrl_idx);
|
do {
|
ch = (struct phl_scan_channel*)node;
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "%3d, ", ch->channel);
|
total_ch_num++;
|
ch_dur = (op_num) ? param->back_op.off_ch_dur_ms : ch->duration;
|
PHL_INFO("\t%3d, dur:%d(ms)\n", ch->channel, ch_dur);
|
chidx++;
|
} while(pq_get_next(drv, &sctrl->chlist, node, &node, _ps));
|
if (op_num) {
|
for(opidx = 0; opidx < op_num; opidx++) {
|
total_ch_num++;
|
PHL_INFO("\t[%3d], dur:%d(ms)\n",
|
sctrl->back_op_ch[opidx].channel, sctrl->back_op_ch[opidx].duration);
|
}
|
}
|
PHL_INFO("max_listen_time:%d (ms)\n", param->max_listen_time);
|
PHL_INFO("op_ch_dur_ms:%d, off_ch_dur_ms:%d, off_ch_ext_dur_ms:%d (ms)",
|
param->back_op.ch_dur_ms,
|
param->back_op.off_ch_dur_ms,
|
param->back_op.off_ch_ext_dur_ms);
|
}
|
#endif
|
else if (param->back_op.mode == SCAN_BKOP_NONE) {
|
PHL_INFO("[SCAN_BKOP_NONE]:: sctrl_idx[%d]\n", sctrl_idx);
|
do {
|
ch = (struct phl_scan_channel*)node;
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "%3d, ", ch->channel);
|
total_ch_num++;
|
if(!((chidx + 1) % 6))
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
|
chidx++;
|
} while(pq_get_next(drv, &sctrl->chlist, node, &node, _ps));
|
PHL_DATA(COMP_PHL_DBG, _PHL_INFO_, "\n");
|
}
|
|
PHL_INFO("Scan chan num:%d , Total num:%d, repeat:%d\n",
|
param->ch_num, total_ch_num, param->repeat);
|
PHL_INFO("--------\n");
|
}
|
#endif /*DBG_SCAN_CHAN_DUMP*/
|
|
#ifdef CONFIG_RTW_ACS
|
static void
|
_cmd_scan_acs_mntr_trigger(struct phl_info_t *phl_info, enum phl_band_idx band_idx,
|
struct rtw_phl_scan_param *param,
|
u8 sctrl_idx)
|
{
|
struct phl_acs_parm parm = {0};
|
struct phl_scan_channel *scan_ch = param->sctrl[sctrl_idx].scan_ch;
|
|
if (!param->acs)
|
return;
|
|
parm.idx = scan_ch->acs_idx;
|
parm.monitor_time = ACS_ENV_MNTR_TIME(scan_ch->duration);
|
parm.nhm_include_cca = param->nhm_include_cca;
|
|
phl_acs_mntr_trigger(phl_info, band_idx, &parm);
|
}
|
|
static void
|
_cmd_scan_acs_mntr_result(struct phl_info_t *phl_info, enum phl_band_idx band_idx,
|
struct rtw_phl_scan_param *param,
|
u8 sctrl_idx)
|
{
|
struct phl_acs_parm parm = {0};
|
struct phl_scan_channel *scan_ch = param->sctrl[sctrl_idx].scan_ch;
|
|
if (!param->acs || param->sctrl[sctrl_idx].ch_idx < 0)
|
return;
|
|
parm.idx = scan_ch->acs_idx;
|
|
phl_acs_mntr_result(phl_info, band_idx, &parm);
|
}
|
#endif /* CONFIG_RTW_ACS */
|
|
static void
|
_cmd_scan_update_chlist(void *drv, struct rtw_phl_scan_param *param,
|
u8 sctrl_idx, bool is_cckphy)
|
{
|
u8 idx = 0;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
|
INIT_LIST_HEAD(¶m->sctrl[sctrl_idx].chlist.queue);
|
|
if (param->sctrl_num > 1) {
|
|
sctrl = ¶m->sctrl[sctrl_idx];
|
sctrl->is_cckphy = is_cckphy;
|
|
PHL_INFO("%s[%d]:: is_cckphy:%d\n",
|
__func__, sctrl_idx, is_cckphy);
|
|
|
/* 1,2,3,[36],4,5,6,[36],7,8,9,[36],10,11*/
|
/* 36,[36],40,44,48,[36],52,56,60,[36]...*/
|
/* ---> 1,2,3,4,5,6,7,8,9,10,11*/
|
/* ---> [36],[36],[36],36,[36],40,44,48,[36]*/
|
for (idx = 0; idx < param->ch_num; idx++) {
|
|
if (is_cckphy && (param->ch[idx].band == BAND_ON_5G ||
|
param->ch[idx].band == BAND_ON_6G))
|
continue;
|
|
if (!is_cckphy && param->ch[idx].band == BAND_ON_24G)
|
continue;
|
|
INIT_LIST_HEAD(¶m->ch[idx].list);
|
pq_push(drv, &sctrl->chlist, ¶m->ch[idx].list, _tail, _ps);
|
|
}
|
} else {
|
param->sctrl[0].is_cckphy = is_cckphy;
|
for (idx = 0; idx < param->ch_num; idx++) {
|
INIT_LIST_HEAD(¶m->ch[idx].list);
|
pq_push(drv, ¶m->sctrl[0].chlist, ¶m->ch[idx].list, _tail, _ps);
|
}
|
}
|
}
|
|
/*
|
* Insert op channel list
|
* Ex. ch_intvl =3
|
* ch_idx : -1, 0, 1, 2, 3, 4, 5, 6
|
* ^ ^
|
* op0~op5 op0~op5
|
*
|
* => 0,1,2,[op0],[op1],3,4,5,[op0],[op1],6,7,8,[op0],[op1]
|
*/
|
|
static inline void
|
_cmd_scan_enqueue_opch(void *drv, struct cmd_scan_ctrl *sctrl)
|
{
|
u8 idx = 0;
|
|
for(idx = 0; idx < MAX_WIFI_ROLE_NUMBER; idx ++) {
|
if(sctrl->back_op_ch[idx].channel)
|
pq_push(drv, &sctrl->chlist, &sctrl->back_op_ch[idx].list, _first, _ps);
|
else
|
break;
|
}
|
}
|
static struct phl_scan_channel *_cmd_scan_select_chnl(
|
void *drv, struct rtw_phl_scan_param *param, u8 band_idx)
|
{
|
struct phl_scan_channel *scan_ch = NULL;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
_os_list* obj = NULL;
|
bool back_op_is_required = false;
|
u8 sctrl_idx = 0;
|
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
return NULL;
|
}
|
back_op_is_required = (sctrl->back_op_ch[0].channel)? true:false;
|
|
|
next_ch:
|
if(pq_pop(drv, &sctrl->chlist, &obj, _first, _ps)) {
|
scan_ch = (struct phl_scan_channel*)obj;
|
|
if(scan_ch->scan_mode == NORMAL_SCAN_MODE) {
|
sctrl->ch_idx++;
|
/* 1- enable, 2- BK_CNT mode, 3- prev is non-op, 4- ch_intvl's turn */
|
if (back_op_is_required && param->back_op.mode == SCAN_BKOP_CNT) {
|
if(!((sctrl->ch_idx + 1) % param->back_op.ch_intv)) {
|
_cmd_scan_enqueue_opch(drv, sctrl);
|
}
|
} else if (back_op_is_required && param->back_op.mode == SCAN_BKOP_TIMER) {
|
|
if ((phl_get_passing_time_ms(param->start_time) -
|
sctrl->last_opch_add_time) >
|
param->back_op.off_ch_dur_ms) {
|
sctrl->last_opch_add_time =
|
phl_get_passing_time_ms(param->start_time);
|
_cmd_scan_enqueue_opch(drv, sctrl);
|
}
|
}
|
}
|
#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
|
else if (scan_ch->scan_mode == P2P_LISTEN_MODE) {
|
if (back_op_is_required && param->back_op.mode == SCAN_BKOP_TIMER) {
|
scan_ch->duration = param->back_op.off_ch_dur_ms;
|
_cmd_scan_enqueue_opch(drv, sctrl);
|
}
|
sctrl->ch_idx++;
|
}
|
#endif
|
sctrl->scan_ch = scan_ch;
|
}
|
else if(sctrl->repeat > 0) {
|
_cmd_scan_update_chlist(drv, param, band_idx,
|
sctrl->is_cckphy);
|
sctrl->ch_idx = 0;
|
/* 255 means loop forever */
|
if (sctrl->repeat != 255)
|
sctrl->repeat--;
|
goto next_ch;
|
}
|
else {
|
return NULL;
|
}
|
|
PHL_INFO("%s:[%d] repeat[%d] ch_idx=[%d], remain=[%d], ch_number=%d, scan_mode= %s\n", __func__,
|
band_idx, sctrl->repeat, sctrl->ch_idx, sctrl->chlist.cnt, sctrl->scan_ch->channel,
|
(sctrl->scan_ch->scan_mode == BACKOP_MODE)? "OP_CH": "Non-OP");
|
|
return sctrl->scan_ch;
|
}
|
|
/* Notification complete */
|
void _cmd_scan_timer_notify_cb(void *priv, struct phl_msg *msg)
|
{
|
struct cmd_scan_ctrl *sctrl = (struct cmd_scan_ctrl *)priv;
|
|
if (IS_MSG_CANNOT_IO(msg->msg_id)) {
|
PHL_ERR("%s: LISTEN_STATE_EXPIRE failure by CANNOT IO\n", __func__);
|
return;
|
}
|
|
if(IS_MSG_CLR_SNDR(msg->msg_id)) {
|
/* Last event occured MSG_STATUS_PENDING */
|
PHL_ERR("%s: LISTEN_STATE_EXPIRE pending Occurred!\n", __func__);
|
_cmd_scan_timer((void *)sctrl);
|
}
|
else if (IS_MSG_CANCEL(msg->msg_id)) {
|
PHL_ERR("%s: LISTEN_STATE_EXPIRE abort Occurred!\n", __func__);
|
return;
|
}
|
}
|
|
static void _cmd_scan_timer(void *context)
|
{
|
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
|
struct cmd_scan_ctrl *sctrl = (struct cmd_scan_ctrl *)context;
|
struct phl_info_t *phl_info = wrole_to_phl(sctrl->wrole);
|
struct rtw_wifi_role_link_t *rlink = sctrl_to_rlink(sctrl, RTW_RLINK_PRIMARY);
|
u8 band_idx = rlink->hw_band;
|
|
struct phl_msg msg = {0};
|
struct phl_msg_attribute attr = {0};
|
|
PHL_INFO("%s: band_idx=%d\n", __func__, band_idx);
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
|
/** When listen state of each channel entry expired,
|
* timer callback send MSG_EVT_LISTEN_STATE_EXPIRE for additional condition check
|
* If nothing specitail occured, then send MSG_EVT_SWCH_START to proceed for the rest of channel list
|
* therefore, additional process delay for MSG_EVT_LISTEN_STATE_EXPIRE would prolong listen period
|
* */
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_LISTEN_STATE_EXPIRE);
|
msg.band_idx = band_idx;
|
|
attr.completion.completion = _cmd_scan_timer_notify_cb;
|
attr.completion.priv = sctrl;
|
|
phl_status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
|
if(phl_status != RTW_PHL_STATUS_SUCCESS)
|
PHL_ERR("%s: [SCAN_TIMER] phl_disp_eng_send_msg failed(%X) !\n", __func__, phl_status);
|
}
|
|
/* Notification complete */
|
void _cmd_swch_done_notify_cb(
|
void *drv, struct phl_msg *msg)
|
{
|
if (msg->inbuf) {
|
_os_mem_free(drv, msg->inbuf, msg->inlen);
|
}
|
}
|
|
enum rtw_phl_status _cmd_swch_done_notify(
|
void *dispr, void *drv, struct rtw_phl_scan_param *param, u8 sctrl_idx)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
struct cmd_scan_ctrl *sctrl = ¶m->sctrl[sctrl_idx];
|
struct phl_info_t *phl_info = wrole_to_phl(sctrl->wrole);
|
struct phl_scan_channel *scan_ch = sctrl->scan_ch;
|
struct phl_msg msg = {0};
|
struct phl_msg_attribute attr = {0};
|
u8 *info = NULL;
|
u8 band_idx = 0;
|
|
info = _os_mem_alloc(drv, sizeof(struct phl_scan_channel));
|
if (info == NULL) {
|
PHL_ERR("%s: [SWCH_DONE] alloc buffer failed!\n", __func__);
|
return RTW_PHL_STATUS_FAILURE;
|
}
|
|
_os_mem_cpy(drv, info, scan_ch, sizeof(*scan_ch));
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SWCH_DONE);
|
|
attr.opt = MSG_OPT_CLR_SNDR_MSG_IF_PENDING;
|
attr.completion.completion = _cmd_swch_done_notify_cb;
|
attr.completion.priv = drv;
|
|
msg.inbuf = info;
|
msg.inlen = sizeof(*scan_ch);
|
msg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
msg.rsvd[1].ptr = (u8*)&sctrl->wrole->rlink[RTW_RLINK_PRIMARY];
|
phl_dispr_get_idx(dispr, &band_idx);
|
msg.band_idx = band_idx;
|
pstatus = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS) {
|
PHL_ERR("%s: [SWCH_DONE] phl_disp_eng_send_msg failed!\n", __func__);
|
_os_mem_free(drv, info, sizeof(struct phl_scan_channel));
|
}
|
return pstatus;
|
}
|
|
void _cmd_scan_end(
|
void *drv, struct rtw_phl_scan_param *param,
|
u8 band_idx)
|
{
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
struct phl_info_t *phl_info = phl_com->phl_priv;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
bool indicate = true;
|
u8 sctrl_idx = 0xff;
|
|
PHL_INFO("_cmd_scan_end \n");
|
#ifdef CONFIG_PHL_SCANOFLD
|
if (param->mode == SCAN_MD_FW) {
|
phl_cmd_scanofld_end(drv, param, band_idx);
|
return;
|
}
|
#endif
|
|
if((param->sctrl_num > 1) &&
|
!TEST_SCAN_FLAGS(param->state, CMD_SCAN_END)) {
|
indicate = false;
|
}
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_END);
|
|
param->end_time = _os_get_cur_time_ms();
|
|
/* dump scan time */
|
param->total_scan_time =
|
phl_get_passing_time_ms(param->enqueue_time);
|
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
goto error;
|
}
|
|
sctrl->scan_ch = NULL;
|
|
/* acquire state */
|
_os_cancel_timer(drv, &sctrl->scan_timer);
|
_os_release_timer(drv, &sctrl->scan_timer);
|
|
if (TEST_SCAN_FLAG(param->state, band_idx, CMD_SCAN_STARTED)) {
|
if (!TEST_SCAN_FLAG(param->state, band_idx, CMD_SCAN_DF_IO)) {
|
rtw_hal_com_scan_restore_tx_lifetime(phl_info->hal, band_idx);
|
|
rtw_hal_scan_set_rxfltr_by_mode(phl_info->hal, band_idx,
|
false, &sctrl->fltr_mode);
|
rtw_hal_scan_pause_tx_fifo(phl_info->hal, band_idx, false);
|
|
rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_END, band_idx);
|
} else {
|
rtw_hal_pause_tx_fifo_sw(phl_info->hal, band_idx, false,
|
PAUSE_RSON_NOR_SCAN);
|
}
|
}
|
error:
|
if (indicate) {
|
_cmd_scan_req_deinit(phl_info, param);
|
param->sctrl_num = 0;
|
}
|
|
PHL_INFO("[cmd_scan][%d]:: sctrl_idx[%d] param->state(0x%X), result(0x%X)\n",
|
band_idx, sctrl_idx, param->state, param->result);
|
|
if (indicate && param->ops->scan_complete)
|
param->ops->scan_complete(param->priv, param);
|
}
|
|
/* Notification complete */
|
void _cmd_abort_notify_cb(
|
void *drv, struct phl_msg *msg)
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param *)msg->inbuf;
|
|
if (IS_MSG_CANNOT_IO(msg->msg_id))
|
SET_SCAN_FLAG(param->state, msg->band_idx, CMD_SCAN_DF_IO);
|
|
_cmd_scan_end(drv, param, msg->band_idx);
|
}
|
|
void _cmd_abort_notify(void *dispr, void *drv,
|
struct rtw_phl_scan_param *param, bool abort)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
struct phl_msg msg = {0};
|
struct phl_msg_attribute attr = {0};
|
struct phl_info_t *phl = (struct phl_info_t *) phl_com->phl_priv;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
bool indicate = true;
|
u8 band_idx = 0xff, sctrl_idx = 0xff;
|
|
phl_dispr_get_idx(dispr, &band_idx);
|
|
if(TEST_SCAN_FLAG(param->state, band_idx, CMD_SCAN_ACQUIRE))
|
{
|
param->result = SCAN_REQ_CANCEL;
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SCAN_END);
|
|
msg.inbuf = (u8*)param; /* for _cmd_abort_notify_cb */
|
msg.band_idx = band_idx;
|
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if (sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
_cmd_abort_notify_cb(drv, &msg);
|
return;
|
}
|
msg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
|
if (abort)
|
attr.opt = MSG_OPT_SEND_IN_ABORT;
|
attr.completion.completion = _cmd_abort_notify_cb;
|
attr.completion.priv = drv;
|
|
pstatus = phl_disp_eng_send_msg(phl, &msg, &attr, NULL);
|
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
|
/* (1) dispr_stop
|
(2) idle msg empty .*/
|
|
PHL_ERR("%s :: [Abort] dispr_send_msg failed (0x%X)\n",
|
__func__, pstatus);
|
|
if(pstatus == RTW_PHL_STATUS_UNEXPECTED_ERROR ||
|
TEST_STATUS_FLAG(phl_com->dev_state, RTW_DEV_SURPRISE_REMOVAL)) {
|
/* clean sw resource only */
|
/* (1) driver is going to unload */
|
/* (2) Supprise remove */
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_DF_IO);
|
}
|
_cmd_abort_notify_cb(drv, &msg);
|
}
|
}
|
else {
|
if((param->sctrl_num > 1) &&
|
!TEST_SCAN_FLAGS(param->state, CMD_SCAN_END)) {
|
indicate = false;
|
}
|
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_END);
|
|
param->result = SCAN_REQ_ABORT;
|
|
if(indicate) {
|
_cmd_scan_req_deinit(phl, param);
|
param->sctrl_num = 0;
|
}
|
|
if (indicate && param->ops->scan_complete)
|
param->ops->scan_complete(param->priv, param);
|
}
|
}
|
|
enum phl_mdl_ret_code _cmd_scan_fail_ev_hdlr(
|
void* dispr, void* priv, struct phl_msg* msg)
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
struct phl_info_t *phl_info = phl_com->phl_priv;
|
void *d = phlcom_to_drvpriv(phl_com);
|
u8 band_idx = 0xff, sctrl_idx = 0xff;
|
struct phl_msg nextmsg = {0};
|
struct phl_msg_attribute attr = {0};
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
|
SET_MSG_MDL_ID_FIELD(nextmsg.msg_id, PHL_FG_MDL_SCAN);
|
phl_dispr_get_idx(dispr, &band_idx);
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
return MDL_RET_FAIL;
|
}
|
|
nextmsg.band_idx = band_idx;
|
switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
|
case MSG_EVT_SCAN_START:
|
/* fall through */
|
case MSG_EVT_LISTEN_STATE_EXPIRE:
|
/* fall through */
|
case MSG_EVT_SWCH_START:
|
/* fall through */
|
case MSG_EVT_SWCH_DONE:
|
PHL_INFO("[%d]SCAN_START/SWCH_START/SWCH_DONE:: failed/timeout handler \n", band_idx);
|
|
SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SCAN_END);
|
nextmsg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
|
pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS)
|
PHL_ERR("%s :: [SWCH_START] phl_disp_eng_send_msg failed\n", __func__);
|
break;
|
|
case MSG_EVT_SCAN_END:
|
// free token
|
// release timer
|
PHL_INFO("[%d]MSG_EVT_SCAN_END:: failed/timeout handler \n", band_idx);
|
pstatus = phl_disp_eng_free_token(phl_info, band_idx, &sctrl->token);
|
if (pstatus == RTW_PHL_STATUS_SUCCESS) {
|
if (IS_MSG_CANNOT_IO(msg->msg_id))
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_DF_IO);
|
_cmd_scan_end(d, param, band_idx);
|
}
|
break;
|
|
default:
|
PHL_INFO("%s, unknown state : %d \n", __func__,
|
MSG_EVT_ID_FIELD(msg->msg_id));
|
/* unknown state */
|
break;
|
}
|
|
return MDL_RET_SUCCESS;
|
}
|
|
enum phl_mdl_ret_code _cmd_scan_hdl_external_evt(
|
void* dispr, void* priv, struct phl_msg* msg)
|
{
|
PHL_DBG("%s :: From others MDL =%d , EVT_ID=%d\n", __func__,
|
MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
|
return MDL_RET_IGNORE;
|
}
|
|
u8 phl_cmd_chk_ext_act_scan(struct rtw_phl_scan_param *param, u8 sctrl_idx)
|
{
|
struct cmd_scan_ctrl *sctrl = ¶m->sctrl[sctrl_idx];
|
/** suppose to query the time of last recieved beacon in current channel here
|
* then change state to EXT_ACT_SCAN_TRIGGER if needed
|
* but, PHL does not store bss list at the moment, therefore,
|
* core layer use set_info (FG_REQ_OP_NOTIFY_BCN_RCV) to notify scan module incoming bcn
|
* and change state to EXT_ACT_SCAN_TRIGGER accordingly.
|
*/
|
if (sctrl->scan_ch->type == RTW_PHL_SCAN_PASSIVE &&
|
sctrl->scan_ch->ext_act_scan == EXT_ACT_SCAN_TRIGGER) {
|
if (param->ops->scan_issue_pbreq)
|
param->ops->scan_issue_pbreq(param->priv, param, sctrl_idx);
|
sctrl->scan_ch->ext_act_scan = EXT_ACT_SCAN_DONE;
|
return true;
|
}
|
return false;
|
}
|
|
/*
|
* Return value :
|
* false : cancel cur channel.
|
* true : keep scan on cur channel.
|
*/
|
static bool _handle_probing(void *d, struct rtw_phl_scan_param *param, u8 sctrl_idx)
|
{
|
struct cmd_scan_ctrl *sctrl = ¶m->sctrl[sctrl_idx];
|
struct phl_scan_channel *scan_ch = sctrl->scan_ch;
|
u32 dur = 0, diff_t = 0, probe_t = 0;
|
bool check_cancel = true;
|
|
scan_ch->pass_t = phl_get_passing_time_ms(scan_ch->start_t);
|
if (scan_ch->pass_t >= scan_ch->last_t)
|
diff_t = scan_ch->pass_t - scan_ch->last_t;
|
PHL_INFO("[probing], band %d, ch %d, pass_t %d, last_t %d, diff_t %d, duration %d\n",
|
scan_ch->band, scan_ch->channel, scan_ch->pass_t,
|
scan_ch->last_t, diff_t, scan_ch->duration);
|
|
/* DFS, tx probe and extend scan period */
|
if (phl_cmd_chk_ext_act_scan(param, sctrl_idx)) {
|
scan_ch->duration += (u16)param->ext_act_scan_period;
|
check_cancel = false;
|
PHL_INFO("[probing], DFS extend period to %d !\n",
|
scan_ch->duration);
|
}
|
|
dur = scan_ch->duration;
|
if (scan_ch->pass_t >= dur) {
|
PHL_INFO("[probing], expired, channel end !!\n");
|
return false;
|
}
|
|
scan_ch->remain_t = (u32)(dur - scan_ch->pass_t);
|
PHL_INFO("[probing], remain_t %d \n", scan_ch->remain_t);
|
|
if (diff_t >= DEF_PROBE_PERIOD) {
|
scan_ch->last_t = scan_ch->pass_t;
|
|
if (param->ops->scan_ch_cancel && check_cancel) {
|
if (param->ops->scan_ch_cancel(param->priv, param, sctrl_idx)) {
|
PHL_INFO("[probing], channel canceled !\n");
|
return false;
|
}
|
}
|
|
/* core probe handler */
|
param->ops->scan_probe(param->priv, param, sctrl_idx);
|
}
|
|
if (scan_ch->remain_t <= param->probe_t)
|
probe_t = scan_ch->remain_t;
|
else
|
probe_t = param->probe_t;
|
|
_os_set_timer(d, &sctrl->scan_timer, probe_t);
|
|
return true;
|
}
|
|
void
|
_cmd_scan_start(struct phl_info_t *phl_info,
|
struct cmd_scan_ctrl *sctrl,
|
u8 band_idx)
|
{
|
rtw_hal_scan_pause_tx_fifo(phl_info->hal, band_idx, true);
|
rtw_hal_scan_set_rxfltr_by_mode(phl_info->hal, band_idx,
|
true, &sctrl->fltr_mode);
|
rtw_hal_com_scan_set_tx_lifetime(phl_info->hal, band_idx);
|
rtw_hal_notification(phl_info->hal, MSG_EVT_SCAN_START, band_idx);
|
}
|
|
enum phl_mdl_ret_code _cmd_scan_hdl_internal_evt(
|
void* dispr, void* priv, struct phl_msg* msg)
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
struct phl_info_t *phl_info = phl_com->phl_priv;
|
void *d = phlcom_to_drvpriv(phl_com);
|
u32 diff_time = 0, probe_t = 0;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
struct phl_msg nextmsg = {0};
|
struct phl_msg_attribute attr = {0};
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
u8 band_idx = 0xff, sctrl_idx = 0xff;
|
struct phl_scan_channel *scan_ch = NULL;
|
bool tx_pause = true;
|
struct rtw_chan_def chdef = {0};
|
|
diff_time = phl_get_passing_time_ms(param->enqueue_time);
|
|
if (param->max_scan_time && diff_time >= param->max_scan_time) {
|
PHL_WARN("%s:: Timeout! %d > max_time %d\n",
|
__func__, diff_time, param->max_scan_time);
|
|
/* Abort scan request */
|
/* Based on [CN3AXSW-552]
|
* ex. max_scan_time = 4sec
|
* Usb dongle would abort scan_req in 29~33th chnl
|
* If chnllist insert op-chnl, scan_req would be aborted in 21~23th chnl.
|
* It means that usb dongle always can't do fully scan.
|
* So, abort scan_req or not, depend on core layer.
|
*/
|
_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
|
return MDL_RET_FAIL;
|
}
|
else {
|
PHL_INFO("\t[cmd_scan]:: TimeIntvl: %u \n", diff_time);
|
}
|
|
#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
|
if (param->max_listen_time && diff_time >= param->max_listen_time) {
|
PHL_WARN("%s:: Timeout! %d > max_listen_time %d\n",
|
__func__, diff_time, param->max_listen_time);
|
#if 0
|
_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
|
return MDL_RET_FAIL;
|
#endif
|
}
|
#endif
|
|
phl_dispr_get_idx(dispr, &band_idx);
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
return MDL_RET_FAIL;
|
}
|
|
SET_MSG_MDL_ID_FIELD(nextmsg.msg_id, PHL_FG_MDL_SCAN);
|
nextmsg.band_idx = band_idx;
|
|
switch(MSG_EVT_ID_FIELD(msg->msg_id)) {
|
case MSG_EVT_SCAN_START:
|
_cmd_scan_start(phl_info, sctrl, band_idx);
|
|
PHL_INFO("[%d]MSG_EVT_SCAN_START \n", band_idx);
|
/* [scan start notify] */
|
if (!TEST_SCAN_FLAGS(param->state, CMD_SCAN_STARTED)) {
|
if (param->ops->scan_start)
|
param->ops->scan_start(param->priv, param);
|
}
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_STARTED);
|
|
SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SWCH_START);
|
nextmsg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS)
|
PHL_ERR("%s :: [SCAN_START] phl_disp_eng_send_msg failed\n", __func__);
|
break;
|
case MSG_EVT_LISTEN_STATE_EXPIRE:
|
if (!param->ops->scan_probe) {
|
PHL_INFO("[%d]MSG_EVT_LISTEN_STATE_EXPIRE \n", band_idx);
|
if (phl_cmd_chk_ext_act_scan(param, sctrl_idx)) {
|
_os_set_timer(d, &sctrl->scan_timer,
|
param->ext_act_scan_period);
|
PHL_INFO("%s :: extend listen state of ch %d by %d ms, and reset timer\n",
|
__func__, sctrl->scan_ch->channel, param->ext_act_scan_period);
|
break;
|
}
|
} else {
|
if (_handle_probing(d, param, sctrl_idx))
|
break;
|
}
|
|
SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SWCH_START);
|
nextmsg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
|
pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS)
|
PHL_ERR("%s :: [LISTEN_STATE_EXPIRE] dispr_send_msg failed\n", __func__);
|
|
break;
|
|
case MSG_EVT_SWCH_START:
|
/* ycx++
|
ycx > length(yclist) ? SCAN_EV_END : switch channel */
|
|
PHL_INFO("[%d]MSG_EVT_SWCH_START \n", band_idx);
|
|
/* For the first time, param->scan_ch would be NULL */
|
/* Current channel scan_mode */
|
if (sctrl->scan_ch && sctrl->scan_ch->scan_mode == BACKOP_MODE) {
|
tx_pause = false;
|
}
|
|
#ifdef CONFIG_RTW_ACS
|
_cmd_scan_acs_mntr_result(phl_info, band_idx, param, sctrl_idx);
|
#endif
|
|
scan_ch = _cmd_scan_select_chnl(d, param, band_idx);
|
if (scan_ch == NULL) {
|
/* no more channel, we are done */
|
SET_MSG_EVT_ID_FIELD(nextmsg.msg_id, MSG_EVT_SCAN_END);
|
nextmsg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
pstatus = phl_disp_eng_send_msg(phl_info, &nextmsg, &attr, NULL);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS)
|
PHL_ERR("%s :: [SWCH_START] dispr_send_msg failed\n", __func__);
|
break;
|
}
|
|
/* Next channel scan_mode */
|
if ((scan_ch->scan_mode != BACKOP_MODE) && !tx_pause) {
|
/* Tx pause */
|
rtw_hal_scan_pause_tx_fifo(phl_info->hal, band_idx, true);
|
tx_pause = true;
|
}
|
chdef.band = scan_ch->band;
|
chdef.chan = (u8)scan_ch->channel;
|
chdef.bw = scan_ch->bw;
|
chdef.offset = scan_ch->offset;
|
|
if ((scan_ch->scan_mode == BACKOP_MODE))
|
phl_set_ch_bw(phl_info, band_idx, &chdef, RFK_TYPE_SCAN_BK_OP);
|
else
|
phl_set_ch_bw(phl_info, band_idx, &chdef, RFK_TYPE_SCAN_CHG_CH);
|
|
#ifdef CONFIG_RTW_ACS
|
_cmd_scan_acs_mntr_trigger(phl_info, band_idx, param, sctrl_idx);
|
#endif
|
|
if (!BAND_6GHZ(scan_ch->band) &&
|
(scan_ch->scan_mode != BACKOP_MODE) &&
|
(scan_ch->type == RTW_PHL_SCAN_ACTIVE)) {
|
/* Notify RF to do tssi backup */
|
rtw_hal_notification(phl_info->hal, MSG_EVT_SWCH_START, band_idx);
|
if (param->ops->scan_issue_pbreq)
|
param->ops->scan_issue_pbreq(param->priv, param, sctrl_idx);
|
}
|
|
if (param->ops->scan_probe) {
|
scan_ch->start_t = _os_get_cur_time_ms();
|
scan_ch->last_t = 0;
|
scan_ch->pass_t = 0;
|
scan_ch->remain_t = scan_ch->duration;
|
if (scan_ch->remain_t >= param->probe_t)
|
probe_t = param->probe_t;
|
else
|
probe_t = scan_ch->remain_t;
|
} else {
|
probe_t = scan_ch->duration;
|
}
|
|
_os_set_timer(d, &sctrl->scan_timer, probe_t);
|
|
if ((scan_ch->scan_mode == BACKOP_MODE) && tx_pause) {
|
/* Tx un-pause */
|
rtw_hal_scan_pause_tx_fifo(phl_info->hal, band_idx, false);
|
}
|
#ifdef DBG_SCAN_CHAN_DUMP
|
PHL_INFO("[SCAN] band:%d chan:%d bw:%d offset:%d duration:%d (ms)\n",
|
scan_ch->band, scan_ch->channel, scan_ch->bw,
|
scan_ch->offset, scan_ch->duration);
|
#endif
|
|
pstatus = _cmd_swch_done_notify(dispr, d, param, sctrl_idx);
|
break;
|
|
case MSG_EVT_SWCH_DONE:
|
if (param->ops->scan_ch_ready)
|
param->ops->scan_ch_ready(param->priv, param, sctrl_idx);
|
|
PHL_INFO("\tMSG_EVT_SWCH_DONE :: duration=%d\n", sctrl->scan_ch->duration);
|
break;
|
|
case MSG_EVT_SCAN_END:
|
PHL_INFO("[%d]MSG_EVT_SCAN_END \n", band_idx);
|
pstatus = phl_disp_eng_free_token(phl_info, band_idx, &sctrl->token);
|
if(pstatus == RTW_PHL_STATUS_SUCCESS) {
|
|
param->result = SCAN_REQ_COMPLETE;
|
_cmd_scan_end(d, param, band_idx);
|
}
|
else
|
PHL_WARN("%s :: [SCAN_END] Abort occurred, skip!\n", __func__);
|
|
break;
|
|
default:
|
/* unknown state */
|
break;
|
}
|
|
return MDL_RET_SUCCESS;
|
}
|
|
|
enum phl_mdl_ret_code _phl_cmd_scan_req_acquired(
|
void* dispr, void* priv)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
void *d = phlcom_to_drvpriv(phl_com);
|
u32 diff_time = 0;
|
struct phl_info_t *phl_info = phl_com->phl_priv;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
u8 band_idx = 0xff, sctrl_idx = 0xff;
|
struct phl_msg msg = {0};
|
struct phl_msg_attribute attr = {0};
|
|
FUNCIN();
|
|
if(!param->start_time)
|
param->start_time = _os_get_cur_time_ms();
|
|
/* check max scan time */
|
if (param->max_scan_time > 0) {
|
diff_time = phl_get_passing_time_ms(param->enqueue_time);
|
|
if (diff_time >= param->max_scan_time) {
|
PHL_WARN("%s:: Timeout! %u > max_time %d\n",
|
__func__, diff_time, param->max_scan_time);
|
goto error;
|
}
|
}
|
|
phl_dispr_get_idx(dispr, &band_idx);
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
goto error;
|
}
|
|
if (param->probe_t == 0)
|
param->probe_t = DEF_PROBE_PERIOD;
|
|
_os_init_timer(d, &sctrl->scan_timer, _cmd_scan_timer,
|
sctrl, "phl_cmd_scan_req_timer");
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SCAN_START);
|
msg.rsvd[0].ptr = (u8*)sctrl->wrole;
|
msg.band_idx = band_idx;
|
pstatus = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
|
|
if(pstatus != RTW_PHL_STATUS_SUCCESS) {
|
_os_release_timer(d, &sctrl->scan_timer);
|
// take care another fg cmd
|
goto error;
|
}
|
else {
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_ACQUIRE);
|
return MDL_RET_SUCCESS;
|
}
|
|
error:
|
_cmd_abort_notify(dispr, d, param, false);
|
return MDL_RET_FAIL;
|
}
|
|
enum phl_mdl_ret_code _phl_cmd_scan_req_abort(
|
void* dispr, void* priv)
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
void *d = phlcom_to_drvpriv(phl_com);
|
|
PHL_INFO("_phl_cmd_scan_req_abort \n");
|
_cmd_abort_notify(dispr, d, param, true);
|
return MDL_RET_SUCCESS;
|
}
|
|
enum phl_mdl_ret_code _phl_cmd_scan_req_ev_hdlr(
|
void* dispr, void* priv,
|
struct phl_msg* msg)
|
{
|
enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
|
if(IS_MSG_FAIL(msg->msg_id)) {
|
PHL_INFO("%s :: MSG(%d)_FAIL - EVT_ID=%d \n", __func__,
|
MSG_MDL_ID_FIELD(msg->msg_id), MSG_EVT_ID_FIELD(msg->msg_id));
|
|
_cmd_scan_fail_ev_hdlr(dispr, priv, msg);
|
return MDL_RET_FAIL;
|
}
|
|
switch(MSG_MDL_ID_FIELD(msg->msg_id)) {
|
case PHL_FG_MDL_SCAN:
|
|
#ifdef CONFIG_PHL_SCANOFLD
|
/* Scan offload */
|
if (param->mode == SCAN_MD_FW) {
|
ret = phl_cmd_scanofld_hdl_internal_evt(dispr,
|
priv,
|
(void *)msg);
|
} else
|
#endif
|
{
|
ret = _cmd_scan_hdl_internal_evt(dispr, priv, msg);
|
}
|
break;
|
|
default:
|
ret = _cmd_scan_hdl_external_evt(dispr, priv, msg);
|
break;
|
}
|
return ret;
|
}
|
|
enum phl_mdl_ret_code _phl_cmd_scan_req_set_info(
|
void* dispr, void* priv, struct phl_module_op_info* info)
|
{
|
enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
|
u8 band_idx = 0;
|
|
phl_dispr_get_idx(dispr, &band_idx);
|
|
switch(info->op_code) {
|
case FG_REQ_OP_NOTIFY_BCN_RCV:
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
struct phl_scan_channel *scan_ch = NULL;
|
u16 channel = 0;
|
u8 sctrl_idx = 0;
|
|
/* this workaround might have race condition with background thread*/
|
channel = *(u8*)info->inbuf;
|
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s[%d]: find sctrl failed\n", __func__, band_idx);
|
return ret;
|
}
|
|
scan_ch = sctrl->scan_ch;
|
|
if (scan_ch &&
|
scan_ch->channel == channel &&
|
scan_ch->ext_act_scan == EXT_ACT_SCAN_ENABLE) {
|
scan_ch->ext_act_scan = EXT_ACT_SCAN_TRIGGER;
|
PHL_INFO("%s[%d] :: channel %d extend for active scan\n", __func__, band_idx, channel);
|
}
|
if (scan_ch &&
|
scan_ch->channel != channel)
|
PHL_DBG("%s[%d] :: sctrl[%d] channel %d mismatch from listen channel %d\n",
|
__func__, band_idx, sctrl_idx, channel, scan_ch->channel);
|
ret = MDL_RET_SUCCESS;
|
}
|
break;
|
default:
|
break;
|
}
|
|
/* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
|
return ret;
|
}
|
|
enum phl_mdl_ret_code _phl_cmd_scan_req_query_info(
|
void* dispr, void* priv, struct phl_module_op_info* info)
|
{
|
struct rtw_phl_scan_param *param = (struct rtw_phl_scan_param*)priv;
|
struct rtw_phl_com_t *phl_com = param_to_phlcom(param);
|
void *d = phlcom_to_drvpriv(phl_com);
|
struct cmd_scan_ctrl *sctrl = NULL;
|
u8 ucInfo = 0;
|
void* pInfo = NULL;
|
u8 band_idx = 0, sctrl_idx = 0;
|
|
enum phl_mdl_ret_code ret = MDL_RET_IGNORE;
|
phl_dispr_get_idx(dispr, &band_idx);
|
sctrl_idx = phl_cmd_scan_ctrl(param, band_idx, &sctrl);
|
if(sctrl == NULL) {
|
PHL_ERR("%s: find sctrl failed\n", __func__);
|
return MDL_RET_FAIL;
|
}
|
|
/* PHL_INFO(" %s :: info->op_code=%d \n", __func__, info->op_code); */
|
|
switch(info->op_code) {
|
case FG_REQ_OP_GET_ROLE:
|
info->outbuf = (u8*)sctrl->wrole;
|
ret = MDL_RET_SUCCESS;
|
break;
|
case FG_REQ_OP_GET_ROLE_LINK:
|
info->outbuf = (u8*)&sctrl->wrole->rlink[RTW_RLINK_PRIMARY];
|
ret = MDL_RET_SUCCESS;
|
break;
|
|
case FG_REQ_OP_GET_MDL_ID:
|
ucInfo= PHL_FG_MDL_SCAN;
|
pInfo = (void*) &ucInfo;
|
info->outlen=1;
|
_os_mem_cpy(d, (void*)info->outbuf, pInfo, info->outlen);
|
ret = MDL_RET_SUCCESS;
|
break;
|
default:
|
break;
|
}
|
|
return ret;
|
}
|
|
static struct rtw_wifi_role_t *
|
_phl_cmd_scan_select_wrole(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param, u8 sctrl_idx)
|
{
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
|
if(sctrl_idx == 0) {
|
return param->wifi_role; /* sctrl[0]: original band_idx */
|
} else {
|
u8 band_idx = HW_BAND_1;
|
|
rlink = &(param->wifi_role->rlink[RTW_RLINK_PRIMARY]);
|
if(rlink->hw_band == HW_BAND_1)
|
band_idx = HW_BAND_0;
|
#ifdef CONFIG_DBCC_P2P_BG_LISTEN
|
if (param->back_op.mode == SCAN_BKOP_TIMER)
|
rlink = phl_mr_get_first_rlink_by_band_ex(phl_info, band_idx, false);
|
else
|
#endif
|
rlink = phl_mr_get_first_rlink_by_band(phl_info, band_idx);
|
|
if (rlink != NULL)
|
return rlink->wrole;
|
else
|
return NULL;
|
}
|
}
|
|
#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
|
static void
|
_cmd_scan_update_chparam(void *drv, struct rtw_phl_scan_param *param, u8 sctrl_idx)
|
{
|
struct cmd_scan_ctrl *sctrl = ¶m->sctrl[sctrl_idx];
|
//u8 idx = 0;
|
u16 scan_section_ms = 0;
|
u16 total_scan_ms = 0;
|
struct phl_scan_channel *ch;
|
_os_list *node = NULL;
|
|
/*for(idx = 0; idx < param->ch_num; idx++) {
|
if (param->ch[idx].scan_mode == P2P_LISTEN_MODE) {
|
param->max_listen_time = param->ch[idx].duration;
|
total_scan_ms = param->ch[idx].duration;
|
break;
|
}
|
}*/
|
|
if (pq_get_front(drv, &sctrl->chlist, &node, _ps) == false) {
|
PHL_ERR("%s get sctrl->chlist failed\n", __func__);
|
return;
|
}
|
|
do {
|
ch = (struct phl_scan_channel*)node;
|
if (ch->scan_mode == P2P_LISTEN_MODE) {
|
param->max_listen_time = ch->duration;
|
total_scan_ms = ch->duration;
|
break;
|
}
|
} while(pq_get_next(drv, &sctrl->chlist, node, &node, _ps));
|
|
scan_section_ms = param->back_op.ch_dur_ms + param->back_op.off_ch_dur_ms;
|
if (scan_section_ms)
|
sctrl->repeat = total_scan_ms / scan_section_ms;
|
}
|
#endif
|
|
static u16
|
_assign_opch_duration(struct scan_backop_para *bkop_para, u8 band_idx,
|
struct rtw_chan_def *chdef)
|
{
|
u16 max_dur = 0;
|
u8 i = 0;
|
struct scan_bkop_link_info *link_info = NULL;
|
|
/* SCAN_BKOP_SEL_AUTO */
|
if (bkop_para->sel == SCAN_BKOP_SEL_AUTO)
|
return bkop_para->ch_dur_ms;
|
|
/* SCAN_BKOP_SEL_MANUAL, get the max duration in the same channel and band_idx from the role_link list
|
* e.g. link_info_num = 2, chdef->ch = 6, band_idx = 0,
|
* (1) (a) phy 0, ch6, dur=40 (b) phy 0, ch6 dur=60, then return 60
|
* (2) (a) phy 0, ch6, dur=30 (b) phy 1, ch6 dur=80, then return 30
|
* (3) (a) phy 0, ch6, dur=50 (b) phy 0, ch11 dur=70, then return 50
|
*/
|
for (i = 0; i < bkop_para->link_info_num; i++) {
|
link_info = &bkop_para->link_info_list[i];
|
if (link_info->rlink->hw_band == band_idx) {
|
if (link_info->rlink->chandef.band == chdef->band &&
|
link_info->rlink->chandef.chan == chdef->chan) {
|
if (link_info->ch_dur_ms > max_dur)
|
max_dur = link_info->ch_dur_ms;
|
}
|
}
|
}
|
|
return max_dur == 0 ? bkop_para->ch_dur_ms : max_dur;
|
}
|
|
static u8
|
_assign_opch_list(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param,
|
u8 band_idx, struct cmd_scan_ctrl *sctrl)
|
{
|
u8 op_num = 0, i = 0;
|
struct rtw_chan_def chdef_list[MAX_WIFI_ROLE_NUMBER] = {0};
|
struct rtw_wifi_role_link_t *rlink_list[MAX_WIFI_ROLE_NUMBER] = {0};
|
u8 rlink_num = 0;
|
|
if (param->back_op.sel == SCAN_BKOP_SEL_AUTO) {
|
op_num = rtw_phl_mr_get_opch_list(phl_info,
|
band_idx,
|
chdef_list,
|
(u8)MAX_WIFI_ROLE_NUMBER,
|
NULL,
|
0);
|
} else if (param->back_op.sel == SCAN_BKOP_SEL_MANUAL) {
|
/* list all role link */
|
rlink_num = param->back_op.link_info_num;
|
for (i = 0; i < rlink_num; i++)
|
rlink_list[i] = param->back_op.link_info_list[i].rlink;
|
|
op_num = rtw_phl_mr_get_opch_list(phl_info,
|
band_idx,
|
chdef_list,
|
(u8)MAX_WIFI_ROLE_NUMBER,
|
rlink_list,
|
rlink_num);
|
}
|
|
for (i = 0; i < op_num; i++) {
|
if (chdef_list[i].chan) {
|
INIT_LIST_HEAD(&sctrl->back_op_ch[i].list);
|
sctrl->back_op_ch[i].band = chdef_list[i].band;
|
sctrl->back_op_ch[i].channel = chdef_list[i].chan;
|
sctrl->back_op_ch[i].bw = chdef_list[i].bw;
|
sctrl->back_op_ch[i].offset = chdef_list[i].offset;
|
sctrl->back_op_ch[i].duration =
|
_assign_opch_duration(¶m->back_op, band_idx,
|
&(chdef_list[i]));
|
sctrl->back_op_ch[i].scan_mode = BACKOP_MODE;
|
}
|
}
|
|
return op_num;
|
}
|
|
static enum rtw_phl_status
|
_cmd_scan_req_init(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param)
|
{
|
void *drv = phl_to_drvpriv(phl_info);
|
struct rtw_chan_def chdef_list[MAX_WIFI_ROLE_NUMBER] = {0};
|
u8 sctrl_idx = 0;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
u8 band_idx = 0, op_num = 0;
|
bool is_cckphy = true;
|
|
param->enqueue_time = _os_get_cur_time_ms();
|
param->start_time = 0;
|
param->state = 0;
|
for(sctrl_idx = 0; sctrl_idx < param->sctrl_num; sctrl_idx++) {
|
_os_mem_set(drv, &chdef_list, 0, sizeof(struct rtw_chan_def) * MAX_WIFI_ROLE_NUMBER);
|
|
sctrl = ¶m->sctrl[sctrl_idx];
|
sctrl->repeat = param->repeat;
|
sctrl->ch_idx = -1;
|
sctrl->last_opch_add_time = 0;
|
pq_init(drv, &sctrl->chlist);
|
|
sctrl->wrole = _phl_cmd_scan_select_wrole(phl_info, param, sctrl_idx);
|
if(sctrl->wrole == NULL) {
|
PHL_ERR("%s sctrl->wrole == NULL\n", __func__);
|
_os_warn_on(1);
|
return RTW_PHL_STATUS_FAILURE;
|
}
|
|
rlink = sctrl_to_rlink(sctrl, RTW_RLINK_PRIMARY);
|
band_idx = rlink->hw_band;
|
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_INIT);
|
|
#ifdef CONFIG_DBCC_SUPPORT
|
is_cckphy = phl_mr_is_cckphy(phl_info, band_idx);
|
#endif
|
_cmd_scan_update_chlist(drv, param, sctrl_idx, is_cckphy);
|
|
if (param->back_op.mode != SCAN_BKOP_NONE) {
|
op_num = _assign_opch_list(phl_info, param, band_idx, sctrl);
|
#ifdef CONFIG_PHL_CMD_SCAN_BKOP_TIME
|
if (op_num && param->back_op.mode == SCAN_BKOP_TIMER)
|
_cmd_scan_update_chparam(drv, param, sctrl_idx);
|
#endif
|
}
|
|
#ifdef DBG_SCAN_CHAN_DUMP
|
/* debug information*/
|
_cmd_estimated_swch_seq(drv, param, op_num, sctrl_idx);
|
#endif
|
}
|
|
return RTW_PHL_STATUS_SUCCESS;
|
}
|
|
static void
|
_cmd_scan_req_deinit(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param)
|
{
|
void *drv = phl_to_drvpriv(phl_info);
|
struct cmd_scan_ctrl *sctrl = NULL;
|
u8 sctrl_idx = 0;
|
|
for(sctrl_idx = 0; sctrl_idx < param->sctrl_num; sctrl_idx++) {
|
sctrl = ¶m->sctrl[sctrl_idx];
|
pq_deinit(drv, &sctrl->chlist);
|
sctrl->scan_ch = NULL;
|
}
|
}
|
|
enum rtw_phl_status
|
_phl_cmd_scan_req_submit(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
struct phl_cmd_token_req fgreq[HW_BAND_MAX] = {0};
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
u8 sctrl_idx = 0, band_idx = 0xff;
|
|
for(sctrl_idx = 0; sctrl_idx < param->sctrl_num; sctrl_idx++) {
|
/* Fill foreground command request */
|
fgreq[sctrl_idx].module_id= PHL_FG_MDL_SCAN;
|
fgreq[sctrl_idx].priv = param;
|
|
fgreq[sctrl_idx].role = param->sctrl[sctrl_idx].wrole;
|
|
fgreq[sctrl_idx].acquired = _phl_cmd_scan_req_acquired;
|
fgreq[sctrl_idx].abort = _phl_cmd_scan_req_abort;
|
fgreq[sctrl_idx].msg_hdlr = _phl_cmd_scan_req_ev_hdlr;
|
fgreq[sctrl_idx].set_info = _phl_cmd_scan_req_set_info;
|
fgreq[sctrl_idx].query_info = _phl_cmd_scan_req_query_info;
|
|
rlink = sctrl_to_rlink((¶m->sctrl[sctrl_idx]), RTW_RLINK_PRIMARY);
|
band_idx = rlink->hw_band;
|
|
if(param->sctrl[sctrl_idx].chlist.cnt) {
|
/* cmd_dispatcher would copy whole phl_cmd_token_req */
|
pstatus = phl_disp_eng_add_token_req(phl_info, band_idx, &fgreq[sctrl_idx], ¶m->sctrl[sctrl_idx].token);
|
}
|
else {
|
/*if chlist have no element */
|
pstatus = RTW_PHL_STATUS_SUCCESS;
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_END);
|
}
|
|
if((pstatus == RTW_PHL_STATUS_SUCCESS) ||
|
(pstatus == RTW_PHL_STATUS_PENDING)) {
|
//if(sctrl_idx == 0) param->token = param->sctrl[0].token;
|
}
|
else {
|
if(sctrl_idx == 0) {
|
PHL_ERR("%s: 1st cmd_scan failed!\n", __func__);
|
return pstatus;
|
}
|
else {
|
/* 2nd FG cmd failed */
|
SET_SCAN_FLAG(param->state, band_idx, CMD_SCAN_END);
|
}
|
}
|
|
}
|
return RTW_PHL_STATUS_SUCCESS;
|
}
|
|
static u8
|
_cmd_scan_dbcc_policy(struct phl_info_t *phl_info,
|
struct rtw_phl_scan_param *param)
|
{
|
u8 band_idx = 0, valid_role = 0;
|
u8 sctrl_num = 1;
|
|
/* case1: DBCC_en and SCAN_CMD_OPT_DB */
|
if(param->opt == SCAN_CMD_OPT_DB) {
|
for (band_idx = 0; band_idx < HW_BAND_MAX; band_idx++) {
|
if(phl_mr_get_role_by_bandidx(phl_info, band_idx))
|
valid_role = true;
|
else
|
valid_role = false;
|
|
}
|
if(valid_role)
|
sctrl_num = band_idx; /* MAX_BAND_NUM */
|
}
|
/* case2:
|
* - DBCC_en
|
* - scan_req without SCAN_CMD_OPT_DB
|
* - only a cck-phy module
|
* - wrole->hw_band != cckphy
|
* - chlist have 2G
|
*/
|
|
return sctrl_num;
|
}
|
|
/* For EXTERNAL application to request scan (expose) */
|
/* @pscan: scan object
|
* @pbuf: scan parameter, will be freed by caller after retrun
|
*/
|
enum rtw_phl_status rtw_phl_cmd_scan_request(void *phl,
|
struct rtw_phl_scan_param *param)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
void *drv = phl_to_drvpriv(phl_info);
|
|
//Debug log
|
if(param->wifi_role->rlink[RTW_RLINK_PRIMARY].hw_band == HW_BAND_1)
|
PHL_INFO("rtw_phl_cmd_scan_request:: HW_BAND_1!\n");
|
|
#ifdef CONFIG_DBCC_SUPPORT
|
if(rtw_phl_mr_is_db(phl_info))
|
param->sctrl_num =_cmd_scan_dbcc_policy(phl_info, param);
|
else
|
#endif
|
param->sctrl_num = 1;
|
|
PHL_INFO("[cmd_scan]:: param->sctrl_num = %d\n", param->sctrl_num);
|
|
_os_mem_set(drv, param->sctrl, 0, MAX_BAND_NUM * sizeof(struct cmd_scan_ctrl));
|
|
pstatus = _cmd_scan_req_init(phl_info, param);
|
if(pstatus != RTW_PHL_STATUS_SUCCESS) {
|
goto error;
|
}
|
|
/* cmd_dispatcher would copy whole phl_cmd_token_req */
|
pstatus = _phl_cmd_scan_req_submit(phl_info, param);
|
if((pstatus != RTW_PHL_STATUS_SUCCESS) &&
|
(pstatus != RTW_PHL_STATUS_PENDING)) {
|
goto error;
|
}
|
|
return RTW_PHL_STATUS_SUCCESS;
|
|
error:
|
if(param->sctrl) {
|
_cmd_scan_req_deinit(phl_info, param);
|
param->sctrl_num = 0;
|
}
|
|
return pstatus;
|
}
|
|
enum rtw_phl_status rtw_phl_cmd_scan_cancel(void *phl,
|
struct rtw_phl_scan_param *param)
|
{
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
struct cmd_scan_ctrl *sctrl = NULL;
|
struct rtw_wifi_role_link_t *rlink = NULL;
|
u8 sctrl_idx = 0;
|
|
for(sctrl_idx = 0; sctrl_idx < param->sctrl_num; sctrl_idx++) {
|
sctrl = ¶m->sctrl[sctrl_idx];
|
rlink = sctrl_to_rlink(sctrl, RTW_RLINK_PRIMARY);
|
pstatus = phl_disp_eng_cancel_token_req(phl_info, rlink->hw_band, &sctrl->token);
|
sctrl->token = 0;
|
}
|
//param->token = 0;
|
return pstatus;
|
}
|
|
/** Scan return format: (1Byte or 2Byte)
|
* 0 1 2
|
* +-------------+-------------+
|
* | MDL | sctrl_num |
|
* +-------------+-------------+
|
**/
|
int rtw_phl_cmd_scan_inprogress(void *phl, u8 band_idx)
|
{
|
struct phl_module_op_info op_info = {0};
|
u8 mdl = 0;
|
|
op_info.op_code = FG_REQ_OP_GET_MDL_ID;
|
op_info.outbuf = (u8*)&mdl;
|
op_info.outlen = 4;
|
|
if(phl_disp_eng_query_cur_cmd_info(phl, band_idx,
|
&op_info)== RTW_PHL_STATUS_SUCCESS ) {
|
|
if(mdl == PHL_FG_MDL_SCAN)
|
return true;
|
}
|
|
return false;
|
}
|
|
static void _cmd_scan_send_msg_done(void *priv, struct phl_msg *msg)
|
{
|
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
|
|
if (msg->inbuf && msg->inlen) {
|
_os_kmem_free(phl_to_drvpriv(phl_info), msg->inbuf, msg->inlen);
|
}
|
}
|
|
void rtw_phl_cmd_scan_send_msg(void *phl, u16 evt_id, u8 band_idx, u8 *buf,
|
u32 len)
|
{
|
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
|
struct phl_msg msg = {0};
|
struct phl_msg_attribute attr = {0};
|
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
|
u8 *ptr = NULL;
|
|
ptr = _os_kmem_alloc(phl_to_drvpriv(phl_info), len);
|
if (ptr == NULL) {
|
PHL_ERR("%s(): allocate ptr fail.\n", __func__);
|
return;
|
}
|
|
_os_mem_cpy(phl_to_drvpriv(phl_info), ptr, buf, len);
|
|
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_FG_MDL_SCAN);
|
attr.completion.completion = _cmd_scan_send_msg_done;
|
attr.completion.priv = (void *)phl_info;
|
msg.band_idx = band_idx;
|
msg.inbuf = (u8 *)ptr;
|
msg.inlen = len;
|
|
SET_MSG_EVT_ID_FIELD(msg.msg_id, evt_id);
|
|
pstatus = phl_disp_eng_send_msg(phl, &msg, &attr, NULL);
|
if (RTW_PHL_STATUS_SUCCESS != pstatus) {
|
_cmd_scan_send_msg_done(phl, &msg);
|
PHL_ERR("%s sending msg failed \n", __func__);
|
}
|
}
|
|
#endif /* CONFIG_PHL_CMD_SCAN */
|