/******************************************************************************
|
*
|
* Copyright(c) 2019 Realtek Corporation. All rights reserved.
|
*
|
* 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 "p2p.h"
|
|
static u32 p2p_info_size = sizeof(struct mac_ax_p2p_info) * P2P_MAX_NUM;
|
|
static u32 _get_valid_p2pid(struct mac_ax_adapter *adapter, u8 macid, u8 *p2pid)
|
{
|
struct mac_ax_p2p_info *info = adapter->p2p_info;
|
u8 idx;
|
|
for (idx = 0; idx < P2P_MAX_NUM; idx++) {
|
if (info[idx].run && info[idx].macid == macid) {
|
PLTFM_MSG_ERR("[ERR]macid %d has running p2pid %d\n",
|
macid, idx);
|
*p2pid = P2PID_INVALID;
|
return MACSUCCESS;
|
}
|
}
|
|
for (idx = 0; idx < P2P_MAX_NUM; idx++) {
|
if (!info[idx].run && !info[idx].wait_dack) {
|
*p2pid = idx;
|
return MACSUCCESS;
|
}
|
}
|
|
PLTFM_MSG_ERR("[ERR]no valid p2p\n");
|
*p2pid = P2PID_INVALID;
|
return MACHWNOSUP;
|
}
|
|
static u32 _get_macid_p2pid(struct mac_ax_adapter *adapter, u8 macid, u8 *p2pid)
|
{
|
struct mac_ax_p2p_info *info = adapter->p2p_info;
|
u8 idx;
|
|
for (idx = 0; idx < P2P_MAX_NUM; idx++) {
|
if (info[idx].run && info[idx].macid == macid) {
|
*p2pid = idx;
|
return MACSUCCESS;
|
}
|
}
|
|
PLTFM_MSG_ERR("[ERR]no valid p2pid for macid %d\n", macid);
|
*p2pid = P2PID_INVALID;
|
return MACFUNCINPUT;
|
}
|
|
u32 get_wait_dack_p2pid(struct mac_ax_adapter *adapter, u8 *p2pid)
|
{
|
struct mac_ax_p2p_info *info = adapter->p2p_info;
|
u8 idx;
|
u8 hit = 0;
|
|
for (idx = 0; idx < P2P_MAX_NUM; idx++) {
|
if (info[idx].wait_dack && !hit) {
|
*p2pid = idx;
|
hit = 1;
|
} else if (info[idx].wait_dack) {
|
PLTFM_MSG_ERR("[ERR]multiple wait dack p2p\n");
|
return MACPROCERR;
|
}
|
}
|
|
if (!hit)
|
*p2pid = P2PID_INVALID;
|
|
return MACSUCCESS;
|
}
|
|
u32 p2p_info_init(struct mac_ax_adapter *adapter)
|
{
|
u32 i;
|
|
adapter->p2p_info =
|
(struct mac_ax_p2p_info *)PLTFM_MALLOC(p2p_info_size);
|
if (!adapter->p2p_info) {
|
PLTFM_MSG_ERR("%s malloc p2p_info fail\n", __func__);
|
return MACNOBUF;
|
}
|
|
for (i = 0; i < P2P_MAX_NUM; i++)
|
PLTFM_MEMSET(&adapter->p2p_info[i], 0,
|
sizeof(struct mac_ax_p2p_info));
|
|
return MACSUCCESS;
|
}
|
|
u32 p2p_info_exit(struct mac_ax_adapter *adapter)
|
{
|
PLTFM_FREE(adapter->p2p_info, p2p_info_size);
|
|
return MACSUCCESS;
|
}
|
|
u32 rst_p2p_info(struct mac_ax_adapter *adapter)
|
{
|
PLTFM_MEMSET(adapter->p2p_info, 0, p2p_info_size);
|
|
return MACSUCCESS;
|
}
|
|
u32 mac_p2p_act_h2c(struct mac_ax_adapter *adapter,
|
struct mac_ax_p2p_act_info *info)
|
{
|
struct h2c_info h2c_info = {0};
|
struct fwcmd_p2p_act hdr;
|
u32 ret = MACSUCCESS;
|
u8 p2pid;
|
|
if (info->noaid >= NOA_MAX_NUM) {
|
PLTFM_MSG_ERR("[ERR]invalid noaid %d\n", info->noaid);
|
return MACFUNCINPUT;
|
}
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_WARN("%s fw not ready\n", __func__);
|
return MACFWNONRDY;
|
}
|
|
if (info->act == P2P_ACT_INIT) {
|
ret = _get_valid_p2pid(adapter, info->macid, &p2pid);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]get valid p2pid %d\n", ret);
|
return MACHWNOSUP;
|
}
|
if (p2pid == P2PID_INVALID) {
|
PLTFM_MSG_ERR("[ERR]get invalid p2pid\n");
|
return MACNOITEM;
|
}
|
} else {
|
ret = _get_macid_p2pid(adapter, info->macid, &p2pid);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]get macid %d p2pid %d\n",
|
info->macid, ret);
|
return MACFUNCINPUT;
|
}
|
if (p2pid == P2PID_INVALID) {
|
PLTFM_MSG_ERR("[ERR]get macid p2pid shall ret err\n");
|
return MACCMP;
|
}
|
}
|
|
if (adapter->sm.p2p_stat == MAC_AX_P2P_ACT_BUSY) {
|
PLTFM_MSG_ERR("[ERR] p2p act h2c stat busy\n");
|
return MACPROCERR;
|
}
|
adapter->sm.p2p_stat = MAC_AX_P2P_ACT_BUSY;
|
|
hdr.dword0 =
|
cpu_to_le32(SET_WORD(info->macid, FWCMD_H2C_P2P_ACT_MACID) |
|
SET_WORD(p2pid, FWCMD_H2C_P2P_ACT_P2PID) |
|
SET_WORD(info->noaid, FWCMD_H2C_P2P_ACT_NOAID) |
|
SET_WORD(info->act, FWCMD_H2C_P2P_ACT_ACT) |
|
(info->type ? FWCMD_H2C_P2P_ACT_TYPE : 0) |
|
(info->all_slep ? FWCMD_H2C_P2P_ACT_ALL_SLEP : 0));
|
|
hdr.dword1 =
|
cpu_to_le32(SET_WORD(info->srt, FWCMD_H2C_P2P_ACT_SRT));
|
|
hdr.dword2 =
|
cpu_to_le32(SET_WORD(info->itvl, FWCMD_H2C_P2P_ACT_ITVL));
|
|
hdr.dword3 =
|
cpu_to_le32(SET_WORD(info->dur, FWCMD_H2C_P2P_ACT_DUR));
|
|
hdr.dword4 =
|
cpu_to_le32(SET_WORD(info->cnt, FWCMD_H2C_P2P_ACT_CNT) |
|
SET_WORD(info->ctw, FWCMD_H2C_P2P_ACT_CTW));
|
|
h2c_info.agg_en = 0;
|
h2c_info.content_len = sizeof(struct fwcmd_p2p_act);
|
h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
|
h2c_info.h2c_class = FWCMD_H2C_CL_PS;
|
h2c_info.h2c_func = FWCMD_H2C_FUNC_P2P_ACT;
|
h2c_info.rec_ack = 0;
|
h2c_info.done_ack = 1;
|
|
ret = mac_h2c_common(adapter, &h2c_info, (u32 *)&hdr);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("%s send h2c fail %d\n", __func__, ret);
|
return ret;
|
}
|
|
if (info->act == P2P_ACT_INIT) {
|
adapter->p2p_info[p2pid].macid = info->macid;
|
adapter->p2p_info[p2pid].wait_init = 1;
|
}
|
if (info->act == P2P_ACT_TERM)
|
adapter->p2p_info[p2pid].wait_term = 1;
|
|
adapter->p2p_info[p2pid].wait_dack = 1;
|
|
return ret;
|
}
|
|
u32 mac_p2p_macid_ctrl_h2c(struct mac_ax_adapter *adapter,
|
struct mac_ax_p2p_macid_info *info)
|
{
|
struct h2c_info h2c_info = {0};
|
struct fwcmd_p2p_macid_ctrl *hdr;
|
u32 ret = MACSUCCESS;
|
u32 idx, bmap_ext_size, pldsize, bmap_srt_sh, bmap_last;
|
u32 bmap_idx_srt, bmap_idx_end, bmap_idx_diff;
|
u16 macid_start;
|
u8 *curr_buf, *content_buf;
|
u8 p2pid;
|
|
if (info->ctrl_type >= P2P_MACID_CTRL_MAX) {
|
PLTFM_MSG_ERR("[ERR]p2p macid ctrl invalid ctrl type %d\n",
|
info->ctrl_type);
|
return MACFUNCINPUT;
|
}
|
|
if (adapter->sm.fwdl != MAC_AX_FWDL_INIT_RDY) {
|
PLTFM_MSG_WARN("%s fw not ready\n", __func__);
|
return MACFWNONRDY;
|
}
|
|
ret = _get_macid_p2pid(adapter, info->main_macid, &p2pid);
|
if (ret != MACSUCCESS) {
|
PLTFM_MSG_ERR("[ERR]get macid %d p2pid %d\n",
|
info->main_macid, ret);
|
return MACFUNCINPUT;
|
}
|
if (p2pid == P2PID_INVALID) {
|
PLTFM_MSG_ERR("[ERR]get macid p2pid shall ret err\n");
|
return MACNOITEM;
|
}
|
|
bmap_idx_srt = 0;
|
for (idx = 0; idx < info->bmap_len; idx++) {
|
if (*(info->bitmap + idx))
|
break;
|
if (idx && !(idx & MACID_BMAP_BYTE_MSK))
|
bmap_idx_srt++;
|
}
|
|
bmap_idx_end = info->bmap_len >> MACID_BMAP_BYTE_SH;
|
bmap_last = info->bmap_len ? (info->bmap_len - 1) : 0;
|
for (idx = bmap_last; idx > 0; idx--) {
|
if (*(info->bitmap + idx))
|
break;
|
if (!(idx & MACID_BMAP_BYTE_MSK))
|
bmap_idx_end--;
|
}
|
|
if (bmap_idx_srt > bmap_idx_end) {
|
PLTFM_MSG_ERR("[ERR] p2p macid ctrl bitmap comp err\n");
|
return MACCMP;
|
}
|
|
bmap_idx_diff = bmap_idx_end - bmap_idx_srt;
|
bmap_ext_size = bmap_idx_diff << MACID_BMAP_BYTE_SH;
|
|
if (adapter->sm.p2p_stat == MAC_AX_P2P_ACT_BUSY) {
|
PLTFM_MSG_ERR("[ERR] p2p macid ctrl h2c stat busy\n");
|
return MACPROCERR;
|
}
|
adapter->sm.p2p_stat = MAC_AX_P2P_ACT_BUSY;
|
|
pldsize = sizeof(struct fwcmd_p2p_macid_ctrl) + bmap_ext_size;
|
content_buf = (u8 *)PLTFM_MALLOC(pldsize);
|
if (!content_buf) {
|
PLTFM_MSG_ERR("[ERR] p2p macid ctrl h2c no buffer\n");
|
return MACNOBUF;
|
}
|
hdr = (struct fwcmd_p2p_macid_ctrl *)content_buf;
|
|
macid_start = bmap_idx_srt << MACID_BMAP_BIT_SH;
|
|
hdr->dword0 =
|
cpu_to_le32(SET_WORD(p2pid, FWCMD_H2C_P2P_MACID_CTRL_P2PID) |
|
SET_WORD(info->ctrl_type, FWCMD_H2C_P2P_MACID_CTRL_CTRL_TYPE) |
|
SET_WORD(macid_start, FWCMD_H2C_P2P_MACID_CTRL_MACID_SRT) |
|
SET_WORD((bmap_idx_diff + 1), FWCMD_H2C_P2P_MACID_CTRL_BMAP_LEN));
|
|
for (idx = 0; idx < ((bmap_idx_diff + 1) << MACID_BMAP_BYTE_SH); idx++) {
|
bmap_srt_sh = (bmap_idx_srt << MACID_BMAP_BYTE_SH) + idx;
|
curr_buf = (u8 *)(&hdr->dword1) + idx;
|
if (bmap_srt_sh < info->bmap_len)
|
*curr_buf = *(info->bitmap + bmap_srt_sh);
|
else
|
*curr_buf = 0;
|
}
|
|
h2c_info.agg_en = 0;
|
h2c_info.content_len = (u16)pldsize;
|
h2c_info.h2c_cat = FWCMD_H2C_CAT_MAC;
|
h2c_info.h2c_class = FWCMD_H2C_CL_PS;
|
h2c_info.h2c_func = FWCMD_H2C_FUNC_P2P_MACID_CTRL;
|
h2c_info.rec_ack = 0;
|
h2c_info.done_ack = 1;
|
|
ret = mac_h2c_common(adapter, &h2c_info, (u32 *)content_buf);
|
if (ret != MACSUCCESS)
|
PLTFM_MSG_ERR("%s send h2c fail %d\n", __func__, ret);
|
else
|
adapter->p2p_info[p2pid].wait_dack = 1;
|
|
PLTFM_FREE(content_buf, pldsize);
|
return ret;
|
}
|
|
u32 mac_get_p2p_stat(struct mac_ax_adapter *adapter)
|
{
|
switch (adapter->sm.p2p_stat) {
|
case MAC_AX_P2P_ACT_IDLE:
|
return MACSUCCESS;
|
case MAC_AX_P2P_ACT_BUSY:
|
return MACPROCBUSY;
|
case MAC_AX_P2P_ACT_FAIL:
|
default:
|
return MACP2PSTFAIL;
|
}
|
}
|