M7350/wlan/8192es/DriverSrcPkg/Driver/rtl8192cd_92es/hal_intf_xmit.c
2024-09-09 08:59:52 +00:00

1338 lines
32 KiB
C
Executable File

/*
* SDIO core routines
*
* $Id: hal_intf_xmit.c,v 1.27.2.31 2010/12/31 08:37:43 family Exp $
*
* Copyright (c) 2009 Realtek Semiconductor Corp.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#define _HAL_INTF_XMIT_C_
#ifdef __KERNEL__
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#endif
#include "./8192cd.h"
#include "./8192cd_headers.h"
#include "./8192cd_debug.h"
#ifdef WMM_APSD
const unsigned char wmm_apsd_bitmask[MAX_STA_TX_SERV_QUEUE] = {
0, // MGNT_QUEUE
0x04, // BK_QUEUE
0x08, // BE_QUEUE
0x02, // VI_QUEUE
0x01 // VO_QUEUE
};
#endif
#ifdef TX_SHORTCUT
int get_tx_sc_index(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned char *hdr, unsigned char pktpri)
{
struct tx_sc_entry *ptxsc_entry;
int i;
ptxsc_entry = pstat->tx_sc_ent[pktpri];
for (i=0; i<TX_SC_ENTRY_NUM; i++) {
#ifdef MCAST2UI_REFINE
if ((OPMODE & WIFI_AP_STATE)
#ifdef WDS
&& !(pstat->state & WIFI_WDS)
#endif
) {
if (!memcmp(hdr+6, &ptxsc_entry[i].ethhdr.saddr, sizeof(struct wlan_ethhdr_t)-6))
return i;
}
else
#endif
{
if (!memcmp(hdr, &ptxsc_entry[i].ethhdr, sizeof(struct wlan_ethhdr_t)))
return i;
}
}
return -1;
}
int get_tx_sc_free_entry(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned char *hdr, unsigned char pktpri)
{
struct tx_sc_entry *ptxsc_entry;
int i;
i = get_tx_sc_index(priv, pstat, hdr, pktpri);
if (i >= 0)
return i;
ptxsc_entry = pstat->tx_sc_ent[pktpri];
for (i=0; i<TX_SC_ENTRY_NUM; i++) {
if (ptxsc_entry[i].txcfg.fr_len == 0)
return i;
}
// no free entry
i = pstat->tx_sc_replace_idx[pktpri];
pstat->tx_sc_replace_idx[pktpri] = (i+1) % TX_SC_ENTRY_NUM;
return i;
}
#endif // TX_SHORTCUT
u32 rtw_is_tx_queue_empty(struct rtl8192cd_priv *priv, struct tx_insn *txcfg)
{
int empty = TRUE;
if (txcfg->pstat) {
if (tx_servq_len(&txcfg->pstat->tx_queue[txcfg->q_num]) > 0)
empty = FALSE;
} else { // txcfg->pstat == NULL
if (MGNT_QUEUE == txcfg->q_num) {
if (tx_servq_len(&priv->tx_mgnt_queue) > 0)
empty = FALSE;
} else if (tx_servq_len(&priv->tx_mc_queue) > 0)
empty = FALSE;
}
return empty;
}
// Note. update_txinsn_stage1() must be fulfilled first before calling
int rtw_xmit_enqueue(struct rtl8192cd_priv *priv, struct tx_insn *txcfg)
{
struct xmit_frame *pxmitframe;
int ret;
#ifdef CONFIG_SDIO_TX_FILTER_BY_PRI
if (OPMODE & WIFI_AP_STATE) {
if (priv->pshare->rf_ft_var.tx_filter_enable && !priv->pshare->iot_mode_enable) {
int qlen = priv->pshare->free_xmit_queue.qlen;
switch (txcfg->q_num) {
case VO_QUEUE:
if (1 > qlen) {
priv->pshare->nr_tx_filter_vo++;
return FALSE;
}
break;
case VI_QUEUE:
if (41 > qlen) {
priv->pshare->nr_tx_filter_vi++;
return FALSE;
}
break;
case BE_QUEUE:
if (81 > qlen) {
priv->pshare->nr_tx_filter_be++;
return FALSE;
}
break;
case BK_QUEUE:
if (121 > qlen) {
priv->pshare->nr_tx_filter_bk++;
return FALSE;
}
break;
}
}
}
#endif
if (NULL == (pxmitframe = rtw_alloc_xmitframe(priv))) {
DEBUG_WARN("No more xmitframe\n");
return FALSE;
}
memcpy(&pxmitframe->txinsn, txcfg, sizeof(struct tx_insn));
pxmitframe->priv = priv;
if (txcfg->is_urgent)
ret = rtw_enqueue_urg_xmitframe(priv, pxmitframe, ENQUEUE_TO_TAIL);
else
ret = rtw_enqueue_xmitframe(priv, pxmitframe, ENQUEUE_TO_TAIL);
if (FALSE == ret) {
priv->ext_stats.tx_drops++;
DEBUG_ERR("TX DROP: %s failed!\n", __func__);
rtw_free_xmitframe(priv, pxmitframe);
return FALSE;
}
return TRUE;
}
// Note. for __rtl8192cd_firetx(), it not release any xmitbuf resource no matter return value is success or fail
void rtw_handle_xmit_fail(struct rtl8192cd_priv *priv, struct tx_insn *txcfg)
{
struct xmit_buf *pxmitbuf = txcfg->pxmitbuf;
if (pxmitbuf) {
// handle error case for the first user that hold xmitbuf
if ((txcfg == pxmitbuf->agg_start_with) && pxmitbuf->use_hw_queue) {
txcfg->pxmitbuf = NULL;
pxmitbuf->use_hw_queue = 0;
#ifdef CONFIG_SDIO_TX_AGGREGATION
if (pxmitbuf->flags & XMIT_BUF_FLAG_REUSE) {
unsigned long flags;
xmit_preempt_disable(flags);
// Release the ownership of the HW TX queue
clear_bit(pxmitbuf->q_num, &priv->pshare->use_hw_queue_bitmap);
/* Enqueue the pxmitbuf, and it will be dequeued by a xmit thread later */
enqueue_pending_xmitbuf(priv, pxmitbuf);
xmit_preempt_enable(flags);
} else
#endif // CONFIG_SDIO_TX_AGGREGATION
{
// Release the ownership of the HW TX queue
clear_bit(pxmitbuf->q_num, &priv->pshare->use_hw_queue_bitmap);
rtw_free_xmitbuf(priv, pxmitbuf);
// schedule xmit_tasklet to avoid the same source TX queue not be handled
// because this queue had enqueued packet during this processing
if (FALSE == priv->pshare->bDriverStopped)
tasklet_hi_schedule(&priv->pshare->xmit_tasklet);
}
}
}
}
static int _rtw_xmit_decision(struct rtl8192cd_priv *priv, struct tx_insn *txcfg)
{
if (test_and_set_bit(txcfg->q_num, &priv->pshare->use_hw_queue_bitmap) == 0)
{
// Got the ownership of the corresponding HW TX queue
if (NULL == txcfg->pxmitbuf) {
struct xmit_buf *pxmitbuf;
if (txcfg->is_urgent) {
pxmitbuf = rtw_alloc_urg_xmitbuf(priv, (u8)txcfg->q_num);
} else if (txcfg->fr_type == _SKB_FRAME_TYPE_) {
#if 0//def CONFIG_SDIO_TX_AGGREGATION
pxmitbuf = get_usable_pending_xmitbuf(priv, txcfg);
if (NULL == pxmitbuf)
#endif
pxmitbuf = rtw_alloc_xmitbuf(priv, (u8)txcfg->q_num);
} else {
pxmitbuf = rtw_alloc_xmitbuf_ext(priv, (u8)txcfg->q_num);
}
if (NULL == pxmitbuf) {
// Release the ownership of the HW TX queue
clear_bit(txcfg->q_num, &priv->pshare->use_hw_queue_bitmap);
if (rtw_xmit_enqueue(priv, txcfg) == FALSE) {
return XMIT_DECISION_STOP;
}
return XMIT_DECISION_ENQUEUE;
}
pxmitbuf->agg_start_with = txcfg;
txcfg->pxmitbuf = pxmitbuf;
} else {
BUG_ON((txcfg->pxmitbuf->q_num != txcfg->q_num) ||txcfg->pxmitbuf->use_hw_queue);
}
txcfg->pxmitbuf->use_hw_queue = 1;
}
else if (NULL == txcfg->pxmitbuf) {
if (rtw_xmit_enqueue(priv, txcfg) == FALSE) {
return XMIT_DECISION_STOP;
}
return XMIT_DECISION_ENQUEUE;
}
else {
BUG_ON(0 == txcfg->pxmitbuf->use_hw_queue);
}
return XMIT_DECISION_CONTINUE;
}
int rtw_xmit_decision(struct rtl8192cd_priv *priv, struct tx_insn *txcfg)
{
unsigned long flags;
int res;
xmit_preempt_disable(flags);
res = _rtw_xmit_decision(priv, txcfg);
xmit_preempt_enable(flags);
return res;
}
int dz_queue(struct rtl8192cd_priv *priv, struct stat_info *pstat, struct tx_insn *txcfg)
{
if (pstat)
{
if (0 == pstat->expire_to)
return FALSE;
if (rtw_xmit_enqueue(priv, txcfg) == FALSE) {
return FALSE;
}
#ifdef WMM_APSD
if ((QOS_ENABLE) && (APSD_ENABLE) && (pstat->apsd_bitmap & 0x0f)
&& (pstat->apsd_bitmap & wmm_apsd_bitmask[txcfg->q_num]))
pstat->apsd_pkt_buffering = 1;
#endif
return TRUE;
}
else { // Multicast or Broadcast or class 1 frame
if (rtw_xmit_enqueue(priv, txcfg) == TRUE) {
priv->pkt_in_dtimQ = 1;
return TRUE;
}
}
return FALSE;
}
#define MAX_FRAG_NUM 16
int update_txinsn_stage1(struct rtl8192cd_priv *priv, struct tx_insn* txcfg)
{
struct sk_buff *pskb=NULL;
unsigned short protocol;
unsigned char *da=NULL;
struct stat_info *pstat=NULL;
int priority=0;
if (txcfg->aggre_en == FG_AGGRE_MSDU_MIDDLE || txcfg->aggre_en == FG_AGGRE_MSDU_LAST)
return TRUE;
/*---frag_thrshld setting---plus tune---0115*/
#ifdef WDS
if (txcfg->wdsIdx >= 0){
txcfg->frag_thrshld = 2346; // if wds, disable fragment
}else
#endif
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s){
txcfg->frag_thrshld = 2346; // if Mesh case, disable fragment
}else
#endif
{
txcfg->frag_thrshld = FRAGTHRSLD - _CRCLNG_;
}
/*---frag_thrshld setting---end*/
txcfg->rts_thrshld = RTSTHRSLD;
txcfg->privacy = txcfg->iv = txcfg->icv = txcfg->mic = 0;
txcfg->frg_num = 0;
txcfg->need_ack = 1;
if (txcfg->fr_type == _SKB_FRAME_TYPE_)
{
pskb = ((struct sk_buff *)txcfg->pframe);
txcfg->fr_len = pskb->len - WLAN_ETHHDR_LEN;
protocol = ntohs(*((UINT16 *)((UINT8 *)pskb->data + ETH_ALEN*2)));
if ((protocol + WLAN_ETHHDR_LEN) > WLAN_MAX_ETHFRM_LEN)
txcfg->llc = sizeof(struct llc_snap);
#ifdef MP_TEST
if (OPMODE & WIFI_MP_STATE) {
txcfg->hdr_len = WLAN_HDR_A3_LEN;
txcfg->frg_num = 1;
if (IS_MCAST(pskb->data))
txcfg->need_ack = 0;
return TRUE;
}
#endif
#ifdef WDS
if (txcfg->wdsIdx >= 0) {
pstat = get_stainfo(priv, priv->pmib->dot11WdsInfo.entry[txcfg->wdsIdx].macAddr);
if (pstat == NULL) {
DEBUG_ERR("TX DROP: %s: get_stainfo() for wds failed [%d]!\n", (char *)__FUNCTION__, txcfg->wdsIdx);
return FALSE;
}
txcfg->privacy = priv->pmib->dot11WdsInfo.wdsPrivacy;
switch (txcfg->privacy) {
case _WEP_40_PRIVACY_:
case _WEP_104_PRIVACY_:
txcfg->iv = 4;
txcfg->icv = 4;
break;
case _TKIP_PRIVACY_:
txcfg->iv = 8;
txcfg->icv = 4;
txcfg->mic = 0;
break;
case _CCMP_PRIVACY_:
txcfg->iv = 8;
txcfg->icv = 0;
txcfg->mic = 8;
break;
}
txcfg->frg_num = 1;
if (txcfg->aggre_en < FG_AGGRE_MSDU_FIRST) {
priority = get_skb_priority(priv, pskb, pstat);
#ifdef RTL_MANUAL_EDCA
txcfg->q_num = PRI_TO_QNUM(priv, priority);
#else
PRI_TO_QNUM(priority, txcfg->q_num, priv->pmib->dot11OperationEntry.wifi_specific);
#endif
}
txcfg->need_ack = 1;
txcfg->pstat = pstat;
#ifdef WIFI_WMM
if ((QOS_ENABLE) && (pstat->QosEnabled))
txcfg->hdr_len = WLAN_HDR_A4_QOS_LEN;
else
#endif
txcfg->hdr_len = WLAN_HDR_A4_LEN;
return TRUE;
}
#endif // WDS
if (OPMODE & WIFI_AP_STATE) {
#ifdef MCAST2UI_REFINE
pstat = get_stainfo(priv, &pskb->cb[10]);
#else
pstat = get_stainfo(priv, pskb->data);
#endif
#ifdef A4_STA
if (pstat == NULL) {
if (txcfg->pstat && (txcfg->pstat->state & WIFI_A4_STA))
pstat = txcfg->pstat;
else if (!IS_MCAST(pskb->data) && priv->pshare->rf_ft_var.a4_enable)
pstat = a4_sta_lookup(priv, pskb->data);
if (pstat)
da = pstat->hwaddr;
}
#endif
}
#ifdef CLIENT_MODE
else if (OPMODE & WIFI_STATION_STATE)
pstat = get_stainfo(priv, BSSID);
else if (OPMODE & WIFI_ADHOC_STATE)
pstat = get_stainfo(priv, pskb->data);
#endif
#ifdef WIFI_WMM
if ((pstat) && (QOS_ENABLE) && (pstat->QosEnabled)) {
txcfg->hdr_len = WLAN_HDR_A3_QOS_LEN;
}
else
#endif
{
txcfg->hdr_len = WLAN_HDR_A3_LEN;
}
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s)
{
txcfg->hdr_len = WLAN_HDR_A4_QOS_LEN ;
da = txcfg->nhop_11s;
}
else
#endif
#ifdef A4_STA
if (!da)
#endif
#ifdef MCAST2UI_REFINE
da = &pskb->cb[10];
#else
da = pskb->data;
#endif
//check if da is associated, if not, just drop and return false
if (!IS_MCAST(da)
#ifdef CLIENT_MODE
|| (OPMODE & WIFI_STATION_STATE)
#endif
#ifdef A4_STA
|| (pstat && (pstat->state & WIFI_A4_STA))
#endif
)
{
if ((pstat == NULL) || (!(pstat->state & WIFI_ASOC_STATE)))
{
DEBUG_ERR("TX DROP: Non asoc tx request!\n");
return FALSE;
}
#ifdef A4_STA
if (pstat->state & WIFI_A4_STA)
txcfg->hdr_len += WLAN_ADDR_LEN;
#endif
if (((protocol == 0x888E) && ((GET_UNICAST_ENCRYP_KEYLEN == 0)
#ifdef WIFI_SIMPLE_CONFIG
|| (pstat->state & WIFI_WPS_JOIN)
#endif
))
#ifdef CONFIG_RTL_WAPI_SUPPORT
|| (protocol == ETH_P_WAPI)
#endif
#ifdef BEAMFORMING_SUPPORT
|| (txcfg->ndpa)
#endif
)
txcfg->privacy = 0;
else
txcfg->privacy = get_privacy(priv, pstat, &txcfg->iv, &txcfg->icv, &txcfg->mic);
if ((OPMODE & WIFI_AP_STATE) && !IS_MCAST(da) && (isDHCPpkt(pskb) == TRUE))
txcfg->is_dhcp = 1;
if ((protocol == 0x888E)
#ifdef CONFIG_RTL_WAPI_SUPPORT
|| (protocol == ETH_P_WAPI)
#endif
|| txcfg->is_dhcp) {
txcfg->is_urgent = 1;
}
if (txcfg->aggre_en < FG_AGGRE_MSDU_FIRST) {
#ifdef CONFIG_RTK_MESH
priority = get_skb_priority3(priv, pskb, txcfg->is_11s, pstat);
#else
priority = get_skb_priority(priv, pskb, pstat);
#endif
#ifdef RTL_MANUAL_EDCA
txcfg->q_num = PRI_TO_QNUM(priv, priority);
#else
PRI_TO_QNUM(priority, txcfg->q_num, priv->pmib->dot11OperationEntry.wifi_specific);
#endif
}
}
else
{
// if group key not set yet, don't let unencrypted multicast go to air
if (priv->pmib->dot11GroupKeysTable.dot11Privacy) {
if (GET_GROUP_ENCRYP_KEYLEN == 0) {
DEBUG_ERR("TX DROP: group key not set yet!\n");
return FALSE;
}
}
txcfg->privacy = get_mcast_privacy(priv, &txcfg->iv, &txcfg->icv, &txcfg->mic);
txcfg->q_num = priv->tx_mc_queue.q_num;
pskb->cb[1] = 0;
if ((*da) == 0xff) // broadcast
txcfg->tx_rate = find_rate(priv, NULL, 0, 1);
else { // multicast
if (priv->pmib->dot11StationConfigEntry.lowestMlcstRate)
txcfg->tx_rate = get_rate_from_bit_value(priv->pmib->dot11StationConfigEntry.lowestMlcstRate);
else
txcfg->tx_rate = find_rate(priv, NULL, 1, 1);
}
#ifdef CONFIG_RTK_MESH
mesh_debug_tx4(priv, txcfg);
#endif
txcfg->lowest_tx_rate = txcfg->tx_rate;
txcfg->fixed_rate = 1;
}
}
#ifdef _11s_TEST_MODE_ /*---11s mgt frame---*/
else if (txcfg->is_11s)
mesh_debug_tx6(priv, txcfg);
#endif
if (!da)
{
// This is non data frame, no need to frag.
#ifdef CONFIG_RTK_MESH
if(txcfg->is_11s)
da = GetAddr1Ptr(txcfg->phdr);
else
#endif
da = get_da((unsigned char *) (txcfg->phdr));
#ifdef CLIENT_MODE
if ((OPMODE & WIFI_AP_STATE) || (OPMODE & WIFI_ADHOC_STATE))
#else
if (OPMODE & WIFI_AP_STATE)
#endif
{
if (!IS_MCAST(da) && (GetFrameSubType(txcfg->phdr) != WIFI_PROBERSP)) {
pstat = get_stainfo(priv, da);
}
}
#ifdef CLIENT_MODE
else if (OPMODE & WIFI_STATION_STATE)
{
pstat = get_stainfo(priv, BSSID);
}
#endif
txcfg->frg_num = 1;
if (IS_MCAST(da))
txcfg->need_ack = 0;
else
txcfg->need_ack = 1;
if (GetPrivacy(txcfg->phdr))
{
#ifdef CONFIG_IEEE80211W
if (txcfg->isPMF) {
txcfg->privacy = _CCMP_PRIVACY_;
txcfg->iv = 8;
txcfg->icv = 0;
txcfg->mic = 8;
} else
#endif
{
// only auth with legacy wep...
txcfg->iv = 4;
txcfg->icv = 4;
txcfg->privacy = priv->pmib->dot1180211AuthEntry.dot11PrivacyAlgrthm;
}
}
#ifdef DRVMAC_LB
if (GetFrameType(txcfg->phdr) == WIFI_MGT_TYPE)
#endif
if (txcfg->fr_len != 0) //for mgt frame
txcfg->hdr_len += WLAN_HDR_A3_LEN;
}
txcfg->is_mcast = IS_MCAST(da);
#ifdef CLIENT_MODE
if ((OPMODE & WIFI_AP_STATE) || (OPMODE & WIFI_ADHOC_STATE))
#else
if (OPMODE & WIFI_AP_STATE)
#endif
{
if (IS_MCAST(da))
{
txcfg->frg_num = 1;
txcfg->need_ack = 0;
txcfg->rts_thrshld = 10000;
}
else
{
txcfg->pstat = pstat;
}
}
#ifdef CLIENT_MODE
else if (OPMODE & WIFI_STATION_STATE)
{
txcfg->pstat = pstat;
}
#endif
#ifdef BEAMFORMING_SUPPORT
if((priv->pmib->dot11RFEntry.txbf == 1) && (pstat) &&
((pstat->ht_cap_len && (pstat->ht_cap_buf.txbf_cap))
#ifdef RTK_AC_SUPPORT
||(pstat->vht_cap_len && (cpu_to_le32(pstat->vht_cap_buf.vht_cap_info) & BIT(SU_BFEE_S)))
#endif
))
Beamforming_GidPAid(priv, pstat);
#endif
txcfg->frag_thrshld -= (txcfg->mic + txcfg->iv + txcfg->icv + txcfg->hdr_len);
if (txcfg->frg_num == 0)
{
if (txcfg->aggre_en > 0)
txcfg->frg_num = 1;
else {
// how many mpdu we need...
int size;
size = txcfg->fr_len + txcfg->llc + ((_TKIP_PRIVACY_ == txcfg->privacy) ? 8 : 0);
txcfg->frg_num = (size + txcfg->frag_thrshld -1) / txcfg->frag_thrshld;
if (unlikely(txcfg->frg_num > MAX_FRAG_NUM)) {
txcfg->frag_thrshld = 2346;
txcfg->frg_num = 1;
}
}
}
return TRUE;
}
int update_txinsn_stage2(struct rtl8192cd_priv *priv, struct tx_insn* txcfg)
{
struct sk_buff *pskb=NULL;
unsigned short protocol;
struct stat_info *pstat=NULL;
int priority=0;
if (txcfg->aggre_en == FG_AGGRE_MSDU_MIDDLE || txcfg->aggre_en == FG_AGGRE_MSDU_LAST)
return TRUE;
if (txcfg->fr_type == _SKB_FRAME_TYPE_)
{
#ifdef MP_TEST
if (OPMODE & WIFI_MP_STATE) {
return TRUE;
}
#endif
pskb = ((struct sk_buff *)txcfg->pframe);
pstat = txcfg->pstat;
#ifdef WDS
if (txcfg->wdsIdx >= 0) {
if (txcfg->privacy == _TKIP_PRIVACY_)
txcfg->fr_len += 8; // for Michael padding.
txcfg->tx_rate = get_tx_rate(priv, pstat);
txcfg->lowest_tx_rate = get_lowest_tx_rate(priv, pstat, txcfg->tx_rate);
if (priv->pmib->dot11WdsInfo.entry[pstat->wds_idx].txRate)
txcfg->fixed_rate = 1;
if (txcfg->aggre_en == 0) {
if ((pstat->aggre_mthd == AGGRE_MTHD_MPDU) && is_MCS_rate(txcfg->tx_rate))
txcfg->aggre_en = FG_AGGRE_MPDU;
}
return TRUE;
}
#endif
//check if da is associated, if not, just drop and return false
if (!txcfg->is_mcast
#ifdef CLIENT_MODE
|| (OPMODE & WIFI_STATION_STATE)
#endif
#ifdef A4_STA
|| (pstat && (pstat->state & WIFI_A4_STA))
#endif
)
{
protocol = ntohs(*((UINT16 *)((UINT8 *)pskb->data + ETH_ALEN*2)));
if ((protocol == 0x888E)
#ifdef CONFIG_RTL_WAPI_SUPPORT
||(protocol == ETH_P_WAPI)
#endif
|| txcfg->is_dhcp) {
// use basic rate to send EAP packet for sure
txcfg->tx_rate = find_rate(priv, NULL, 0, 1);
txcfg->lowest_tx_rate = txcfg->tx_rate;
txcfg->fixed_rate = 1;
} else {
txcfg->tx_rate = get_tx_rate(priv, pstat);
txcfg->lowest_tx_rate = get_lowest_tx_rate(priv, pstat, txcfg->tx_rate);
if (!is_auto_rate(priv, pstat)&&
!(should_restrict_Nrate(priv, pstat) && is_fixedMCSTxRate(priv, pstat)))
txcfg->fixed_rate = 1;
}
if (txcfg->aggre_en == 0
#ifdef SUPPORT_TX_MCAST2UNI
&& (priv->pshare->rf_ft_var.mc2u_disable || (pskb->cb[2] != (char)0xff))
#endif
) {
if ((pstat->aggre_mthd == AGGRE_MTHD_MPDU) &&
/* is_MCS_rate(txcfg->tx_rate) &&*/ (protocol != 0x888E)
#ifdef CONFIG_RTL_WAPI_SUPPORT
&& (protocol != ETH_P_WAPI)
#endif
&& !txcfg->is_dhcp)
txcfg->aggre_en = FG_AGGRE_MPDU;
}
if (
#ifdef RTK_AC_SUPPORT //FOR_VHT5G_PF
(txcfg->aggre_en && pstat &&
((pstat->aggre_mthd == AGGRE_MTHD_MPDU_AMSDU) || (pstat->aggre_mthd == AGGRE_MTHD_MPDU))) ||
#endif
(txcfg->aggre_en >= FG_AGGRE_MPDU && txcfg->aggre_en <= FG_AGGRE_MPDU_BUFFER_LAST))
{
priority = pskb->cb[1];
if (!pstat->ADDBA_ready[priority]) {
if ((pstat->ADDBA_req_num[priority] < 5) && !pstat->ADDBA_sent[priority]) {
pstat->ADDBA_req_num[priority]++;
issue_ADDBAreq(priv, pstat, priority);
pstat->ADDBA_sent[priority]++;
}
}
}
if (txcfg->is_pspoll && (tx_servq_len(&pstat->tx_queue[BE_QUEUE]) > 0)) {
SetMData(txcfg->phdr);
}
#ifdef WMM_APSD
if (pstat->apsd_trigger) {
if (((pstat->apsd_bitmap & 0x01) && tx_servq_len(&pstat->tx_queue[VO_QUEUE]))
|| ((pstat->apsd_bitmap & 0x02) && tx_servq_len(&pstat->tx_queue[VI_QUEUE]))
|| ((pstat->apsd_bitmap & 0x04) && tx_servq_len(&pstat->tx_queue[BK_QUEUE]))
|| ((pstat->apsd_bitmap & 0x08) && tx_servq_len(&pstat->tx_queue[BE_QUEUE]))) {
SetMData(txcfg->phdr);
} else {
pstat->apsd_trigger = 0;
pstat->apsd_pkt_buffering = 0;
}
}
#endif
} else {
if ((OPMODE & WIFI_AP_STATE) && !list_empty(&priv->sleep_list)
&& (tx_servq_len(&priv->tx_mc_queue) > 0)) {
SetMData(txcfg->phdr);
}
}
}
if (txcfg->privacy == _TKIP_PRIVACY_)
txcfg->fr_len += 8; // for Michael padding.
if (txcfg->aggre_en > 0) {
txcfg->frg_num = 1;
txcfg->frag_thrshld = 2346;
}
return TRUE;
}
int rtl8192cd_firetx(struct rtl8192cd_priv *priv, struct tx_insn* txcfg)
{
unsigned long flags;
int retval;
#ifdef CONFIG_POWER_SAVE
unsigned short fr_type;
#endif
#ifdef DFS
if (!priv->pmib->dot11DFSEntry.disable_DFS &&
GET_ROOT(priv)->pmib->dot11DFSEntry.disable_tx) {
DEBUG_ERR("TX DROP: DFS probation period\n");
return CONGESTED;
}
#endif
#ifdef SDIO_AP_OFFLOAD
if (priv->pshare->offload_function_ctrl)
return CONGESTED;
#ifdef CONFIG_POWER_SAVE
fr_type = GetFrameSubType(txcfg->phdr);
if ((WIFI_PROBEREQ != fr_type) && (WIFI_PROBERSP != fr_type))
rtw_lock_suspend_timeout(priv, 2000);
#endif
#endif
if (update_txinsn_stage1(priv, txcfg) == FALSE) {
return CONGESTED;
}
txcfg->next_txpath = TXPATH_FIRETX;
xmit_preempt_disable(flags);
if (rtw_is_tx_queue_empty(priv, txcfg) == FALSE) {
if (rtw_xmit_enqueue(priv, txcfg) == FALSE) {
xmit_preempt_enable(flags);
return CONGESTED;
}
xmit_preempt_enable(flags);
return SUCCESS;
}
xmit_preempt_enable(flags);
retval = __rtl8192cd_firetx(priv, txcfg);
rtw_handle_xmit_fail(priv, txcfg);
return retval;
}
#ifndef CONFIG_NETDEV_MULTI_TX_QUEUE
void rtl8192cd_tx_restartQueue(struct rtl8192cd_priv *priv)
{
priv = GET_ROOT(priv);
if (IS_DRV_OPEN(priv)) {
netif_wake_queue(priv->dev);
}
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
netif_wake_queue(GET_VXD_PRIV(priv)->dev);
}
#endif
#ifdef MBSSID
if (priv->pmib->miscEntry.vap_enable) {
int bssidIdx;
for (bssidIdx=0; bssidIdx<RTL8192CD_NUM_VWLAN; bssidIdx++) {
if (IS_DRV_OPEN(priv->pvap_priv[bssidIdx])) {
netif_wake_queue(priv->pvap_priv[bssidIdx]->dev);
}
}
}
#endif
#ifdef CONFIG_RTK_MESH
if (priv->pmib->dot1180211sInfo.mesh_enable) {
if (netif_running(priv->mesh_dev)) {
netif_wake_queue(priv->mesh_dev);
}
}
#endif
#ifdef WDS
if (priv->pmib->dot11WdsInfo.wdsEnabled) {
int i;
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
if (netif_running(priv->wds_dev[i])) {
netif_wake_queue(priv->wds_dev[i]);
}
}
}
#endif
}
void rtl8192cd_tx_stopQueue(struct rtl8192cd_priv *priv)
{
priv = GET_ROOT(priv);
++priv->pshare->nr_stop_netif_tx_queue;
if (IS_DRV_OPEN(priv)) {
netif_stop_queue(priv->dev);
}
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
netif_stop_queue(GET_VXD_PRIV(priv)->dev);
}
#endif
#ifdef MBSSID
if (priv->pmib->miscEntry.vap_enable) {
int bssidIdx;
for (bssidIdx=0; bssidIdx<RTL8192CD_NUM_VWLAN; bssidIdx++) {
if (IS_DRV_OPEN(priv->pvap_priv[bssidIdx])) {
netif_stop_queue(priv->pvap_priv[bssidIdx]->dev);
}
}
}
#endif
#ifdef CONFIG_RTK_MESH
if (priv->pmib->dot1180211sInfo.mesh_enable) {
if (netif_running(priv->mesh_dev)) {
netif_stop_queue(priv->mesh_dev);
}
}
#endif
#ifdef WDS
if (priv->pmib->dot11WdsInfo.wdsEnabled) {
int i;
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
if (netif_running(priv->wds_dev[i])) {
netif_stop_queue(priv->wds_dev[i]);
}
}
}
#endif
}
#else // CONFIG_NETDEV_MULTI_TX_QUEUE
void rtl8192cd_tx_restartQueue(struct rtl8192cd_priv *priv, unsigned int index)
{
priv = GET_ROOT(priv);
if (IS_DRV_OPEN(priv)) {
if (unlikely(_NETDEV_TX_QUEUE_ALL == index))
netif_tx_wake_all_queues(priv->dev);
else
netif_tx_wake_queue(netdev_get_tx_queue(priv->dev, index));
}
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
if (unlikely(_NETDEV_TX_QUEUE_ALL == index))
netif_tx_wake_all_queues(GET_VXD_PRIV(priv)->dev);
else
netif_tx_wake_queue(netdev_get_tx_queue(GET_VXD_PRIV(priv)->dev, index));
}
#endif
#ifdef MBSSID
if (priv->pmib->miscEntry.vap_enable) {
int bssidIdx;
for (bssidIdx=0; bssidIdx<RTL8192CD_NUM_VWLAN; bssidIdx++) {
if (IS_DRV_OPEN(priv->pvap_priv[bssidIdx])) {
if (unlikely(_NETDEV_TX_QUEUE_ALL == index))
netif_tx_wake_all_queues(priv->pvap_priv[bssidIdx]->dev);
else
netif_tx_wake_queue(netdev_get_tx_queue(priv->pvap_priv[bssidIdx]->dev, index));
}
}
}
#endif
if ((_NETDEV_TX_QUEUE_ALL != index) && (_NETDEV_TX_QUEUE_BE != index))
return;
#ifdef CONFIG_RTK_MESH
if (priv->pmib->dot1180211sInfo.mesh_enable) {
if (netif_running(priv->mesh_dev)) {
netif_wake_queue(priv->mesh_dev);
}
}
#endif
#ifdef WDS
if (priv->pmib->dot11WdsInfo.wdsEnabled) {
int i;
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
if (netif_running(priv->wds_dev[i])) {
netif_wake_queue(priv->wds_dev[i]);
}
}
}
#endif
}
void rtl8192cd_tx_stopQueue(struct rtl8192cd_priv *priv)
{
priv = GET_ROOT(priv);
++priv->pshare->nr_stop_netif_tx_queue;
if (IS_DRV_OPEN(priv)) {
netif_tx_stop_all_queues(priv->dev);
}
#ifdef UNIVERSAL_REPEATER
if (IS_DRV_OPEN(GET_VXD_PRIV(priv))) {
netif_tx_stop_all_queues(GET_VXD_PRIV(priv)->dev);
}
#endif
#ifdef MBSSID
if (priv->pmib->miscEntry.vap_enable) {
int bssidIdx;
for (bssidIdx=0; bssidIdx<RTL8192CD_NUM_VWLAN; bssidIdx++) {
if (IS_DRV_OPEN(priv->pvap_priv[bssidIdx])) {
netif_tx_stop_all_queues(priv->pvap_priv[bssidIdx]->dev);
}
}
}
#endif
#ifdef CONFIG_RTK_MESH
if (priv->pmib->dot1180211sInfo.mesh_enable) {
if (netif_running(priv->mesh_dev)) {
netif_stop_queue(priv->mesh_dev);
}
}
#endif
#ifdef WDS
if (priv->pmib->dot11WdsInfo.wdsEnabled) {
int i;
for (i=0; i<priv->pmib->dot11WdsInfo.wdsNum; i++) {
if (netif_running(priv->wds_dev[i])) {
netif_stop_queue(priv->wds_dev[i]);
}
}
}
#endif
}
#endif // !CONFIG_NETDEV_MULTI_TX_QUEUE
static int activate_mc_queue_xmit(struct rtl8192cd_priv *priv, u8 force_tx)
{
_irqL irqL;
struct tx_servq *ptxservq;
_queue *xframe_queue, *sta_queue;
int active = 0;
ptxservq = &priv->tx_mc_queue;
xframe_queue = &ptxservq->xframe_queue;
xmit_lock(&xframe_queue->lock, &irqL);
if (_rtw_queue_empty(xframe_queue) == FALSE) {
sta_queue = &priv->pshare->tx_pending_sta_queue[ptxservq->q_num];
_rtw_spinlock(&sta_queue->lock);
if (rtw_is_list_empty(&ptxservq->tx_pending) == TRUE) {
rtw_list_insert_head(&ptxservq->tx_pending, &sta_queue->queue);
++sta_queue->qlen;
active = 1;
}
priv->release_mcast = force_tx;
_rtw_spinunlock(&sta_queue->lock);
}
xmit_unlock(&xframe_queue->lock, &irqL);
return active;
}
void stop_sta_xmit(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int q_num, deactive;
struct tx_servq *ptxservq;
_queue *sta_queue;
_irqL irqL;
#ifdef WMM_APSD
if (pstat->apsd_trigger)
return;
#endif
for (q_num = 0; q_num < MAX_STA_TX_SERV_QUEUE; ++q_num) {
ptxservq = &pstat->tx_queue[q_num];
sta_queue = &priv->pshare->tx_pending_sta_queue[q_num];
deactive = 0;
xmit_lock(&sta_queue->lock, &irqL);
if (rtw_is_list_empty(&ptxservq->tx_pending) == FALSE) {
rtw_list_delete(&ptxservq->tx_pending);
--sta_queue->qlen;
deactive = 1;
}
xmit_unlock(&sta_queue->lock, &irqL);
if (deactive)
need_sched_xmit_for_dequeue(priv, q_num);
}
#ifdef WMM_APSD
if ((QOS_ENABLE) && (APSD_ENABLE) && (pstat->apsd_bitmap & 0x0f)) {
if (((pstat->apsd_bitmap & 0x01) && tx_servq_len(&pstat->tx_queue[VO_QUEUE]))
|| ((pstat->apsd_bitmap & 0x02) && tx_servq_len(&pstat->tx_queue[VI_QUEUE]))
|| ((pstat->apsd_bitmap & 0x04) && tx_servq_len(&pstat->tx_queue[BK_QUEUE]))
|| ((pstat->apsd_bitmap & 0x08) && tx_servq_len(&pstat->tx_queue[BE_QUEUE])))
pstat->apsd_pkt_buffering = 1;
}
#endif
// for BC/MC frames
ptxservq = &priv->tx_mc_queue;
sta_queue = &priv->pshare->tx_pending_sta_queue[ptxservq->q_num];
xmit_lock(&sta_queue->lock, &irqL);
if (rtw_is_list_empty(&ptxservq->tx_pending) == FALSE) {
rtw_list_delete(&ptxservq->tx_pending);
--sta_queue->qlen;
}
ptxservq->q_num = MCAST_QNUM;
xmit_unlock(&sta_queue->lock, &irqL);
if (priv->release_mcast) {
activate_mc_queue_xmit(priv, priv->release_mcast);
}
}
void wakeup_sta_xmit(struct rtl8192cd_priv *priv, struct stat_info *pstat)
{
int q_num, active;
struct tx_servq *ptxservq;
_queue *xframe_queue, *sta_queue;
_irqL irqL;
for (q_num = 0; q_num < MAX_STA_TX_SERV_QUEUE; ++q_num) {
ptxservq = &pstat->tx_queue[q_num];
xframe_queue = &ptxservq->xframe_queue;
xmit_lock(&xframe_queue->lock, &irqL);
if (_rtw_queue_empty(xframe_queue) == FALSE) {
sta_queue = &priv->pshare->tx_pending_sta_queue[q_num];
active = 0;
_rtw_spinlock(&sta_queue->lock);
if (rtw_is_list_empty(&ptxservq->tx_pending) == TRUE) {
rtw_list_insert_head(&ptxservq->tx_pending, &sta_queue->queue);
++sta_queue->qlen;
#ifdef CONFIG_SDIO_HCI
ptxservq->ts_used = 0;
#endif
active = 1;
}
_rtw_spinunlock(&sta_queue->lock);
if (active)
need_sched_xmit_for_enqueue(priv, q_num);
}
xmit_unlock(&xframe_queue->lock, &irqL);
}
#ifdef WMM_APSD
pstat->apsd_pkt_buffering = 0;
pstat->apsd_trigger = 0;
#endif
// for BC/MC frames
if (list_empty(&priv->sleep_list)) {
activate_mc_queue_xmit(priv, 0);
}
#ifdef __ECOS
triggered_wlan_tx_tasklet(priv);
#else
tasklet_hi_schedule(&priv->pshare->xmit_tasklet);
#endif
}
void process_dzqueue(struct rtl8192cd_priv *priv)
{
struct stat_info *pstat;
struct list_head *phead = &priv->wakeup_list;
struct list_head *plist;
unsigned long flags;
while(1)
{
plist = NULL;
SAVE_INT_AND_CLI(flags);
SMP_LOCK_WAKEUP_LIST(flags);
if (!list_empty(phead)) {
plist = phead->next;
list_del_init(plist);
}
SMP_UNLOCK_WAKEUP_LIST(flags);
RESTORE_INT(flags);
if (NULL == plist) break;
pstat = list_entry(plist, struct stat_info, wakeup_list);
DEBUG_INFO("Del fr wakeup_list %02X%02X%02X%02X%02X%02X\n",
pstat->hwaddr[0],pstat->hwaddr[1],pstat->hwaddr[2],pstat->hwaddr[3],pstat->hwaddr[4],pstat->hwaddr[5]);
wakeup_sta_xmit(priv, pstat);
}
}
void process_mcast_dzqueue(struct rtl8192cd_priv *priv)
{
priv->tx_mc_pkt_num = 0;
if (activate_mc_queue_xmit(priv, 1)) {
need_sched_xmit_for_enqueue(priv, priv->tx_mc_queue.q_num);
}
}
#ifdef WMM_APSD
void process_APSD_dz_queue(struct rtl8192cd_priv *priv, struct stat_info *pstat, unsigned short tid)
{
int q_num;
int active, need_sched;
struct tx_servq *ptxservq;
_queue *xframe_queue, *sta_queue;
_irqL irqL;
if ((((tid == 7) || (tid == 6)) && !(pstat->apsd_bitmap & 0x01))
|| (((tid == 5) || (tid == 4)) && !(pstat->apsd_bitmap & 0x02))
|| (((tid == 3) || (tid == 0)) && !(pstat->apsd_bitmap & 0x08))
|| (((tid == 2) || (tid == 1)) && !(pstat->apsd_bitmap & 0x04))) {
DEBUG_INFO("RcvQosNull legacy ps tid=%d", tid);
return;
}
if (pstat->apsd_trigger)
return;
pstat->sleep_time = jiffies;
if (pstat->apsd_pkt_buffering == 0)
goto sendQosNull;
if ((!(pstat->apsd_bitmap & 0x01) || (tx_servq_len(&pstat->tx_queue[VO_QUEUE]) == 0))
&& (!(pstat->apsd_bitmap & 0x02) || (tx_servq_len(&pstat->tx_queue[VI_QUEUE]) == 0))
&& (!(pstat->apsd_bitmap & 0x04) || (tx_servq_len(&pstat->tx_queue[BK_QUEUE]) == 0))
&& (!(pstat->apsd_bitmap & 0x08) || (tx_servq_len(&pstat->tx_queue[BE_QUEUE]) == 0))) {
pstat->apsd_pkt_buffering = 0;
//send QoS Null packet
sendQosNull:
SendQosNullData(priv, pstat->hwaddr);
DEBUG_INFO("sendQosNull tid=%d\n", tid);
return;
}
pstat->apsd_trigger = 1;
need_sched = 0;
for (q_num = VO_QUEUE; q_num >= BK_QUEUE; --q_num) {
if (pstat->apsd_bitmap & wmm_apsd_bitmask[q_num]) {
ptxservq = &pstat->tx_queue[q_num];
xframe_queue = &ptxservq->xframe_queue;
xmit_lock(&xframe_queue->lock, &irqL);
if (_rtw_queue_empty(xframe_queue) == FALSE) {
sta_queue = &priv->pshare->tx_pending_sta_queue[q_num];
active = 0;
_rtw_spinlock(&sta_queue->lock);
if (rtw_is_list_empty(&ptxservq->tx_pending) == TRUE) {
rtw_list_insert_head(&ptxservq->tx_pending, &sta_queue->queue);
++sta_queue->qlen;
#ifdef CONFIG_SDIO_HCI
ptxservq->ts_used = 0;
#endif
active = 1;
need_sched = 1;
}
_rtw_spinunlock(&sta_queue->lock);
if (active)
need_sched_xmit_for_enqueue(priv, q_num);
}
xmit_unlock(&xframe_queue->lock, &irqL);
}
}
if (need_sched) {
if (pstat->txpause_flag) {
#ifdef CONFIG_WLAN_HAL
if (IS_HAL_CHIP(priv)) {
GET_HAL_INTERFACE(priv)->SetMACIDSleepHandler(priv, 0, REMAP_AID(pstat));
} else
#endif
#ifdef CONFIG_RTL_8812_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8812E) {
RTL8812_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
} else
#endif
#ifdef CONFIG_RTL_88E_SUPPORT
if (GET_CHIP_VER(priv) == VERSION_8188E) {
RTL8188E_MACID_PAUSE(priv, 0, REMAP_AID(pstat));
} else
#endif
{
#if defined(CONFIG_RTL_92D_SUPPORT) || defined(CONFIG_RTL_92C_SUPPORT)
add_update_ps(priv, pstat);
#endif
}
pstat->txpause_flag = 0;
}
}
}
#endif // WMM_APSD