/****************************************************************************** * * Copyright(c) 2016 - 2018 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 "halmac_sdio_8822b.h" #include "halmac_pwr_seq_8822b.h" #include "../halmac_init_88xx.h" #include "../halmac_common_88xx.h" #include "../halmac_sdio_88xx.h" #if HALMAC_8822B_SUPPORT #define WLAN_ACQ_NUM_MAX 8 static enum halmac_ret_status chk_oqt_8822b(struct halmac_adapter *adapter, u32 tx_agg_num, u8 *buf, u8 macid_cnt); static enum halmac_ret_status update_oqt_free_space_8822b(struct halmac_adapter *adapter); static enum halmac_ret_status update_sdio_free_page_8822b(struct halmac_adapter *adapter); static enum halmac_ret_status chk_qsel_8822b(struct halmac_adapter *adapter, u8 qsel_first, u8 *pkt, u8 *macid_cnt); static enum halmac_ret_status chk_dma_mapping_8822b(struct halmac_adapter *adapter, u16 **cur_fs, u8 qsel_first); static enum halmac_ret_status chk_rqd_page_num_8822b(struct halmac_adapter *adapter, u8 *buf, u32 *rqd_pg_num, u16 **cur_fs, u8 *macid_cnt, u32 tx_agg_num); /** * mac_pwr_switch_sdio_8822b() - switch mac power * @adapter : the adapter of halmac * @pwr : power state * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status mac_pwr_switch_sdio_8822b(struct halmac_adapter *adapter, enum halmac_mac_power pwr) { u8 value8; u8 rpwm; u32 imr_backup; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); PLTFM_MSG_TRACE("[TRACE]8822B pwr seq ver = %s\n", HALMAC_8822B_PWR_SEQ_VER); adapter->rpwm = HALMAC_REG_R8(REG_SDIO_HRPWM1); /* Check FW still exist or not */ if (HALMAC_REG_R16(REG_MCUFW_CTRL) == 0xC078) { /* Leave 32K */ rpwm = (u8)((adapter->rpwm ^ BIT(7)) & 0x80); HALMAC_REG_W8(REG_SDIO_HRPWM1, rpwm); } value8 = HALMAC_REG_R8(REG_CR); if (value8 == 0xEA) adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_OFF; else adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_ON; /*Check if power switch is needed*/ if (pwr == HALMAC_MAC_POWER_ON && adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_ON) { PLTFM_MSG_WARN("[WARN]power state unchange!!\n"); return HALMAC_RET_PWR_UNCHANGE; } imr_backup = HALMAC_REG_R32(REG_SDIO_HIMR); HALMAC_REG_W32(REG_SDIO_HIMR, 0); if (pwr == HALMAC_MAC_POWER_OFF) { adapter->pwr_off_flow_flag = 1; if (pwr_seq_parser_88xx(adapter, card_dis_flow_8822b) != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]Handle power off cmd error\n"); HALMAC_REG_W32(REG_SDIO_HIMR, imr_backup); return HALMAC_RET_POWER_OFF_FAIL; } adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_OFF; adapter->halmac_state.dlfw_state = HALMAC_DLFW_NONE; adapter->pwr_off_flow_flag = 0; init_adapter_dynamic_param_88xx(adapter); } else { if (pwr_seq_parser_88xx(adapter, card_en_flow_8822b) != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]Handle power on cmd error\n"); HALMAC_REG_W32(REG_SDIO_HIMR, imr_backup); return HALMAC_RET_POWER_ON_FAIL; } adapter->halmac_state.mac_pwr = HALMAC_MAC_POWER_ON; } HALMAC_REG_W32(REG_SDIO_HIMR, imr_backup); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * halmac_tx_allowed_sdio_88xx() - check tx status * @adapter : the adapter of halmac * @buf : tx packet, include txdesc * @size : tx packet size, include txdesc * Author : Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status tx_allowed_sdio_8822b(struct halmac_adapter *adapter, u8 *buf, u32 size) { u16 *cur_fs = NULL; u32 cnt; u32 tx_agg_num; u32 rqd_pg_num = 0; u8 macid_cnt = 0; struct halmac_sdio_free_space *fs_info = &adapter->sdio_fs; enum halmac_ret_status status = HALMAC_RET_SUCCESS; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); if (!fs_info->macid_map) { PLTFM_MSG_ERR("[ERR]halmac allocate Macid_map Fail!!\n"); return HALMAC_RET_MALLOC_FAIL; } PLTFM_MEMSET(fs_info->macid_map, 0x00, fs_info->macid_map_size); tx_agg_num = GET_TX_DESC_DMA_TXAGG_NUM(buf); tx_agg_num = (tx_agg_num == 0) ? 1 : tx_agg_num; status = chk_rqd_page_num_8822b(adapter, buf, &rqd_pg_num, &cur_fs, &macid_cnt, tx_agg_num); if (status != HALMAC_RET_SUCCESS) return status; cnt = 10; do { if ((u32)(*cur_fs + fs_info->pubq_pg_num) > rqd_pg_num) { status = chk_oqt_8822b(adapter, tx_agg_num, buf, macid_cnt); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_WARN("[WARN]oqt buffer full!!\n"); return status; } if (*cur_fs >= rqd_pg_num) { *cur_fs -= (u16)rqd_pg_num; } else { fs_info->pubq_pg_num -= (u16)(rqd_pg_num - *cur_fs); *cur_fs = 0; } break; } update_sdio_free_page_8822b(adapter); cnt--; if (cnt == 0) return HALMAC_RET_FREE_SPACE_NOT_ENOUGH; } while (1); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * halmac_reg_read_8_sdio_88xx() - read 1byte register * @adapter : the adapter of halmac * @offset : register offset * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ u8 reg_r8_sdio_8822b(struct halmac_adapter *adapter, u32 offset) { u8 value8; enum halmac_ret_status status = HALMAC_RET_SUCCESS; if ((offset & 0xFFFF0000) == 0) { value8 = (u8)r_indir_sdio_88xx(adapter, offset, HALMAC_IO_BYTE); } else { status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } value8 = PLTFM_SDIO_CMD52_R(offset); } return value8; } /** * halmac_reg_write_8_sdio_88xx() - write 1byte register * @adapter : the adapter of halmac * @offset : register offset * @value : register value * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status reg_w8_sdio_8822b(struct halmac_adapter *adapter, u32 offset, u8 value) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if ((offset & 0xFFFF0000) == 0) offset |= WLAN_IOREG_OFFSET; status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } PLTFM_SDIO_CMD52_W(offset, value); return HALMAC_RET_SUCCESS; } /** * halmac_reg_read_16_sdio_88xx() - read 2byte register * @adapter : the adapter of halmac * @offset : register offset * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ u16 reg_r16_sdio_8822b(struct halmac_adapter *adapter, u32 offset) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u16 word; u8 byte[2]; } value16 = { 0x0000 }; if ((offset & 0xFFFF0000) == 0) return (u16)r_indir_sdio_88xx(adapter, offset, HALMAC_IO_WORD); status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF || ((offset & (2 - 1)) != 0) || adapter->sdio_cmd53_4byte == HALMAC_SDIO_CMD53_4BYTE_MODE_RW || adapter->sdio_cmd53_4byte == HALMAC_SDIO_CMD53_4BYTE_MODE_R) { value16.byte[0] = PLTFM_SDIO_CMD52_R(offset); value16.byte[1] = PLTFM_SDIO_CMD52_R(offset + 1); value16.word = rtk_le16_to_cpu(value16.word); } else { value16.word = PLTFM_SDIO_CMD53_R16(offset); } return value16.word; } /** * halmac_reg_write_16_sdio_88xx() - write 2byte register * @adapter : the adapter of halmac * @offset : register offset * @value : register value * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status reg_w16_sdio_8822b(struct halmac_adapter *adapter, u32 offset, u16 value) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF || ((offset & (2 - 1)) != 0) || adapter->sdio_cmd53_4byte == HALMAC_SDIO_CMD53_4BYTE_MODE_RW || adapter->sdio_cmd53_4byte == HALMAC_SDIO_CMD53_4BYTE_MODE_W) { if ((offset & 0xFFFF0000) == 0 && ((offset & (2 - 1)) == 0)) { status = w_indir_sdio_88xx(adapter, offset, value, HALMAC_IO_WORD); } else { if ((offset & 0xFFFF0000) == 0) offset |= WLAN_IOREG_OFFSET; status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } PLTFM_SDIO_CMD52_W(offset, (u8)(value & 0xFF)); PLTFM_SDIO_CMD52_W(offset + 1, (u8)((value & 0xFF00) >> 8)); } } else { if ((offset & 0xFFFF0000) == 0) offset |= WLAN_IOREG_OFFSET; status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } PLTFM_SDIO_CMD53_W16(offset, value); } return status; } /** * halmac_reg_read_32_sdio_88xx() - read 4byte register * @adapter : the adapter of halmac * @offset : register offset * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ u32 reg_r32_sdio_8822b(struct halmac_adapter *adapter, u32 offset) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; union { u32 dword; u8 byte[4]; } value32 = { 0x00000000 }; if ((offset & 0xFFFF0000) == 0) return r_indir_sdio_88xx(adapter, offset, HALMAC_IO_DWORD); status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF || (offset & (4 - 1)) != 0) { value32.byte[0] = PLTFM_SDIO_CMD52_R(offset); value32.byte[1] = PLTFM_SDIO_CMD52_R(offset + 1); value32.byte[2] = PLTFM_SDIO_CMD52_R(offset + 2); value32.byte[3] = PLTFM_SDIO_CMD52_R(offset + 3); value32.dword = rtk_le32_to_cpu(value32.dword); } else { value32.dword = PLTFM_SDIO_CMD53_R32(offset); } return value32.dword; } /** * halmac_reg_write_32_sdio_88xx() - write 4byte register * @adapter : the adapter of halmac * @offset : register offset * @value : register value * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status reg_w32_sdio_8822b(struct halmac_adapter *adapter, u32 offset, u32 value) { enum halmac_ret_status status = HALMAC_RET_SUCCESS; if (adapter->halmac_state.mac_pwr == HALMAC_MAC_POWER_OFF || (offset & (4 - 1)) != 0) { if ((offset & 0xFFFF0000) == 0 && ((offset & (4 - 1)) == 0)) { status = w_indir_sdio_88xx(adapter, offset, value, HALMAC_IO_DWORD); } else { if ((offset & 0xFFFF0000) == 0) offset |= WLAN_IOREG_OFFSET; status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } PLTFM_SDIO_CMD52_W(offset, (u8)(value & 0xFF)); PLTFM_SDIO_CMD52_W(offset + 1, (u8)((value >> 8) & 0xFF)); PLTFM_SDIO_CMD52_W(offset + 2, (u8)((value >> 16) & 0xFF)); PLTFM_SDIO_CMD52_W(offset + 3, (u8)((value >> 24) & 0xFF)); } } else { if ((offset & 0xFFFF0000) == 0) offset |= WLAN_IOREG_OFFSET; status = cnv_to_sdio_bus_offset_88xx(adapter, &offset); if (status != HALMAC_RET_SUCCESS) { PLTFM_MSG_ERR("[ERR]convert offset\n"); return status; } PLTFM_SDIO_CMD53_W32(offset, value); } return status; } static enum halmac_ret_status chk_oqt_8822b(struct halmac_adapter *adapter, u32 tx_agg_num, u8 *buf, u8 macid_cnt) { u32 cnt = 10; struct halmac_sdio_free_space *fs_info = &adapter->sdio_fs; /*S0, S1 are not allowed to use, 0x4E4[0] should be 0. Soar 20160323*/ /*no need to check non_ac_oqt_number*/ /*HI and MGQ blocked will cause protocal issue before H_OQT being full*/ switch ((enum halmac_qsel)GET_TX_DESC_QSEL(buf)) { case HALMAC_QSEL_VO: case HALMAC_QSEL_VO_V2: case HALMAC_QSEL_VI: case HALMAC_QSEL_VI_V2: case HALMAC_QSEL_BE: case HALMAC_QSEL_BE_V2: case HALMAC_QSEL_BK: case HALMAC_QSEL_BK_V2: if (macid_cnt > WLAN_ACQ_NUM_MAX && tx_agg_num > OQT_ENTRY_AC_8822B) { PLTFM_MSG_WARN("[WARN]txagg num %d > oqt entry\n", tx_agg_num); PLTFM_MSG_WARN("[WARN]macid cnt %d > acq max\n", macid_cnt); } cnt = 10; do { if (fs_info->ac_empty >= macid_cnt) { fs_info->ac_empty -= macid_cnt; break; } if (fs_info->ac_oqt_num >= tx_agg_num) { fs_info->ac_empty = 0; fs_info->ac_oqt_num -= (u8)tx_agg_num; break; } update_oqt_free_space_8822b(adapter); cnt--; if (cnt == 0) return HALMAC_RET_OQT_NOT_ENOUGH; } while (1); break; case HALMAC_QSEL_MGNT: case HALMAC_QSEL_HIGH: if (tx_agg_num > OQT_ENTRY_NOAC_8822B) PLTFM_MSG_WARN("[WARN]tx_agg_num %d > oqt entry\n", tx_agg_num, OQT_ENTRY_NOAC_8822B); cnt = 10; do { if (fs_info->non_ac_oqt_num >= tx_agg_num) { fs_info->non_ac_oqt_num -= (u8)tx_agg_num; break; } update_oqt_free_space_8822b(adapter); cnt--; if (cnt == 0) return HALMAC_RET_OQT_NOT_ENOUGH; } while (1); break; default: break; } return HALMAC_RET_SUCCESS; } static enum halmac_ret_status update_oqt_free_space_8822b(struct halmac_adapter *adapter) { struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; struct halmac_sdio_free_space *fs_info = &adapter->sdio_fs; u8 value; u32 oqt_free_page; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); oqt_free_page = HALMAC_REG_R32(REG_SDIO_OQT_FREE_TXPG_V1); fs_info->ac_oqt_num = (u8)BIT_GET_AC_OQT_FREEPG_V1(oqt_free_page); fs_info->non_ac_oqt_num = (u8)BIT_GET_NOAC_OQT_FREEPG_V1(oqt_free_page); fs_info->ac_empty = 0; if (fs_info->ac_oqt_num == OQT_ENTRY_AC_8822B) { value = HALMAC_REG_R8(REG_TXPKT_EMPTY); while (value > 0) { value = value & (value - 1); fs_info->ac_empty++; }; } else { PLTFM_MSG_TRACE("[TRACE]free_space->ac_oqt_num %d != %d\n", fs_info->ac_oqt_num, OQT_ENTRY_AC_8822B); } PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } static enum halmac_ret_status update_sdio_free_page_8822b(struct halmac_adapter *adapter) { u32 free_page = 0; u32 free_page2 = 0; u32 free_page3 = 0; struct halmac_api *api = (struct halmac_api *)adapter->halmac_api; struct halmac_sdio_free_space *fs_info = &adapter->sdio_fs; u8 data[12] = {0}; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); HALMAC_REG_SDIO_RN(REG_SDIO_FREE_TXPG, 12, data); free_page = rtk_le32_to_cpu(*(u32 *)(data + 0)); free_page2 = rtk_le32_to_cpu(*(u32 *)(data + 4)); free_page3 = rtk_le32_to_cpu(*(u32 *)(data + 8)); fs_info->hiq_pg_num = (u16)BIT_GET_HIQ_FREEPG_V1(free_page); fs_info->miq_pg_num = (u16)BIT_GET_MID_FREEPG_V1(free_page); fs_info->lowq_pg_num = (u16)BIT_GET_LOW_FREEPG_V1(free_page2); fs_info->pubq_pg_num = (u16)BIT_GET_PUB_FREEPG_V1(free_page2); fs_info->exq_pg_num = (u16)BIT_GET_EXQ_FREEPG_V1(free_page3); fs_info->ac_oqt_num = (u8)BIT_GET_AC_OQT_FREEPG_V1(free_page3); fs_info->non_ac_oqt_num = (u8)BIT_GET_NOAC_OQT_FREEPG_V1(free_page3); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } /** * phy_cfg_sdio_8822b() - phy config * @adapter : the adapter of halmac * Author : KaiYuan Chang * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status phy_cfg_sdio_8822b(struct halmac_adapter *adapter, enum halmac_intf_phy_platform pltfm) { return HALMAC_RET_SUCCESS; } /** * halmac_pcie_switch_8821c() - pcie gen1/gen2 switch * @adapter : the adapter of halmac * @cfg : gen1/gen2 selection * Author : KaiYuan Chang * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status pcie_switch_sdio_8822b(struct halmac_adapter *adapter, enum halmac_pcie_cfg cfg) { return HALMAC_RET_NOT_SUPPORT; } /** * intf_tun_sdio_8822b() - sdio interface fine tuning * @adapter : the adapter of halmac * Author : Ivan * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status intf_tun_sdio_8822b(struct halmac_adapter *adapter) { return HALMAC_RET_SUCCESS; } /** * halmac_get_sdio_tx_addr_sdio_88xx() - get CMD53 addr for the TX packet * @adapter : the adapter of halmac * @buf : tx packet, include txdesc * @size : tx packet size * @cmd53_addr : cmd53 addr value * Author : KaiYuan Chang/Ivan Lin * Return : enum halmac_ret_status * More details of status code can be found in prototype document */ enum halmac_ret_status get_sdio_tx_addr_8822b(struct halmac_adapter *adapter, u8 *buf, u32 size, u32 *cmd53_addr) { u32 len_unit4; enum halmac_qsel queue_sel; enum halmac_dma_mapping dma_mapping; PLTFM_MSG_TRACE("[TRACE]%s ===>\n", __func__); if (!buf) { PLTFM_MSG_ERR("[ERR]buf is NULL!!\n"); return HALMAC_RET_DATA_BUF_NULL; } if (size == 0) { PLTFM_MSG_ERR("[ERR]size is 0!!\n"); return HALMAC_RET_DATA_SIZE_INCORRECT; } queue_sel = (enum halmac_qsel)GET_TX_DESC_QSEL(buf); switch (queue_sel) { case HALMAC_QSEL_VO: case HALMAC_QSEL_VO_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VO]; break; case HALMAC_QSEL_VI: case HALMAC_QSEL_VI_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VI]; break; case HALMAC_QSEL_BE: case HALMAC_QSEL_BE_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BE]; break; case HALMAC_QSEL_BK: case HALMAC_QSEL_BK_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BK]; break; case HALMAC_QSEL_MGNT: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_MG]; break; case HALMAC_QSEL_HIGH: case HALMAC_QSEL_BCN: case HALMAC_QSEL_CMD: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_HI]; break; default: PLTFM_MSG_ERR("[ERR]Qsel is out of range\n"); return HALMAC_RET_QSEL_INCORRECT; } len_unit4 = (size >> 2) + ((size & (4 - 1)) ? 1 : 0); switch (dma_mapping) { case HALMAC_DMA_MAPPING_HIGH: *cmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_HIGH; break; case HALMAC_DMA_MAPPING_NORMAL: *cmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_NORMAL; break; case HALMAC_DMA_MAPPING_LOW: *cmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_LOW; break; case HALMAC_DMA_MAPPING_EXTRA: *cmd53_addr = HALMAC_SDIO_CMD_ADDR_TXFF_EXTRA; break; default: PLTFM_MSG_ERR("[ERR]DmaMapping is out of range\n"); return HALMAC_RET_DMA_MAP_INCORRECT; } *cmd53_addr = (*cmd53_addr << 13) | (len_unit4 & HALMAC_SDIO_4BYTE_LEN_MASK); PLTFM_MSG_TRACE("[TRACE]%s <===\n", __func__); return HALMAC_RET_SUCCESS; } static enum halmac_ret_status chk_qsel_8822b(struct halmac_adapter *adapter, u8 qsel_first, u8 *pkt, u8 *macid_cnt) { u8 flag = 0; u8 qsel_now; u8 macid; struct halmac_sdio_free_space *fs_info = &adapter->sdio_fs; macid = (u8)GET_TX_DESC_MACID(pkt); qsel_now = (u8)GET_TX_DESC_QSEL(pkt); if (qsel_first == qsel_now) { if (*(fs_info->macid_map + macid) == 0) { *(fs_info->macid_map + macid) = 1; (*macid_cnt)++; } } else { switch ((enum halmac_qsel)qsel_now) { case HALMAC_QSEL_VO: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_VO_V2) flag = 1; break; case HALMAC_QSEL_VO_V2: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_VO) flag = 1; break; case HALMAC_QSEL_VI: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_VI_V2) flag = 1; break; case HALMAC_QSEL_VI_V2: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_VI) flag = 1; break; case HALMAC_QSEL_BE: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_BE_V2) flag = 1; break; case HALMAC_QSEL_BE_V2: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_BE) flag = 1; break; case HALMAC_QSEL_BK: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_BK_V2) flag = 1; break; case HALMAC_QSEL_BK_V2: if ((enum halmac_qsel)qsel_first != HALMAC_QSEL_BK) flag = 1; break; case HALMAC_QSEL_MGNT: case HALMAC_QSEL_HIGH: case HALMAC_QSEL_BCN: case HALMAC_QSEL_CMD: flag = 1; break; default: PLTFM_MSG_ERR("[ERR]Qsel is out of range\n"); return HALMAC_RET_QSEL_INCORRECT; } if (flag == 1) { PLTFM_MSG_ERR("[ERR]Multi-Qsel is not allowed\n"); PLTFM_MSG_ERR("[ERR]qsel = %d, %d\n", qsel_first, qsel_now); return HALMAC_RET_QSEL_INCORRECT; } if (*(fs_info->macid_map + macid + MACID_MAX_8822B) == 0) { *(fs_info->macid_map + macid + MACID_MAX_8822B) = 1; (*macid_cnt)++; } } return HALMAC_RET_SUCCESS; } static enum halmac_ret_status chk_dma_mapping_8822b(struct halmac_adapter *adapter, u16 **cur_fs, u8 qsel_first) { enum halmac_dma_mapping dma_mapping; switch ((enum halmac_qsel)qsel_first) { case HALMAC_QSEL_VO: case HALMAC_QSEL_VO_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VO]; break; case HALMAC_QSEL_VI: case HALMAC_QSEL_VI_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_VI]; break; case HALMAC_QSEL_BE: case HALMAC_QSEL_BE_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BE]; break; case HALMAC_QSEL_BK: case HALMAC_QSEL_BK_V2: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_BK]; break; case HALMAC_QSEL_MGNT: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_MG]; break; case HALMAC_QSEL_HIGH: dma_mapping = adapter->pq_map[HALMAC_PQ_MAP_HI]; break; case HALMAC_QSEL_BCN: case HALMAC_QSEL_CMD: return HALMAC_RET_SUCCESS; default: PLTFM_MSG_ERR("[ERR]Qsel is out of range: %d\n", qsel_first); return HALMAC_RET_QSEL_INCORRECT; } switch (dma_mapping) { case HALMAC_DMA_MAPPING_HIGH: *cur_fs = &adapter->sdio_fs.hiq_pg_num; break; case HALMAC_DMA_MAPPING_NORMAL: *cur_fs = &adapter->sdio_fs.miq_pg_num; break; case HALMAC_DMA_MAPPING_LOW: *cur_fs = &adapter->sdio_fs.lowq_pg_num; break; case HALMAC_DMA_MAPPING_EXTRA: *cur_fs = &adapter->sdio_fs.exq_pg_num; break; default: PLTFM_MSG_ERR("[ERR]DmaMapping is out of range\n"); return HALMAC_RET_DMA_MAP_INCORRECT; } return HALMAC_RET_SUCCESS; } static enum halmac_ret_status chk_rqd_page_num_8822b(struct halmac_adapter *adapter, u8 *buf, u32 *rqd_pg_num, u16 **cur_fs, u8 *macid_cnt, u32 tx_agg_num) { u8 *pkt; u8 qsel_first; u32 i; u32 pkt_size; enum halmac_ret_status status = HALMAC_RET_SUCCESS; pkt = buf; qsel_first = (u8)GET_TX_DESC_QSEL(pkt); status = chk_dma_mapping_8822b(adapter, cur_fs, qsel_first); if (status != HALMAC_RET_SUCCESS) return status; for (i = 0; i < tx_agg_num; i++) { /*QSEL parser*/ status = chk_qsel_8822b(adapter, qsel_first, pkt, macid_cnt); if (status != HALMAC_RET_SUCCESS) return status; /*Page number parser*/ pkt_size = GET_TX_DESC_TXPKTSIZE(pkt) + GET_TX_DESC_OFFSET(pkt); *rqd_pg_num += (pkt_size >> TX_PAGE_SIZE_SHIFT_88XX) + ((pkt_size & (TX_PAGE_SIZE_88XX - 1)) ? 1 : 0); pkt += HALMAC_ALIGN(GET_TX_DESC_TXPKTSIZE(pkt) + (GET_TX_DESC_PKT_OFFSET(pkt) << 3) + TX_DESC_SIZE_88XX, 8); } return HALMAC_RET_SUCCESS; } #endif /* HALMAC_8822B_SUPPORT*/