android13/external/wifi_driver/rtl8852be/phl/phl_sound_cmd.c

581 lines
15 KiB
C

/******************************************************************************
*
* 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.
*
*****************************************************************************/
#include "phl_headers.h"
#ifdef CONFIG_CMD_DISP
/* START of sounding / beamform cmd_disp module */
void
_phl_snd_cmd_set_eng_busy(struct phl_info_t *phl_info, enum snd_cmd_disp_ctrl ctrl)
{
struct phl_sound_obj *snd = (struct phl_sound_obj *)phl_info->snd_obj;
if (snd != NULL) {
snd->msg_busy |= BIT(ctrl);
}
}
void
_phl_snd_cmd_set_eng_idle(struct phl_info_t *phl_info, enum snd_cmd_disp_ctrl ctrl)
{
struct phl_sound_obj *snd = (struct phl_sound_obj *)phl_info->snd_obj;
if (snd != NULL) {
snd->msg_busy &= ~(BIT(ctrl));
}
}
enum rtw_phl_status
_phl_snd_cmd_get_eng_status(struct phl_info_t *phl_info, enum snd_cmd_disp_ctrl ctrl)
{
struct phl_sound_obj *snd = (struct phl_sound_obj *)phl_info->snd_obj;
enum rtw_phl_status pstatus = RTW_PHL_STATUS_FAILURE;
if (snd != NULL) {
if (0 != (snd->msg_busy & BIT(ctrl))) {
pstatus = RTW_PHL_STATUS_PENDING;
} else {
pstatus = RTW_PHL_STATUS_SUCCESS;
}
} else {
pstatus = RTW_PHL_STATUS_RESOURCE;
}
return pstatus;
}
enum rtw_phl_status
_phl_snd_aquire_eng(struct phl_info_t *phl_info, enum snd_cmd_disp_ctrl ctrl)
{
struct phl_sound_obj *snd = (struct phl_sound_obj *)phl_info->snd_obj;
void *d = phl_to_drvpriv(phl_info);
enum rtw_phl_status pstatus = RTW_PHL_STATUS_SUCCESS;
if (snd == NULL)
return RTW_PHL_STATUS_FAILURE;
/* acuired cmd_disp_eng control */
_os_spinlock(d, &snd->cmd_lock, _bh, NULL);
pstatus = _phl_snd_cmd_get_eng_status(phl_info, ctrl);
if (pstatus != RTW_PHL_STATUS_SUCCESS) {
_os_spinunlock(d, &snd->cmd_lock, _bh, NULL);
return pstatus;
}
_phl_snd_cmd_set_eng_busy(phl_info, SND_CMD_DISP_CTRL_BFEE);
_os_spinunlock(d, &snd->cmd_lock, _bh, NULL);
return pstatus;
}
void
_phl_snd_free_eng(struct phl_info_t *phl_info, enum snd_cmd_disp_ctrl ctrl)
{
struct phl_sound_obj *snd = (struct phl_sound_obj *)phl_info->snd_obj;
void *d = phl_to_drvpriv(phl_info);
if (snd != NULL) {
_os_spinlock(d, &snd->cmd_lock, _bh, NULL);
_phl_snd_cmd_set_eng_idle(phl_info, ctrl);
_os_spinunlock(d, &snd->cmd_lock, _bh, NULL);
}
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_init(void *phl, void *dispr, void **priv)
{
enum phl_mdl_ret_code ret = MDL_RET_SUCCESS;
#ifdef CONFIG_SND_CMD
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
void *d = phl_to_drvpriv(phl_info);
struct phl_sound_obj *snd_obj = NULL;
PHL_INFO("--> %s\n", __func__);
if (NULL == phl_info->snd_obj) {
phl_info->snd_obj = _os_kmem_alloc(d, sizeof(struct phl_sound_obj));
}
snd_obj = phl_info->snd_obj;
if (snd_obj == NULL) {
ret = MDL_RET_FAIL;
} else {
/* Init the snd static resources here */
snd_obj->phl_info = (struct phl_info_t *)phl;
_os_spinlock_init(d, &snd_obj->snd_lock);
_os_spinlock_init(d, &snd_obj->cmd_lock);
}
#endif
*priv = (void *)phl;
return ret;
}
static void _phl_snd_cmd_module_deinit(void *dispr, void *priv)
{
#ifdef CONFIG_SND_CMD
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
struct phl_sound_obj *snd_obj = (struct phl_sound_obj *)phl_info->snd_obj;
void *d = phl_to_drvpriv(phl_info);
PHL_INFO("--> %s\n", __func__);
if (NULL != snd_obj) {
_os_spinlock_free(d, &snd_obj->snd_lock);
_os_spinlock_free(d, &snd_obj->cmd_lock);
_os_kmem_free(d, snd_obj, sizeof(struct phl_sound_obj));
}
phl_info->snd_obj = NULL;
#endif
return;
}
static enum phl_mdl_ret_code _phl_snd_cmd_module_start(void *dispr, void *priv)
{
return MDL_RET_SUCCESS;
}
static enum phl_mdl_ret_code _phl_snd_cmd_module_stop(void *dispr, void *priv)
{
return MDL_RET_SUCCESS;
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_set_info(void *dispr, void *priv,
struct phl_module_op_info *info)
{
enum phl_mdl_ret_code mstatus = MDL_RET_IGNORE;
struct phl_info_t *phl = (struct phl_info_t *)priv;
PHL_INFO("[SND_CMD], %s(): opcode %d.\n", __func__, info->op_code);
switch (info->op_code) {
case SND_CMD_OP_SET_AID:
{
struct snd_cmd_set_aid *cmdbuf = (struct snd_cmd_set_aid *)info->inbuf;
if (NULL == cmdbuf) {
mstatus = MDL_RET_FAIL;
break;
}
if (NULL == cmdbuf->sta_info) {
mstatus = MDL_RET_FAIL;
cmdbuf->cmd_sts = MDL_RET_FAIL;
break;
}
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_beamform_set_aid(
phl->hal, cmdbuf->sta_info, cmdbuf->aid)) {
mstatus = MDL_RET_FAIL;
cmdbuf->cmd_sts = MDL_RET_FAIL;
break;
}
#ifdef RTW_WKARD_BFEE_SET_AID
cmdbuf->sta_info->wrole->last_set_aid = cmdbuf->aid;
#endif
cmdbuf->cmd_sts = MDL_RET_SUCCESS;
mstatus = MDL_RET_SUCCESS;
}
break;
case SND_CMD_OP_NONE:
case SND_CMD_OP_MAX:
default:
break;
}
return mstatus;
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_query_info(void *dispr, void *priv,
struct phl_module_op_info *info)
{
return MDL_RET_IGNORE;
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_msg_msg_hdlr_pre(struct phl_info_t *phl,
struct phl_msg *msg)
{
enum phl_mdl_ret_code mstatus = MDL_RET_IGNORE;
switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
case MSG_EVT_SET_VHT_GID:
/* do nothing in pre phase */
break;
case MSG_EVT_SET_BFEE_AID:
/* do nothing in pre phase */
break;
default:
break;
}
return mstatus;
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_msg_msg_hdlr_post(struct phl_info_t *phl,
struct phl_msg *msg)
{
enum phl_mdl_ret_code mstatus = MDL_RET_IGNORE;
switch (MSG_EVT_ID_FIELD(msg->msg_id)) {
case MSG_EVT_SET_VHT_GID:
{
struct rtw_phl_gid_pos_tbl *gid_tbl = (struct rtw_phl_gid_pos_tbl *)msg->inbuf;
if (msg->inlen != sizeof(struct rtw_phl_gid_pos_tbl)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s() VHT-BFEE : Error, size mis-match \n", __func__);
mstatus = MDL_RET_FAIL;
break;
}
rtw_hal_beamform_set_vht_gid(phl->hal, msg->band_idx, gid_tbl);
mstatus = MDL_RET_SUCCESS;
}
break;
case MSG_EVT_SET_BFEE_AID:
{
struct snd_cmd_set_aid *cmdbuf = (struct snd_cmd_set_aid *)msg->inbuf;
if (NULL == cmdbuf) {
mstatus = MDL_RET_FAIL;
break;
}
if (NULL == cmdbuf->sta_info) {
mstatus = MDL_RET_FAIL;
cmdbuf->cmd_sts = MDL_RET_FAIL;
break;
}
if (RTW_HAL_STATUS_SUCCESS != rtw_hal_beamform_set_aid(
phl->hal, cmdbuf->sta_info, cmdbuf->aid)) {
mstatus = MDL_RET_FAIL;
cmdbuf->cmd_sts = MDL_RET_FAIL;
break;
}
cmdbuf->cmd_sts = MDL_RET_SUCCESS;
mstatus = MDL_RET_SUCCESS;
}
break;
default:
break;
}
return mstatus;
}
static enum phl_mdl_ret_code
_phl_snd_cmd_module_msg_hdlr(void *dispr, void *priv,
struct phl_msg *msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
enum phl_mdl_ret_code mstatus = MDL_RET_IGNORE;
PHL_TRACE(COMP_PHL_SOUND, _PHL_INFO_,
"===> %s() event id : 0x%x \n", __func__, MSG_EVT_ID_FIELD(msg->msg_id));
if (IS_MSG_FAIL(msg->msg_id)) {
PHL_TRACE(COMP_PHL_DBG, _PHL_WARNING_,
"%s: cmd dispatcher notify cmd failure: 0x%x.\n",
__FUNCTION__, msg->msg_id);
mstatus = MDL_RET_FAIL;
return mstatus;
}
if (IS_MSG_IN_PRE_PHASE(msg->msg_id)) {
mstatus = _phl_snd_cmd_module_msg_msg_hdlr_pre(phl_info, msg);
} else {
mstatus = _phl_snd_cmd_module_msg_msg_hdlr_post(phl_info, msg);
}
return mstatus;
}
enum rtw_phl_status phl_snd_cmd_register_module(struct phl_info_t *phl_info)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
struct phl_bk_module_ops bk_ops;
struct phl_cmd_dispatch_engine *disp_eng = &(phl_info->disp_eng);
u8 i = 0;
bk_ops.init = _phl_snd_cmd_module_init;
bk_ops.deinit = _phl_snd_cmd_module_deinit;
bk_ops.start = _phl_snd_cmd_module_start;
bk_ops.stop = _phl_snd_cmd_module_stop;
bk_ops.msg_hdlr = _phl_snd_cmd_module_msg_hdlr;
bk_ops.set_info = _phl_snd_cmd_module_set_info;
bk_ops.query_info = _phl_snd_cmd_module_query_info;
for (i = 0; i < disp_eng->phy_num; i++) {
phl_status = phl_disp_eng_register_module(phl_info, i,
PHL_MDL_SOUND, &bk_ops);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_ERR("%s register SOUND module in cmd disp band[%d] failed\n",
__func__, i);
phl_status = RTW_PHL_STATUS_FAILURE;
break;
}
}
return phl_status;
}
/* Start of APIs for Core/OtherModule */
/* sub-functions */
/**
* _phl_snd_cmd_post_set_vht_gid(...)
* used by rtw_phl_snd_cmd_set_vht_gid(..)
**/
void _phl_snd_cmd_post_set_vht_gid(void* priv, struct phl_msg* msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "--> %s : release memeory \n", __func__);
if (msg->inbuf && msg->inlen){
_os_kmem_free(phl_to_drvpriv(phl_info), msg->inbuf, msg->inlen);
}
/* release cmd_disp_eng control */
_phl_snd_free_eng(phl_info, SND_CMD_DISP_CTRL_BFEE);
}
/* main-functions */
/**
* rtw_phl_snd_cmd_set_vht_gid (...)
* input : struct rtw_phl_gid_pos_tbl *tbl
* the received VHT GID management frame's GID / Position informaion.
**/
enum rtw_phl_status
rtw_phl_snd_cmd_set_vht_gid(void *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_phl_gid_pos_tbl *tbl)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
void *d = phl_to_drvpriv(phl_info);
struct rtw_phl_gid_pos_tbl *gid_tbl;
/* acuired cmd_disp_eng control */
if (RTW_PHL_STATUS_SUCCESS !=
_phl_snd_aquire_eng(phl_info, SND_CMD_DISP_CTRL_BFEE)) {
return RTW_PHL_STATUS_FAILURE;
}
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_SOUND);
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SET_VHT_GID);
msg.band_idx = wrole->hw_band;
attr.completion.completion = _phl_snd_cmd_post_set_vht_gid;
attr.completion.priv = phl_info;
gid_tbl = (struct rtw_phl_gid_pos_tbl *)_os_kmem_alloc(d, sizeof(struct rtw_phl_gid_pos_tbl));
_os_mem_cpy(d, gid_tbl, tbl, sizeof(struct rtw_phl_gid_pos_tbl));
msg.inbuf = (u8 *)gid_tbl;
msg.inlen = sizeof(struct rtw_phl_gid_pos_tbl);
phl_status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Dispr send msg fail!\n",
__func__);
goto exit;
}
return phl_status;
exit:
_os_kmem_free(d, gid_tbl,
sizeof(struct rtw_phl_gid_pos_tbl));
/* release cmd_disp_eng control */
_phl_snd_free_eng(phl_info, SND_CMD_DISP_CTRL_BFEE);
return phl_status;
}
void _phl_snd_cmd_post_set_aid(void* priv, struct phl_msg* msg)
{
struct phl_info_t *phl_info = (struct phl_info_t *)priv;
#ifdef RTW_WKARD_BFEE_SET_AID
struct snd_cmd_set_aid *cmdbuf = NULL;
#endif
if (msg->inbuf && msg->inlen){
#ifdef RTW_WKARD_BFEE_SET_AID
cmdbuf = (struct snd_cmd_set_aid *)msg->inbuf;
/* backup aid */
if (MDL_RET_SUCCESS == cmdbuf->cmd_sts) {
cmdbuf->sta_info->wrole->last_set_aid = cmdbuf->aid;
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_,
"%s : set aid (%d)\n",
__func__, cmdbuf->sta_info->wrole->last_set_aid);
}
#endif
_os_kmem_free(phl_to_drvpriv(phl_info), msg->inbuf, msg->inlen);
}
/* release cmd_disp_eng control */
_phl_snd_free_eng(phl_info, SND_CMD_DISP_CTRL_BFEE);
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "%s : set aid complete\n", __func__);
}
enum rtw_phl_status
rtw_phl_snd_cmd_set_aid(void *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_phl_stainfo_t *sta,
u16 aid)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
struct phl_info_t *phl_info = (struct phl_info_t *)phl;
struct phl_msg msg = {0};
struct phl_msg_attribute attr = {0};
void *d = phl_to_drvpriv(phl_info);
struct snd_cmd_set_aid *cmdbuf = NULL;
/* acuired cmd_disp_eng control */
if (RTW_PHL_STATUS_SUCCESS !=
_phl_snd_aquire_eng(phl_info, SND_CMD_DISP_CTRL_BFEE)) {
return RTW_PHL_STATUS_FAILURE;
}
SET_MSG_MDL_ID_FIELD(msg.msg_id, PHL_MDL_SOUND);
SET_MSG_EVT_ID_FIELD(msg.msg_id, MSG_EVT_SET_BFEE_AID);
msg.band_idx = wrole->hw_band;
attr.completion.completion = _phl_snd_cmd_post_set_aid;
attr.completion.priv = phl_info;
cmdbuf = (struct snd_cmd_set_aid *)_os_kmem_alloc(d, sizeof(struct snd_cmd_set_aid));
cmdbuf->aid = aid;
cmdbuf->sta_info = sta;
msg.inbuf = (u8 *)cmdbuf;
msg.inlen = sizeof(struct snd_cmd_set_aid);
phl_status = phl_disp_eng_send_msg(phl_info, &msg, &attr, NULL);
if (phl_status != RTW_PHL_STATUS_SUCCESS) {
PHL_TRACE(COMP_PHL_DBG, _PHL_ERR_, "%s: Dispr send msg fail!\n",
__func__);
goto exit;
}
return phl_status;
exit:
_os_kmem_free(d, cmdbuf, sizeof(struct snd_cmd_set_aid));
/* release cmd_disp_eng control */
_phl_snd_free_eng(phl_info, SND_CMD_DISP_CTRL_BFEE);
return phl_status;
}
/**
* For other module, such as LPS, direct set aid.
**/
enum rtw_phl_status
phl_snd_cmd_set_aid_info(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole,
struct rtw_phl_stainfo_t *sta,
u16 aid)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_FAILURE;
struct phl_module_op_info op_info = {0};
struct snd_cmd_set_aid cmdbuf = {0};
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "--> %s\n", __func__);
cmdbuf.aid = aid;
cmdbuf.sta_info = sta;
op_info.op_code = SND_CMD_OP_SET_AID;
op_info.inbuf = (u8 *)&cmdbuf;
op_info.inlen = sizeof(struct snd_cmd_set_aid);
phl_status = phl_disp_eng_set_bk_module_info(phl, wrole->hw_band,
PHL_MDL_SOUND, &op_info);
PHL_TRACE(COMP_PHL_DBG, _PHL_INFO_, "<-- %s\n", __func__);
return phl_status;
}
#ifdef RTW_WKARD_BFEE_SET_AID
enum rtw_phl_status
_phl_cmd_snd_restore_aid(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
struct rtw_phl_stainfo_t *sta = NULL;
do {
if (MLME_NO_LINK == wrole->mstate)
break;
sta = rtw_phl_get_stainfo_self(phl, wrole);
if (NULL == sta)
break;
if (wrole->last_set_aid == sta->aid)
break;
phl_status = phl_snd_cmd_set_aid_info(phl, wrole, sta, sta->aid);
} while (0);
return phl_status;
}
#endif
enum rtw_phl_status
_phl_snd_cmd_ntfy_ps_enter(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
#ifdef RTW_WKARD_BFEE_SET_AID
phl->phl_com->is_in_lps = 1;
if (PHL_RTYPE_STATION == wrole->type) {
phl_status= _phl_cmd_snd_restore_aid(phl, wrole);
}
#endif
/* TODO: stop BFer period sounding if in progress */
return phl_status;
}
enum rtw_phl_status
_phl_snd_cmd_ntfy_ps_leave(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
#ifdef RTW_WKARD_BFEE_SET_AID
phl->phl_com->is_in_lps = 0;
#endif
/* TODO: restart BFer period sounding if sounding needed */
return phl_status;
}
enum rtw_phl_status
phl_snd_cmd_ntfy_ps(struct phl_info_t *phl,
struct rtw_wifi_role_t *wrole,
bool enter)
{
enum rtw_phl_status phl_status = RTW_PHL_STATUS_SUCCESS;
if (true == enter)
phl_status = _phl_snd_cmd_ntfy_ps_enter(phl, wrole);
else
phl_status = _phl_snd_cmd_ntfy_ps_leave(phl, wrole);
return phl_status;
}
#endif