/****************************************************************************** * * Copyright(c) 2007 - 2011 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. * * You should have received a copy of the GNU General Public License along with * this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA * * ******************************************************************************/ #define _RTL8188E_XMIT_C_ #include #include #ifdef CONFIG_XMIT_ACK void dump_txrpt_ccx_88e(void *buf) { struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; RTW_INFO("%s:\n" "tag1:%u, pkt_num:%u, txdma_underflow:%u, int_bt:%u, int_tri:%u, int_ccx:%u\n" "mac_id:%u, pkt_ok:%u, bmc:%u\n" "retry_cnt:%u, lifetime_over:%u, retry_over:%u\n" "ccx_qtime:%u\n" "final_data_rate:0x%02x\n" "qsel:%u, sw:0x%03x\n" , __func__ , txrpt_ccx->tag1, txrpt_ccx->pkt_num, txrpt_ccx->txdma_underflow, txrpt_ccx->int_bt, txrpt_ccx->int_tri, txrpt_ccx->int_ccx , txrpt_ccx->mac_id, txrpt_ccx->pkt_ok, txrpt_ccx->bmc , txrpt_ccx->retry_cnt, txrpt_ccx->lifetime_over, txrpt_ccx->retry_over , txrpt_ccx_qtime_88e(txrpt_ccx) , txrpt_ccx->final_data_rate , txrpt_ccx->qsel, txrpt_ccx_sw_88e(txrpt_ccx) ); } void handle_txrpt_ccx_88e(_adapter *adapter, u8 *buf) { struct txrpt_ccx_88e *txrpt_ccx = (struct txrpt_ccx_88e *)buf; #ifdef DBG_CCX dump_txrpt_ccx_88e(buf); #endif if (txrpt_ccx->int_ccx) { if (txrpt_ccx->pkt_ok) rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_SUCCESS); else rtw_ack_tx_done(&adapter->xmitpriv, RTW_SCTX_DONE_CCX_PKT_FAIL); } } #endif /* CONFIG_XMIT_ACK */ void _dbg_dump_tx_info(_adapter *padapter, int frame_tag, struct tx_desc *ptxdesc) { u8 bDumpTxPkt; u8 bDumpTxDesc = _FALSE; rtw_hal_get_def_var(padapter, HAL_DEF_DBG_DUMP_TXPKT, &(bDumpTxPkt)); if (bDumpTxPkt == 1) { /* dump txdesc for data frame */ RTW_INFO("dump tx_desc for data frame\n"); if ((frame_tag & 0x0f) == DATA_FRAMETAG) bDumpTxDesc = _TRUE; } else if (bDumpTxPkt == 2) { /* dump txdesc for mgnt frame */ RTW_INFO("dump tx_desc for mgnt frame\n"); if ((frame_tag & 0x0f) == MGNT_FRAMETAG) bDumpTxDesc = _TRUE; } else if (bDumpTxPkt == 3) { /* dump early info */ } if (bDumpTxDesc) { /* ptxdesc->txdw4 = cpu_to_le32(0x00001006); */ /* RTS Rate=24M */ /* ptxdesc->txdw6 = 0x6666f800; */ RTW_INFO("=====================================\n"); RTW_INFO("txdw0(0x%08x)\n", ptxdesc->txdw0); RTW_INFO("txdw1(0x%08x)\n", ptxdesc->txdw1); RTW_INFO("txdw2(0x%08x)\n", ptxdesc->txdw2); RTW_INFO("txdw3(0x%08x)\n", ptxdesc->txdw3); RTW_INFO("txdw4(0x%08x)\n", ptxdesc->txdw4); RTW_INFO("txdw5(0x%08x)\n", ptxdesc->txdw5); RTW_INFO("txdw6(0x%08x)\n", ptxdesc->txdw6); RTW_INFO("txdw7(0x%08x)\n", ptxdesc->txdw7); RTW_INFO("=====================================\n"); } } /* * Description: * Aggregation packets and send to hardware * * Return: * 0 Success * -1 Hardware resource(TX FIFO) not ready * -2 Software resource(xmitbuf) not ready */ #ifdef CONFIG_TX_EARLY_MODE /* #define DBG_EMINFO */ #if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 #define EARLY_MODE_MAX_PKT_NUM 10 #else #define EARLY_MODE_MAX_PKT_NUM 5 #endif struct EMInfo { u8 EMPktNum; u16 EMPktLen[EARLY_MODE_MAX_PKT_NUM]; }; void InsertEMContent_8188E( struct EMInfo *pEMInfo, IN u8 * VirtualAddress) { #if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 u8 index = 0; u32 dwtmp = 0; #endif memset(VirtualAddress, 0, EARLY_MODE_INFO_SIZE); if (pEMInfo->EMPktNum == 0) return; #ifdef DBG_EMINFO { int i; RTW_INFO("\n%s ==> pEMInfo->EMPktNum =%d\n", __func__, pEMInfo->EMPktNum); for (i = 0; i < EARLY_MODE_MAX_PKT_NUM; i++) RTW_INFO("%s ==> pEMInfo->EMPktLen[%d] =%d\n", __func__, i, pEMInfo->EMPktLen[i]); } #endif #if RTL8188E_EARLY_MODE_PKT_NUM_10 == 1 SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); if (pEMInfo->EMPktNum == 1) dwtmp = pEMInfo->EMPktLen[0]; else { dwtmp = pEMInfo->EMPktLen[0]; dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; dwtmp += pEMInfo->EMPktLen[1]; } SET_EARLYMODE_LEN0(VirtualAddress, dwtmp); if (pEMInfo->EMPktNum <= 3) dwtmp = pEMInfo->EMPktLen[2]; else { dwtmp = pEMInfo->EMPktLen[2]; dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; dwtmp += pEMInfo->EMPktLen[3]; } SET_EARLYMODE_LEN1(VirtualAddress, dwtmp); if (pEMInfo->EMPktNum <= 5) dwtmp = pEMInfo->EMPktLen[4]; else { dwtmp = pEMInfo->EMPktLen[4]; dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; dwtmp += pEMInfo->EMPktLen[5]; } SET_EARLYMODE_LEN2_1(VirtualAddress, dwtmp & 0xF); SET_EARLYMODE_LEN2_2(VirtualAddress, dwtmp >> 4); if (pEMInfo->EMPktNum <= 7) dwtmp = pEMInfo->EMPktLen[6]; else { dwtmp = pEMInfo->EMPktLen[6]; dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; dwtmp += pEMInfo->EMPktLen[7]; } SET_EARLYMODE_LEN3(VirtualAddress, dwtmp); if (pEMInfo->EMPktNum <= 9) dwtmp = pEMInfo->EMPktLen[8]; else { dwtmp = pEMInfo->EMPktLen[8]; dwtmp += ((dwtmp % 4) ? (4 - dwtmp % 4) : 0) + 4; dwtmp += pEMInfo->EMPktLen[9]; } SET_EARLYMODE_LEN4(VirtualAddress, dwtmp); #else SET_EARLYMODE_PKTNUM(VirtualAddress, pEMInfo->EMPktNum); SET_EARLYMODE_LEN0(VirtualAddress, pEMInfo->EMPktLen[0]); SET_EARLYMODE_LEN1(VirtualAddress, pEMInfo->EMPktLen[1]); SET_EARLYMODE_LEN2_1(VirtualAddress, pEMInfo->EMPktLen[2] & 0xF); SET_EARLYMODE_LEN2_2(VirtualAddress, pEMInfo->EMPktLen[2] >> 4); SET_EARLYMODE_LEN3(VirtualAddress, pEMInfo->EMPktLen[3]); SET_EARLYMODE_LEN4(VirtualAddress, pEMInfo->EMPktLen[4]); #endif } void UpdateEarlyModeInfo8188E(struct xmit_priv *pxmitpriv, struct xmit_buf *pxmitbuf) { /* _adapter *padapter, struct xmit_frame *pxmitframe,struct tx_servq *ptxservq */ int index, j; u16 offset, pktlen; PTXDESC_8188E ptxdesc; u8 *pmem, *pEMInfo_mem; s8 node_num_0 = 0, node_num_1 = 0; struct EMInfo eminfo; struct agg_pkt_info *paggpkt; struct xmit_frame *pframe = (struct xmit_frame *)pxmitbuf->priv_data; pmem = pframe->buf_addr; #ifdef DBG_EMINFO RTW_INFO("\n%s ==> agg_num:%d\n", __func__, pframe->agg_num); for (index = 0; index < pframe->agg_num; index++) { offset = pxmitpriv->agg_pkt[index].offset; pktlen = pxmitpriv->agg_pkt[index].pkt_len; RTW_INFO("%s ==> agg_pkt[%d].offset=%d\n", __func__, index, offset); RTW_INFO("%s ==> agg_pkt[%d].pkt_len=%d\n", __func__, index, pktlen); } #endif if (pframe->agg_num > EARLY_MODE_MAX_PKT_NUM) { node_num_0 = pframe->agg_num; node_num_1 = EARLY_MODE_MAX_PKT_NUM - 1; } for (index = 0; index < pframe->agg_num; index++) { offset = pxmitpriv->agg_pkt[index].offset; pktlen = pxmitpriv->agg_pkt[index].pkt_len; memset(&eminfo, 0, sizeof(struct EMInfo)); if (pframe->agg_num > EARLY_MODE_MAX_PKT_NUM) { if (node_num_0 > EARLY_MODE_MAX_PKT_NUM) { eminfo.EMPktNum = EARLY_MODE_MAX_PKT_NUM; node_num_0--; } else { eminfo.EMPktNum = node_num_1; node_num_1--; } } else eminfo.EMPktNum = pframe->agg_num - (index + 1); for (j = 0; j < eminfo.EMPktNum ; j++) { eminfo.EMPktLen[j] = pxmitpriv->agg_pkt[index + 1 + j].pkt_len + 4; /* 4 bytes CRC */ } if (pmem) { if (index == 0) { ptxdesc = (PTXDESC_8188E)(pmem); pEMInfo_mem = ((u8 *)ptxdesc) + TXDESC_SIZE; } else { pmem = pmem + pxmitpriv->agg_pkt[index - 1].offset; ptxdesc = (PTXDESC_8188E)(pmem); pEMInfo_mem = ((u8 *)ptxdesc) + TXDESC_SIZE; } #ifdef DBG_EMINFO RTW_INFO("%s ==> desc.pkt_len=%d\n", __func__, ptxdesc->pktlen); #endif InsertEMContent_8188E(&eminfo, pEMInfo_mem); } } memset(pxmitpriv->agg_pkt, 0, sizeof(struct agg_pkt_info) * MAX_AGG_PKT_NUM); } #endif #if defined(CONFIG_CONCURRENT_MODE) void fill_txdesc_force_bmc_camid(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) { if ((pattrib->encrypt > 0) && (!pattrib->bswenc) && (pattrib->bmc_camid != INVALID_SEC_MAC_CAM_ID)) { ptxdesc->txdw1 |= cpu_to_le32((0x01 << 21) & 0x00200000); ptxdesc->txdw1 |= cpu_to_le32((pattrib->bmc_camid) & 0x1f); } } #endif void rtl8188e_cal_txdesc_chksum(struct tx_desc *ptxdesc) { __le16 *usPtr = (__le16 *)ptxdesc; u32 count = 16; /* (32 bytes / 2 bytes per XOR) => 16 times */ u32 index; u16 checksum = 0; /* Clear first */ ptxdesc->txdw7 &= cpu_to_le32(0xffff0000); for (index = 0; index < count; index++) checksum ^= le16_to_cpu(*(usPtr + index)); ptxdesc->txdw7 |= cpu_to_le32(checksum & 0x0000ffff); }