From 9ca8dbcc65cfc63d6f5ef3312a33184e1d726e00 Mon Sep 17 00:00:00 2001 From: Yunhong Jiang Date: Tue, 4 Aug 2015 12:17:53 -0700 Subject: Add the rt linux 4.1.3-rt3 as base Import the rt linux 4.1.3-rt3 as OPNFV kvm base. It's from git://git.kernel.org/pub/scm/linux/kernel/git/rt/linux-rt-devel.git linux-4.1.y-rt and the base is: commit 0917f823c59692d751951bf5ea699a2d1e2f26a2 Author: Sebastian Andrzej Siewior Date: Sat Jul 25 12:13:34 2015 +0200 Prepare v4.1.3-rt3 Signed-off-by: Sebastian Andrzej Siewior We lose all the git history this way and it's not good. We should apply another opnfv project repo in future. Change-Id: I87543d81c9df70d99c5001fbdf646b202c19f423 Signed-off-by: Yunhong Jiang --- .../drivers/staging/rtl8723au/hal/rtl8723au_xmit.c | 520 +++++++++++++++++++++ 1 file changed, 520 insertions(+) create mode 100644 kernel/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c (limited to 'kernel/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c') diff --git a/kernel/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c b/kernel/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c new file mode 100644 index 000000000..6bf87fe86 --- /dev/null +++ b/kernel/drivers/staging/rtl8723au/hal/rtl8723au_xmit.c @@ -0,0 +1,520 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ +#define _RTL8192C_XMIT_C_ +#include +#include +#include +#include +#include +/* include */ +#include + +static int urb_zero_packet_chk(struct rtw_adapter *padapter, int sz) +{ + int blnSetTxDescOffset; + struct dvobj_priv *pdvobj = adapter_to_dvobj(padapter); + + if (pdvobj->ishighspeed) { + if (((sz + TXDESC_SIZE) % 512) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } else { + if (((sz + TXDESC_SIZE) % 64) == 0) + blnSetTxDescOffset = 1; + else + blnSetTxDescOffset = 0; + } + return blnSetTxDescOffset; +} + +static void rtl8192cu_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 = checksum ^ le16_to_cpu(*(usPtr + index)); + + ptxdesc->txdw7 |= cpu_to_le32(0x0000ffff&checksum); +} + +static void fill_txdesc_sectype(struct pkt_attrib *pattrib, struct tx_desc *ptxdesc) +{ + if ((pattrib->encrypt > 0) && !pattrib->bswenc) { + switch (pattrib->encrypt) { + /* SEC_TYPE */ + case WLAN_CIPHER_SUITE_WEP40: + case WLAN_CIPHER_SUITE_WEP104: + ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); + break; + case WLAN_CIPHER_SUITE_TKIP: + /* ptxdesc->txdw1 |= cpu_to_le32((0x02<<22)&0x00c00000); */ + ptxdesc->txdw1 |= cpu_to_le32((0x01<<22)&0x00c00000); + break; + case WLAN_CIPHER_SUITE_CCMP: + ptxdesc->txdw1 |= cpu_to_le32((0x03<<22)&0x00c00000); + break; + case 0: + default: + break; + } + } +} + +static void fill_txdesc_vcs(struct pkt_attrib *pattrib, __le32 *pdw) +{ + /* DBG_8723A("cvs_mode =%d\n", pattrib->vcs_mode); */ + + switch (pattrib->vcs_mode) { + case RTS_CTS: + *pdw |= cpu_to_le32(BIT(12)); + break; + case CTS_TO_SELF: + *pdw |= cpu_to_le32(BIT(11)); + break; + case NONE_VCS: + default: + break; + } + + if (pattrib->vcs_mode) { + *pdw |= cpu_to_le32(BIT(13)); + + /* Set RTS BW */ + if (pattrib->ht_en) { + *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(27)) : 0; + + if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + *pdw |= cpu_to_le32((0x01<<28)&0x30000000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + *pdw |= cpu_to_le32((0x02<<28)&0x30000000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + *pdw |= 0; + else + *pdw |= cpu_to_le32((0x03<<28)&0x30000000); + } + } +} + +static void fill_txdesc_phy(struct pkt_attrib *pattrib, __le32 *pdw) +{ + if (pattrib->ht_en) { + *pdw |= (pattrib->bwmode&HT_CHANNEL_WIDTH_40) ? cpu_to_le32(BIT(25)) : 0; + + if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_LOWER) + *pdw |= cpu_to_le32((0x01<<20)&0x003f0000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_UPPER) + *pdw |= cpu_to_le32((0x02<<20)&0x003f0000); + else if (pattrib->ch_offset == HAL_PRIME_CHNL_OFFSET_DONT_CARE) + *pdw |= 0; + else + *pdw |= cpu_to_le32((0x03<<20)&0x003f0000); + } +} + +static s32 update_txdesc(struct xmit_frame *pxmitframe, u8 *pmem, s32 sz) +{ + int pull = 0; + uint qsel; + struct rtw_adapter *padapter = pxmitframe->padapter; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct hal_data_8723a *pHalData = GET_HAL_DATA(padapter); + struct dm_priv *pdmpriv = &pHalData->dmpriv; + struct tx_desc *ptxdesc = (struct tx_desc *)pmem; + struct mlme_ext_priv *pmlmeext = &padapter->mlmeextpriv; + struct mlme_ext_info *pmlmeinfo = &pmlmeext->mlmext_info; + int bmcst = is_multicast_ether_addr(pattrib->ra); + + if (urb_zero_packet_chk(padapter, sz) == 0) { + ptxdesc = (struct tx_desc *)(pmem+PACKET_OFFSET_SZ); + pull = 1; + pxmitframe->pkt_offset--; + } + + memset(ptxdesc, 0, sizeof(struct tx_desc)); + + if (pxmitframe->frame_tag == DATA_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); + + qsel = (uint)(pattrib->qsel & 0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel << QSEL_SHT) & 0x00001f00); + + ptxdesc->txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); + + fill_txdesc_sectype(pattrib, ptxdesc); + + if (pattrib->ampdu_en) + ptxdesc->txdw1 |= cpu_to_le32(BIT(5));/* AGG EN */ + else + ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ + + /* offset 8 */ + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 , offset 20 */ + if (pattrib->qos_en) + ptxdesc->txdw4 |= cpu_to_le32(BIT(6));/* QoS */ + + if ((pattrib->ether_type != 0x888e) && + (pattrib->ether_type != 0x0806) && + (pattrib->dhcp_pkt != 1)) { + /* Non EAP & ARP & DHCP type data packet */ + + fill_txdesc_vcs(pattrib, &ptxdesc->txdw4); + fill_txdesc_phy(pattrib, &ptxdesc->txdw4); + + ptxdesc->txdw4 |= cpu_to_le32(0x00000008);/* RTS Rate = 24M */ + ptxdesc->txdw5 |= cpu_to_le32(0x0001ff00);/* */ + + /* use REG_INIDATA_RATE_SEL value */ + ptxdesc->txdw5 |= cpu_to_le32(pdmpriv->INIDATA_RATE[pattrib->mac_id]); + } else { + /* EAP data packet and ARP packet. */ + /* Use the 1M data rate to send the EAP/ARP packet. */ + /* This will maybe make the handshake smooth. */ + + ptxdesc->txdw1 |= cpu_to_le32(BIT(6));/* AGG BK */ + + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + if (pmlmeinfo->preamble_mode == PREAMBLE_SHORT) + ptxdesc->txdw4 |= cpu_to_le32(BIT(24));/* DATA_SHORT */ + + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } + } else if (pxmitframe->frame_tag == MGNT_FRAMETAG) { + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32(pattrib->mac_id&0x1f); + + qsel = (uint)(pattrib->qsel&0x0000001f); + ptxdesc->txdw1 |= cpu_to_le32((qsel<txdw1 |= cpu_to_le32((pattrib->raid<<16) & 0x000f0000); + + /* offset 8 */ + /* CCX-TXRPT ack for xmit mgmt frames. */ + if (pxmitframe->ack_report) + ptxdesc->txdw2 |= cpu_to_le32(BIT(19)); + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + /* offset 20 */ + ptxdesc->txdw5 |= cpu_to_le32(BIT(17));/* retry limit enable */ + ptxdesc->txdw5 |= cpu_to_le32(0x00180000);/* retry limit = 6 */ + + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } else if (pxmitframe->frame_tag == TXAGG_FRAMETAG) { + DBG_8723A("pxmitframe->frame_tag == TXAGG_FRAMETAG\n"); + } else { + DBG_8723A("pxmitframe->frame_tag = %d\n", + pxmitframe->frame_tag); + + /* offset 4 */ + ptxdesc->txdw1 |= cpu_to_le32((4)&0x1f);/* CAM_ID(MAC_ID) */ + + ptxdesc->txdw1 |= cpu_to_le32((6<<16) & 0x000f0000);/* raid */ + + /* offset 8 */ + + /* offset 12 */ + ptxdesc->txdw3 |= cpu_to_le32((pattrib->seqnum<<16)&0xffff0000); + + /* offset 16 */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(8));/* driver uses rate */ + + /* offset 20 */ + ptxdesc->txdw5 |= cpu_to_le32(MRateToHwRate23a(pmlmeext->tx_rate)); + } + + /* (1) The sequence number of each non-Qos frame / broadcast / multicast / */ + /* mgnt frame should be controled by Hw because Fw will also send null data */ + /* which we cannot control when Fw LPS enable. */ + /* --> default enable non-Qos data sequense number. 2010.06.23. by tynli. */ + /* (2) Enable HW SEQ control for beacon packet, because we use Hw beacon. */ + /* (3) Use HW Qos SEQ to control the seq num of Ext port non-Qos packets. */ + if (!pattrib->qos_en) { + /* Hw set sequence number */ + ptxdesc->txdw4 |= cpu_to_le32(BIT(7)); + /* set bit3 to 1. */ + ptxdesc->txdw3 |= cpu_to_le32((8 << 28)); + } + + /* offset 0 */ + ptxdesc->txdw0 |= cpu_to_le32(sz&0x0000ffff); + ptxdesc->txdw0 |= cpu_to_le32(OWN | FSG | LSG); + ptxdesc->txdw0 |= cpu_to_le32(((TXDESC_SIZE+OFFSET_SZ)<txdw0 |= cpu_to_le32(BIT(24)); + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + "offset0-txdesc = 0x%x\n", ptxdesc->txdw0); + + /* offset 4 */ + /* pkt_offset, unit:8 bytes padding */ + if (pxmitframe->pkt_offset > 0) + ptxdesc->txdw1 |= cpu_to_le32((pxmitframe->pkt_offset << 26) & 0x7c000000); + + rtl8192cu_cal_txdesc_chksum(ptxdesc); + return pull; +} + +static int rtw_dump_xframe(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + int ret = _SUCCESS; + int inner_ret = _SUCCESS; + int t, sz, w_sz, pull = 0; + u8 *mem_addr; + u32 ff_hwaddr; + struct xmit_buf *pxmitbuf = pxmitframe->pxmitbuf; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + + if (pxmitframe->frame_tag == DATA_FRAMETAG && + pxmitframe->attrib.ether_type != ETH_P_ARP && + pxmitframe->attrib.ether_type != ETH_P_PAE && + pxmitframe->attrib.dhcp_pkt != 1) + rtw_issue_addbareq_cmd23a(padapter, pxmitframe); + + mem_addr = pxmitframe->buf_addr; + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, "rtw_dump_xframe()\n"); + + for (t = 0; t < pattrib->nr_frags; t++) { + if (inner_ret != _SUCCESS && ret == _SUCCESS) + ret = _FAIL; + + if (t != (pattrib->nr_frags - 1)) { + RT_TRACE(_module_rtl871x_xmit_c_, _drv_err_, + "pattrib->nr_frags =%d\n", pattrib->nr_frags); + + sz = pxmitpriv->frag_len; + sz = sz - 4 - pattrib->icv_len; + } else { + /* no frag */ + sz = pattrib->last_txcmdsz; + } + + pull = update_txdesc(pxmitframe, mem_addr, sz); + + if (pull) { + mem_addr += PACKET_OFFSET_SZ; /* pull txdesc head */ + + pxmitframe->buf_addr = mem_addr; + + w_sz = sz + TXDESC_SIZE; + } else { + w_sz = sz + TXDESC_SIZE + PACKET_OFFSET_SZ; + } + + ff_hwaddr = rtw_get_ff_hwaddr23a(pxmitframe); + inner_ret = rtl8723au_write_port(padapter, ff_hwaddr, + w_sz, pxmitbuf); + rtw_count_tx_stats23a(padapter, pxmitframe, sz); + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + "rtw_write_port, w_sz =%d\n", w_sz); + + mem_addr += w_sz; + + mem_addr = PTR_ALIGN(mem_addr, 4); + } + + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + if (ret != _SUCCESS) + rtw23a_sctx_done_err(&pxmitbuf->sctx, RTW_SCTX_DONE_UNKNOWN); + + return ret; +} + +bool rtl8723au_xmitframe_complete(struct rtw_adapter *padapter, + struct xmit_priv *pxmitpriv, + struct xmit_buf *pxmitbuf) +{ + struct hw_xmit *phwxmits; + struct xmit_frame *pxmitframe; + int hwentry; + int res = _SUCCESS, xcnt = 0; + + phwxmits = pxmitpriv->hwxmits; + hwentry = pxmitpriv->hwxmit_entry; + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, "xmitframe_complete()\n"); + + if (pxmitbuf == NULL) { + pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); + if (!pxmitbuf) + return false; + } + pxmitframe = rtw_dequeue_xframe23a(pxmitpriv, phwxmits, hwentry); + + if (pxmitframe) { + pxmitframe->pxmitbuf = pxmitbuf; + + pxmitframe->buf_addr = pxmitbuf->pbuf; + + pxmitbuf->priv_data = pxmitframe; + + if (pxmitframe->frame_tag == DATA_FRAMETAG) { + if (pxmitframe->attrib.priority <= 15)/* TID0~15 */ + res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); + + rtw_os_xmit_complete23a(padapter, pxmitframe);/* always return ndis_packet after rtw_xmitframe_coalesce23a */ + } + + RT_TRACE(_module_rtl871x_xmit_c_, _drv_info_, + "xmitframe_complete(): rtw_dump_xframe\n"); + + if (res == _SUCCESS) { + rtw_dump_xframe(padapter, pxmitframe); + } else { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + } + xcnt++; + } else { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + return false; + } + return true; +} + +static int xmitframe_direct(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + int res; + + res = rtw_xmitframe_coalesce23a(padapter, pxmitframe->pkt, pxmitframe); + if (res == _SUCCESS) + rtw_dump_xframe(padapter, pxmitframe); + return res; +} + +/* + * Return + * true dump packet directly + * false enqueue packet + */ +bool rtl8723au_hal_xmit(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + int res; + struct xmit_buf *pxmitbuf = NULL; + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + struct pkt_attrib *pattrib = &pxmitframe->attrib; + struct mlme_priv *pmlmepriv = &padapter->mlmepriv; + + pattrib->qsel = pattrib->priority; + spin_lock_bh(&pxmitpriv->lock); + +#ifdef CONFIG_8723AU_AP_MODE + if (xmitframe_enqueue_for_sleeping_sta23a(padapter, pxmitframe)) { + struct sta_info *psta; + struct sta_priv *pstapriv = &padapter->stapriv; + + spin_unlock_bh(&pxmitpriv->lock); + + if (pattrib->psta) + psta = pattrib->psta; + else + psta = rtw_get_stainfo23a(pstapriv, pattrib->ra); + + if (psta) { + if (psta->sleepq_len > (NR_XMITFRAME>>3)) + wakeup_sta_to_xmit23a(padapter, psta); + } + + return false; + } +#endif + + if (rtw_txframes_sta_ac_pending23a(padapter, pattrib) > 0) + goto enqueue; + + if (check_fwstate(pmlmepriv, _FW_UNDER_SURVEY|_FW_UNDER_LINKING) == true) + goto enqueue; + + pxmitbuf = rtw_alloc_xmitbuf23a(pxmitpriv); + if (pxmitbuf == NULL) + goto enqueue; + + spin_unlock_bh(&pxmitpriv->lock); + + pxmitframe->pxmitbuf = pxmitbuf; + pxmitframe->buf_addr = pxmitbuf->pbuf; + pxmitbuf->priv_data = pxmitframe; + + if (xmitframe_direct(padapter, pxmitframe) != _SUCCESS) { + rtw_free_xmitbuf23a(pxmitpriv, pxmitbuf); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + } + return true; + +enqueue: + res = rtw_xmitframe_enqueue23a(padapter, pxmitframe); + spin_unlock_bh(&pxmitpriv->lock); + + if (res != _SUCCESS) { + RT_TRACE(_module_xmit_osdep_c_, _drv_err_, + "pre_xmitframe: enqueue xmitframe fail\n"); + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + /* Trick, make the statistics correct */ + pxmitpriv->tx_pkts--; + pxmitpriv->tx_drop++; + return true; + } + return false; +} + +int rtl8723au_mgnt_xmit(struct rtw_adapter *padapter, + struct xmit_frame *pmgntframe) +{ + return rtw_dump_xframe(padapter, pmgntframe); +} + +int rtl8723au_hal_xmitframe_enqueue(struct rtw_adapter *padapter, + struct xmit_frame *pxmitframe) +{ + struct xmit_priv *pxmitpriv = &padapter->xmitpriv; + int err; + + err = rtw_xmitframe_enqueue23a(padapter, pxmitframe); + if (err != _SUCCESS) { + rtw_free_xmitframe23a(pxmitpriv, pxmitframe); + + /* Trick, make the statistics correct */ + pxmitpriv->tx_pkts--; + pxmitpriv->tx_drop++; + } else { + tasklet_hi_schedule(&pxmitpriv->xmit_tasklet); + } + return err; +} -- cgit 1.2.3-korg