/****************************************************************************** * * 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); 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) { #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif 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 (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; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; hdr = (struct fwcmd_p2p_act *) h2cb_put(h2cb, sizeof(struct fwcmd_p2p_act)); if (!hdr) { ret = MACNOBUF; goto fail; } 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)); ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_PS, FWCMD_H2C_FUNC_P2P_ACT, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); h2c_end_flow(adapter); if (info->act == P2P_ACT_INIT) adapter->p2p_info[p2pid].macid = info->macid; if (info->act == P2P_ACT_INIT || info->act == P2P_ACT_TERM) adapter->p2p_info[p2pid].wait_dack = 1; return MACSUCCESS; fail: h2cb_free(adapter, h2cb); return ret; } u32 mac_p2p_macid_ctrl_h2c(struct mac_ax_adapter *adapter, struct mac_ax_p2p_macid_info *info) { #if MAC_AX_PHL_H2C struct rtw_h2c_pkt *h2cb; #else struct h2c_buf *h2cb; #endif 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; u8 *curr_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; } 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; h2cb = h2cb_alloc(adapter, H2CB_CLASS_CMD); if (!h2cb) return MACNPTR; pldsize = sizeof(struct fwcmd_p2p_macid_ctrl) + bmap_ext_size; hdr = (struct fwcmd_p2p_macid_ctrl *)h2cb_put(h2cb, pldsize); if (!hdr) { ret = MACNOBUF; goto fail; } 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((bmap_idx_srt << MACID_BMAP_BIT_SH), 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; } ret = h2c_pkt_set_hdr(adapter, h2cb, FWCMD_TYPE_H2C, FWCMD_H2C_CAT_MAC, FWCMD_H2C_CL_PS, FWCMD_H2C_FUNC_P2P_MACID_CTRL, 0, 1); if (ret) goto fail; ret = h2c_pkt_build_txd(adapter, h2cb); if (ret) goto fail; #if MAC_AX_PHL_H2C ret = PLTFM_TX(h2cb); #else ret = PLTFM_TX(h2cb->data, h2cb->len); #endif if (ret) goto fail; h2cb_free(adapter, h2cb); h2c_end_flow(adapter); adapter->p2p_info[p2pid].wait_dack = 1; return MACSUCCESS; fail: h2cb_free(adapter, h2cb); 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; } }