htc_drv_txrx.c revision 0995d110118b35c0dc5195e3ddddcc0dec263830
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 2fb9987d0f748c983bb795a86f47522313f701a08Sujith * Copyright (c) 2010 Atheros Communications Inc. 3fb9987d0f748c983bb795a86f47522313f701a08Sujith * 4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any 5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above 6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies. 7fb9987d0f748c983bb795a86f47522313f701a08Sujith * 8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 16fb9987d0f748c983bb795a86f47522313f701a08Sujith 17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h" 18fb9987d0f748c983bb795a86f47522313f701a08Sujith 19fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 20fb9987d0f748c983bb795a86f47522313f701a08Sujith/* TX */ 21fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 22fb9987d0f748c983bb795a86f47522313f701a08Sujith 23fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map) 24fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 25fb9987d0f748c983bb795a86f47522313f701a08Sujith switch (queue) { 26fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 27fb9987d0f748c983bb795a86f47522313f701a08Sujith return hwq_map[ATH9K_WME_AC_VO]; 28fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 29fb9987d0f748c983bb795a86f47522313f701a08Sujith return hwq_map[ATH9K_WME_AC_VI]; 30fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 31fb9987d0f748c983bb795a86f47522313f701a08Sujith return hwq_map[ATH9K_WME_AC_BE]; 32fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 33fb9987d0f748c983bb795a86f47522313f701a08Sujith return hwq_map[ATH9K_WME_AC_BK]; 34fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 35fb9987d0f748c983bb795a86f47522313f701a08Sujith return hwq_map[ATH9K_WME_AC_BE]; 36fb9987d0f748c983bb795a86f47522313f701a08Sujith } 37fb9987d0f748c983bb795a86f47522313f701a08Sujith} 38fb9987d0f748c983bb795a86f47522313f701a08Sujith 39e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 40e1572c5eeca8ef87a250322364584458b2dadb35Sujith struct ath9k_tx_queue_info *qinfo) 41fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 42fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 43fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 44fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 45fb9987d0f748c983bb795a86f47522313f701a08Sujith 46fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_get_txq_props(ah, qnum, &qi); 47fb9987d0f748c983bb795a86f47522313f701a08Sujith 48fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = qinfo->tqi_aifs; 49fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ 50fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = qinfo->tqi_cwmax; 51fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_burstTime = qinfo->tqi_burstTime; 52fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_readyTime = qinfo->tqi_readyTime; 53fb9987d0f748c983bb795a86f47522313f701a08Sujith 54fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 55fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, 56fb9987d0f748c983bb795a86f47522313f701a08Sujith "Unable to update hardware queue %u!\n", qnum); 57fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -EIO; 58fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 59fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_resettxqueue(ah, qnum); 60fb9987d0f748c983bb795a86f47522313f701a08Sujith } 61fb9987d0f748c983bb795a86f47522313f701a08Sujith 62fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 63fb9987d0f748c983bb795a86f47522313f701a08Sujith} 64fb9987d0f748c983bb795a86f47522313f701a08Sujith 65fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) 66fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 67fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 68fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 69fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta = tx_info->control.sta; 70fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 71fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_vif *avp; 72fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_tx_ctl tx_ctl; 73fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id epid; 74fb9987d0f748c983bb795a86f47522313f701a08Sujith u16 qnum, hw_qnum; 75fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 76fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *tx_fhdr; 77fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 sta_idx; 78fb9987d0f748c983bb795a86f47522313f701a08Sujith 79fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 80fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 81fb9987d0f748c983bb795a86f47522313f701a08Sujith 82fb9987d0f748c983bb795a86f47522313f701a08Sujith avp = (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv; 83fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta) { 84fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 85fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = ista->index; 86fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 87fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = 0; 88fb9987d0f748c983bb795a86f47522313f701a08Sujith } 89fb9987d0f748c983bb795a86f47522313f701a08Sujith 90fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); 91fb9987d0f748c983bb795a86f47522313f701a08Sujith 92fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 93fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_frame_hdr tx_hdr; 94fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc; 95fb9987d0f748c983bb795a86f47522313f701a08Sujith 96fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); 97fb9987d0f748c983bb795a86f47522313f701a08Sujith 98fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.node_idx = sta_idx; 99fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.vif_idx = avp->index; 100fb9987d0f748c983bb795a86f47522313f701a08Sujith 101fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 102fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_AMPDU; 103fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_AMPDU; 104fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 105fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 106fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_NORMAL; 107fb9987d0f748c983bb795a86f47522313f701a08Sujith } 108fb9987d0f748c983bb795a86f47522313f701a08Sujith 109fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 110fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 111fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 112fb9987d0f748c983bb795a86f47522313f701a08Sujith } 113fb9987d0f748c983bb795a86f47522313f701a08Sujith 114fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Check for RTS protection */ 115fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->hw->wiphy->rts_threshold != (u32) -1) 116fb9987d0f748c983bb795a86f47522313f701a08Sujith if (skb->len > priv->hw->wiphy->rts_threshold) 117fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS; 118fb9987d0f748c983bb795a86f47522313f701a08Sujith 119fb9987d0f748c983bb795a86f47522313f701a08Sujith /* CTS-to-self */ 120fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) && 121fb9987d0f748c983bb795a86f47522313f701a08Sujith (priv->op_flags & OP_PROTECT_ENABLE)) 122fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY; 123fb9987d0f748c983bb795a86f47522313f701a08Sujith 124fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 125fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 126fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 127fb9987d0f748c983bb795a86f47522313f701a08Sujith else 128fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 129fb9987d0f748c983bb795a86f47522313f701a08Sujith 130fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(tx_hdr)); 131fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); 132fb9987d0f748c983bb795a86f47522313f701a08Sujith 133fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = skb_get_queue_mapping(skb); 134fb9987d0f748c983bb795a86f47522313f701a08Sujith hw_qnum = get_hw_qnum(qnum, priv->hwq_map); 135fb9987d0f748c983bb795a86f47522313f701a08Sujith 136fb9987d0f748c983bb795a86f47522313f701a08Sujith switch (hw_qnum) { 137fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 138fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_be_ep; 139fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 140fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 141fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_vi_ep; 142fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 143fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 144fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_vo_ep; 145fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 146fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 147fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 148fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_bk_ep; 149fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 150fb9987d0f748c983bb795a86f47522313f701a08Sujith } 151fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 152fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_mgmt_hdr mgmt_hdr; 153fb9987d0f748c983bb795a86f47522313f701a08Sujith 154fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); 155fb9987d0f748c983bb795a86f47522313f701a08Sujith 156fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 157fb9987d0f748c983bb795a86f47522313f701a08Sujith 158fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.node_idx = sta_idx; 159fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.vif_idx = avp->index; 160fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.tidno = 0; 161fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.flags = 0; 162fb9987d0f748c983bb795a86f47522313f701a08Sujith 163fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 164fb9987d0f748c983bb795a86f47522313f701a08Sujith if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 165fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 166fb9987d0f748c983bb795a86f47522313f701a08Sujith else 167fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 168fb9987d0f748c983bb795a86f47522313f701a08Sujith 169fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); 170fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); 171fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->mgmt_ep; 172fb9987d0f748c983bb795a86f47522313f701a08Sujith } 173fb9987d0f748c983bb795a86f47522313f701a08Sujith 174fb9987d0f748c983bb795a86f47522313f701a08Sujith return htc_send(priv->htc, skb, epid, &tx_ctl); 175fb9987d0f748c983bb795a86f47522313f701a08Sujith} 176fb9987d0f748c983bb795a86f47522313f701a08Sujith 177fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_tasklet(unsigned long data) 178fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 179fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 180fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta; 181fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 182fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 183fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = NULL; 184fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 185fb9987d0f748c983bb795a86f47522313f701a08Sujith 186fb9987d0f748c983bb795a86f47522313f701a08Sujith while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { 187fb9987d0f748c983bb795a86f47522313f701a08Sujith 188fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 189fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 190fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 191fb9987d0f748c983bb795a86f47522313f701a08Sujith sta = tx_info->control.sta; 192fb9987d0f748c983bb795a86f47522313f701a08Sujith 193fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_lock(); 194fb9987d0f748c983bb795a86f47522313f701a08Sujith 195fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta && conf_is_ht(&priv->hw->conf) && 196fb9987d0f748c983bb795a86f47522313f701a08Sujith (priv->op_flags & OP_TXAGGR) 197fb9987d0f748c983bb795a86f47522313f701a08Sujith && !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 198fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data_qos(fc)) { 199fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc, tid; 200fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 201fb9987d0f748c983bb795a86f47522313f701a08Sujith 202fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 203fb9987d0f748c983bb795a86f47522313f701a08Sujith tid = qc[0] & 0xf; 204fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *)sta->drv_priv; 205fb9987d0f748c983bb795a86f47522313f701a08Sujith 206fb9987d0f748c983bb795a86f47522313f701a08Sujith if ((tid < ATH9K_HTC_MAX_TID) && 207fb9987d0f748c983bb795a86f47522313f701a08Sujith ista->tid_state[tid] == AGGR_STOP) { 208fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_start_tx_ba_session(sta, tid); 209fb9987d0f748c983bb795a86f47522313f701a08Sujith ista->tid_state[tid] = AGGR_PROGRESS; 210fb9987d0f748c983bb795a86f47522313f701a08Sujith } 211fb9987d0f748c983bb795a86f47522313f701a08Sujith } 212fb9987d0f748c983bb795a86f47522313f701a08Sujith } 213fb9987d0f748c983bb795a86f47522313f701a08Sujith 214fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_unlock(); 215fb9987d0f748c983bb795a86f47522313f701a08Sujith 216fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_info->status, 0, sizeof(tx_info->status)); 217fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_tx_status(priv->hw, skb); 218fb9987d0f748c983bb795a86f47522313f701a08Sujith } 219fb9987d0f748c983bb795a86f47522313f701a08Sujith} 220fb9987d0f748c983bb795a86f47522313f701a08Sujith 221fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 222fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id, bool txok) 223fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 224fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; 225fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 226fb9987d0f748c983bb795a86f47522313f701a08Sujith 227fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!skb) 228fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 229fb9987d0f748c983bb795a86f47522313f701a08Sujith 230fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ep_id == priv->mgmt_ep) 231fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_mgmt_hdr)); 232fb9987d0f748c983bb795a86f47522313f701a08Sujith else 233fb9987d0f748c983bb795a86f47522313f701a08Sujith /* TODO: Check for cab/uapsd/data */ 234fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_frame_hdr)); 235fb9987d0f748c983bb795a86f47522313f701a08Sujith 236fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 237fb9987d0f748c983bb795a86f47522313f701a08Sujith 238fb9987d0f748c983bb795a86f47522313f701a08Sujith if (txok) 239fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info->flags |= IEEE80211_TX_STAT_ACK; 240fb9987d0f748c983bb795a86f47522313f701a08Sujith 241fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_tail(&priv->tx_queue, skb); 242fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->tx_tasklet); 243fb9987d0f748c983bb795a86f47522313f701a08Sujith} 244fb9987d0f748c983bb795a86f47522313f701a08Sujith 245fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv) 246fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 247fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_head_init(&priv->tx_queue); 248fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 249fb9987d0f748c983bb795a86f47522313f701a08Sujith} 250fb9987d0f748c983bb795a86f47522313f701a08Sujith 251fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv) 252fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 253fb9987d0f748c983bb795a86f47522313f701a08Sujith 254fb9987d0f748c983bb795a86f47522313f701a08Sujith} 255fb9987d0f748c983bb795a86f47522313f701a08Sujith 256fb9987d0f748c983bb795a86f47522313f701a08Sujithbool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, 257fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ath9k_tx_queue_subtype subtype) 258fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 259fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 260fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 261fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 262fb9987d0f748c983bb795a86f47522313f701a08Sujith int qnum; 263fb9987d0f748c983bb795a86f47522313f701a08Sujith 264fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&qi, 0, sizeof(qi)); 265fb9987d0f748c983bb795a86f47522313f701a08Sujith 266fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_subtype = subtype; 267fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; 268fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; 269fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; 270fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_physCompBuf = 0; 271fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | TXQ_FLAG_TXDESCINT_ENABLE; 272fb9987d0f748c983bb795a86f47522313f701a08Sujith 273fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); 274fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum == -1) 275fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 276fb9987d0f748c983bb795a86f47522313f701a08Sujith 277fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum >= ARRAY_SIZE(priv->hwq_map)) { 278fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 279fb9987d0f748c983bb795a86f47522313f701a08Sujith "qnum %u out of range, max %u!\n", 280fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); 281fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_releasetxqueue(ah, qnum); 282fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 283fb9987d0f748c983bb795a86f47522313f701a08Sujith } 284fb9987d0f748c983bb795a86f47522313f701a08Sujith 285fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[subtype] = qnum; 286fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 287fb9987d0f748c983bb795a86f47522313f701a08Sujith} 288fb9987d0f748c983bb795a86f47522313f701a08Sujith 289fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 290fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */ 291fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 292fb9987d0f748c983bb795a86f47522313f701a08Sujith 2930995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 2940995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW. 2950995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 2960995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) 2970995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 2980995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) 2990995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3000995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 3010995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt; 3020995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3030995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) 3040995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST 3050995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_MCAST; 3060995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3070995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* If not a STA, enable processing of Probe Requests */ 3080995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (ah->opmode != NL80211_IFTYPE_STATION) 3090995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROBEREQ; 3100995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3110995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* 3120995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station 3130995d110118b35c0dc5195e3ddddcc0dec263830Sujith * mode interface or when in monitor mode. AP mode does not need this 3140995d110118b35c0dc5195e3ddddcc0dec263830Sujith * since it receives all in-BSS frames anyway. 3150995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 3160995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (((ah->opmode != NL80211_IFTYPE_AP) && 3170995d110118b35c0dc5195e3ddddcc0dec263830Sujith (priv->rxfilter & FIF_PROMISC_IN_BSS)) || 3180995d110118b35c0dc5195e3ddddcc0dec263830Sujith (ah->opmode == NL80211_IFTYPE_MONITOR)) 3190995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROM; 3200995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3210995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (priv->rxfilter & FIF_CONTROL) 3220995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_CONTROL; 3230995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3240995d110118b35c0dc5195e3ddddcc0dec263830Sujith if ((ah->opmode == NL80211_IFTYPE_STATION) && 3250995d110118b35c0dc5195e3ddddcc0dec263830Sujith !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) 3260995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_MYBEACON; 3270995d110118b35c0dc5195e3ddddcc0dec263830Sujith else 3280995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_BEACON; 3290995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3300995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (conf_is_ht(&priv->hw->conf)) 3310995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_COMP_BAR; 3320995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3330995d110118b35c0dc5195e3ddddcc0dec263830Sujith return rfilt; 3340995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3350995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE 3360995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 3370995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3380995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 3390995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change. 3400995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 3410995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) 3420995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 3430995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 3440995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_common *common = ath9k_hw_common(ah); 3450995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3460995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt, mfilt[2]; 3470995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3480995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure rx filter */ 3490995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = ath9k_htc_calcrxfilter(priv); 3500995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setrxfilter(ah, rfilt); 3510995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3520995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure bssid mask */ 3530995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) 3540995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath_hw_setbssidmask(common); 3550995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3560995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure operational mode */ 3570995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setopmode(ah); 3580995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3590995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* Handle any link-level address change. */ 3600995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmac(ah, common->macaddr); 3610995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3620995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* calculate and install multicast filter */ 3630995d110118b35c0dc5195e3ddddcc0dec263830Sujith mfilt[0] = mfilt[1] = ~0; 3640995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 3650995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 3660995d110118b35c0dc5195e3ddddcc0dec263830Sujith 367fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv) 368fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 369fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_rxena(priv->ah); 3700995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_htc_opmode_init(priv); 371fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_startpcureceive(priv->ah); 372fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; 373fb9987d0f748c983bb795a86f47522313f701a08Sujith} 374fb9987d0f748c983bb795a86f47522313f701a08Sujith 375fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw, 376fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rxs, 377fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 rx_rate, u8 rs_flags) 378fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 379fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_supported_band *sband; 380fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ieee80211_band band; 381fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned int i = 0; 382fb9987d0f748c983bb795a86f47522313f701a08Sujith 383fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rx_rate & 0x80) { 384fb9987d0f748c983bb795a86f47522313f701a08Sujith /* HT rate */ 385fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_HT; 386fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_2040) 387fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_40MHZ; 388fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_GI) 389fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORT_GI; 390fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = rx_rate & 0x7f; 391fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 392fb9987d0f748c983bb795a86f47522313f701a08Sujith } 393fb9987d0f748c983bb795a86f47522313f701a08Sujith 394fb9987d0f748c983bb795a86f47522313f701a08Sujith band = hw->conf.channel->band; 395fb9987d0f748c983bb795a86f47522313f701a08Sujith sband = hw->wiphy->bands[band]; 396fb9987d0f748c983bb795a86f47522313f701a08Sujith 397fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < sband->n_bitrates; i++) { 398fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value == rx_rate) { 399fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 400fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 401fb9987d0f748c983bb795a86f47522313f701a08Sujith } 402fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value_short == rx_rate) { 403fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 404fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORTPRE; 405fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 406fb9987d0f748c983bb795a86f47522313f701a08Sujith } 407fb9987d0f748c983bb795a86f47522313f701a08Sujith } 408fb9987d0f748c983bb795a86f47522313f701a08Sujith 409fb9987d0f748c983bb795a86f47522313f701a08Sujith} 410fb9987d0f748c983bb795a86f47522313f701a08Sujith 411fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, 412fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, 413fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rx_status) 414fb9987d0f748c983bb795a86f47522313f701a08Sujith 415fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 416fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 417fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 418fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = rxbuf->skb; 419fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 420fb9987d0f748c983bb795a86f47522313f701a08Sujith int hdrlen, padpos, padsize; 421fb9987d0f748c983bb795a86f47522313f701a08Sujith int last_rssi = ATH_RSSI_DUMMY_MARKER; 422fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 423fb9987d0f748c983bb795a86f47522313f701a08Sujith 424fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *)skb->data; 425fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 426fb9987d0f748c983bb795a86f47522313f701a08Sujith hdrlen = ieee80211_get_hdrlen_from_skb(skb); 427fb9987d0f748c983bb795a86f47522313f701a08Sujith 428fb9987d0f748c983bb795a86f47522313f701a08Sujith padpos = ath9k_cmn_padpos(fc); 429fb9987d0f748c983bb795a86f47522313f701a08Sujith 430fb9987d0f748c983bb795a86f47522313f701a08Sujith padsize = padpos & 3; 431fb9987d0f748c983bb795a86f47522313f701a08Sujith if (padsize && skb->len >= padpos+padsize) { 432fb9987d0f748c983bb795a86f47522313f701a08Sujith memmove(skb->data + padsize, skb->data, padpos); 433fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, padsize); 434fb9987d0f748c983bb795a86f47522313f701a08Sujith } 435fb9987d0f748c983bb795a86f47522313f701a08Sujith 436fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); 437fb9987d0f748c983bb795a86f47522313f701a08Sujith 438fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status != 0) { 439fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) 440fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 441fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) 442fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 443fb9987d0f748c983bb795a86f47522313f701a08Sujith 444fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { 445fb9987d0f748c983bb795a86f47522313f701a08Sujith /* FIXME */ 446fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { 447fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_ctl(fc)) 448fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 449fb9987d0f748c983bb795a86f47522313f701a08Sujith * Sometimes, we get invalid 450fb9987d0f748c983bb795a86f47522313f701a08Sujith * MIC failures on valid control frames. 451fb9987d0f748c983bb795a86f47522313f701a08Sujith * Remove these mic errors. 452fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 453fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; 454fb9987d0f748c983bb795a86f47522313f701a08Sujith else 455fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_MMIC_ERROR; 456fb9987d0f748c983bb795a86f47522313f701a08Sujith } 457fb9987d0f748c983bb795a86f47522313f701a08Sujith 458fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 459fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reject error frames with the exception of 460fb9987d0f748c983bb795a86f47522313f701a08Sujith * decryption and MIC failures. For monitor mode, 461fb9987d0f748c983bb795a86f47522313f701a08Sujith * we also ignore the CRC error. 462fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 463fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { 464fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 465fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 466fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH9K_RXERR_CRC)) 467fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 468fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 469fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 470fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 471fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 472fb9987d0f748c983bb795a86f47522313f701a08Sujith } 473fb9987d0f748c983bb795a86f47522313f701a08Sujith } 474fb9987d0f748c983bb795a86f47522313f701a08Sujith } 475fb9987d0f748c983bb795a86f47522313f701a08Sujith 476fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { 477fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 keyix; 478fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = rxbuf->rxstatus.rs_keyix; 479fb9987d0f748c983bb795a86f47522313f701a08Sujith if (keyix != ATH9K_RXKEYIX_INVALID) { 480fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 481fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (ieee80211_has_protected(fc) && 482fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len >= hdrlen + 4) { 483fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = skb->data[hdrlen + 3] >> 6; 484fb9987d0f748c983bb795a86f47522313f701a08Sujith if (test_bit(keyix, common->keymap)) 485fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 486fb9987d0f748c983bb795a86f47522313f701a08Sujith } 487fb9987d0f748c983bb795a86f47522313f701a08Sujith } 488fb9987d0f748c983bb795a86f47522313f701a08Sujith 489fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, 490fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_flags); 491fb9987d0f748c983bb795a86f47522313f701a08Sujith 492fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->op_flags & OP_ASSOCIATED) { 493fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && 494fb9987d0f748c983bb795a86f47522313f701a08Sujith !rxbuf->rxstatus.rs_moreaggr) 495fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH_RSSI_LPF(priv->rx.last_rssi, 496fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi); 497fb9987d0f748c983bb795a86f47522313f701a08Sujith 498fb9987d0f748c983bb795a86f47522313f701a08Sujith last_rssi = priv->rx.last_rssi; 499fb9987d0f748c983bb795a86f47522313f701a08Sujith 500fb9987d0f748c983bb795a86f47522313f701a08Sujith if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 501fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, 502fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH_RSSI_EP_MULTIPLIER); 503fb9987d0f748c983bb795a86f47522313f701a08Sujith 504fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_rssi < 0) 505fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi = 0; 506fb9987d0f748c983bb795a86f47522313f701a08Sujith 507fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_beacon(fc)) 508fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; 509fb9987d0f748c983bb795a86f47522313f701a08Sujith } 510fb9987d0f748c983bb795a86f47522313f701a08Sujith 511fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->mactime = rxbuf->rxstatus.rs_tstamp; 512fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->band = hw->conf.channel->band; 513fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->freq = hw->conf.channel->center_freq; 514fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 515fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->antenna = rxbuf->rxstatus.rs_antenna; 516fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_TSFT; 517fb9987d0f748c983bb795a86f47522313f701a08Sujith 518fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 519fb9987d0f748c983bb795a86f47522313f701a08Sujith 520fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next: 521fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 522fb9987d0f748c983bb795a86f47522313f701a08Sujith} 523fb9987d0f748c983bb795a86f47522313f701a08Sujith 524fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 525fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on. 526fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 527fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data) 528fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 529fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 530fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 531fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status rx_status; 532fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb; 533fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned long flags; 534fb9987d0f748c983bb795a86f47522313f701a08Sujith 535fb9987d0f748c983bb795a86f47522313f701a08Sujith 536fb9987d0f748c983bb795a86f47522313f701a08Sujith do { 537fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 538fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 539fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tmp_buf->in_process) { 540fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 541fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 542fb9987d0f748c983bb795a86f47522313f701a08Sujith } 543fb9987d0f748c983bb795a86f47522313f701a08Sujith } 544fb9987d0f748c983bb795a86f47522313f701a08Sujith 545fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 546fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 547fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 548fb9987d0f748c983bb795a86f47522313f701a08Sujith } 549fb9987d0f748c983bb795a86f47522313f701a08Sujith 550fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!rxbuf->skb) 551fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 552fb9987d0f748c983bb795a86f47522313f701a08Sujith 553fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { 554fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 555fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 556fb9987d0f748c983bb795a86f47522313f701a08Sujith } 557fb9987d0f748c983bb795a86f47522313f701a08Sujith 558fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, 559fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct ieee80211_rx_status)); 560fb9987d0f748c983bb795a86f47522313f701a08Sujith skb = rxbuf->skb; 561fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 562fb9987d0f748c983bb795a86f47522313f701a08Sujith 563fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_rx(priv->hw, skb); 564fb9987d0f748c983bb795a86f47522313f701a08Sujith 565fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 566fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue: 567fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = false; 568fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = NULL; 569fb9987d0f748c983bb795a86f47522313f701a08Sujith list_move_tail(&rxbuf->list, &priv->rx.rxbuf); 570fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = NULL; 571fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 572fb9987d0f748c983bb795a86f47522313f701a08Sujith } while (1); 573fb9987d0f748c983bb795a86f47522313f701a08Sujith 574fb9987d0f748c983bb795a86f47522313f701a08Sujith} 575fb9987d0f748c983bb795a86f47522313f701a08Sujith 576fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 577fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id) 578fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 579fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; 580fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 581fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 582fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 583fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_htc_rx_status *rxstatus; 584fb9987d0f748c983bb795a86f47522313f701a08Sujith u32 len = 0; 585fb9987d0f748c983bb795a86f47522313f701a08Sujith 586fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 587fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 588fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!tmp_buf->in_process) { 589fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 590fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 591fb9987d0f748c983bb795a86f47522313f701a08Sujith } 592fb9987d0f748c983bb795a86f47522313f701a08Sujith } 593fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 594fb9987d0f748c983bb795a86f47522313f701a08Sujith 595fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 596fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_ANY, 597fb9987d0f748c983bb795a86f47522313f701a08Sujith "No free RX buffer\n"); 598fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 599fb9987d0f748c983bb795a86f47522313f701a08Sujith } 600fb9987d0f748c983bb795a86f47522313f701a08Sujith 601fb9987d0f748c983bb795a86f47522313f701a08Sujith len = skb->len; 602fb9987d0f748c983bb795a86f47522313f701a08Sujith if (len <= HTC_RX_FRAME_HEADER_SIZE) { 603fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 604fb9987d0f748c983bb795a86f47522313f701a08Sujith "Corrupted RX frame, dropping\n"); 605fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 606fb9987d0f748c983bb795a86f47522313f701a08Sujith } 607fb9987d0f748c983bb795a86f47522313f701a08Sujith 608fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus = (struct ath_htc_rx_status *)skb->data; 609fb9987d0f748c983bb795a86f47522313f701a08Sujith 610fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus->rs_tstamp = be64_to_cpu(rxstatus->rs_tstamp); 611fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus->rs_datalen = be16_to_cpu(rxstatus->rs_datalen); 612fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus->evm0 = be32_to_cpu(rxstatus->evm0); 613fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus->evm1 = be32_to_cpu(rxstatus->evm1); 614fb9987d0f748c983bb795a86f47522313f701a08Sujith rxstatus->evm2 = be32_to_cpu(rxstatus->evm2); 615fb9987d0f748c983bb795a86f47522313f701a08Sujith 616fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxstatus->rs_datalen - (len - HTC_RX_FRAME_HEADER_SIZE) != 0) { 617fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 618fb9987d0f748c983bb795a86f47522313f701a08Sujith "Corrupted RX data len, dropping " 619fb9987d0f748c983bb795a86f47522313f701a08Sujith "(epid: %d, dlen: %d, skblen: %d)\n", 620fb9987d0f748c983bb795a86f47522313f701a08Sujith ep_id, rxstatus->rs_datalen, len); 621fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 622fb9987d0f748c983bb795a86f47522313f701a08Sujith } 623fb9987d0f748c983bb795a86f47522313f701a08Sujith 624fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 625fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); 626fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); 627fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len = rxstatus->rs_datalen; 628fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = skb; 629fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = true; 630fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 631fb9987d0f748c983bb795a86f47522313f701a08Sujith 632fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->rx_tasklet); 633fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 634fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 635fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(skb); 636fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 637fb9987d0f748c983bb795a86f47522313f701a08Sujith} 638fb9987d0f748c983bb795a86f47522313f701a08Sujith 639fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */ 640fb9987d0f748c983bb795a86f47522313f701a08Sujith 641fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv) 642fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 643fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, *tbuf; 644fb9987d0f748c983bb795a86f47522313f701a08Sujith 645fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { 646fb9987d0f748c983bb795a86f47522313f701a08Sujith list_del(&rxbuf->list); 647fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->skb) 648fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 649fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(rxbuf); 650fb9987d0f748c983bb795a86f47522313f701a08Sujith } 651fb9987d0f748c983bb795a86f47522313f701a08Sujith} 652fb9987d0f748c983bb795a86f47522313f701a08Sujith 653fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv) 654fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 655fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 656fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 657fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf; 658fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 659fb9987d0f748c983bb795a86f47522313f701a08Sujith 660fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_LIST_HEAD(&priv->rx.rxbuf); 661fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->rx.rxbuflock); 662fb9987d0f748c983bb795a86f47522313f701a08Sujith 663fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ATH9K_HTC_RXBUF; i++) { 664fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); 665fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 666fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 667fb9987d0f748c983bb795a86f47522313f701a08Sujith "Unable to allocate RX buffers\n"); 668fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 669fb9987d0f748c983bb795a86f47522313f701a08Sujith } 670fb9987d0f748c983bb795a86f47522313f701a08Sujith list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 671fb9987d0f748c983bb795a86f47522313f701a08Sujith } 672fb9987d0f748c983bb795a86f47522313f701a08Sujith 673fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 674fb9987d0f748c983bb795a86f47522313f701a08Sujith 675fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 676fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 677fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 678fb9987d0f748c983bb795a86f47522313f701a08Sujith} 679