htc_drv_txrx.c revision 94a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4
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 23ca74b83b66dbd289a395c6243695d746c76676ccSujith#define ATH9K_HTC_INIT_TXQ(subtype) do { \ 24ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_subtype = subtype; \ 25ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \ 26ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \ 27ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \ 28ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_physCompBuf = 0; \ 29ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \ 30ca74b83b66dbd289a395c6243695d746c76676ccSujith TXQ_FLAG_TXDESCINT_ENABLE; \ 31ca74b83b66dbd289a395c6243695d746c76676ccSujith } while (0) 32ca74b83b66dbd289a395c6243695d746c76676ccSujith 33fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map) 34fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 35fb9987d0f748c983bb795a86f47522313f701a08Sujith switch (queue) { 36fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 37e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VO]; 38fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 39e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VI]; 40fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 41e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 42fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 43e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BK]; 44fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 45e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 46fb9987d0f748c983bb795a86f47522313f701a08Sujith } 47fb9987d0f748c983bb795a86f47522313f701a08Sujith} 48fb9987d0f748c983bb795a86f47522313f701a08Sujith 49e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 50e1572c5eeca8ef87a250322364584458b2dadb35Sujith struct ath9k_tx_queue_info *qinfo) 51fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 52fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 53fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 54fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 55fb9987d0f748c983bb795a86f47522313f701a08Sujith 56fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_get_txq_props(ah, qnum, &qi); 57fb9987d0f748c983bb795a86f47522313f701a08Sujith 58fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = qinfo->tqi_aifs; 59fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ 60fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = qinfo->tqi_cwmax; 61fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_burstTime = qinfo->tqi_burstTime; 62fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_readyTime = qinfo->tqi_readyTime; 63fb9987d0f748c983bb795a86f47522313f701a08Sujith 64fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 65fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(ath9k_hw_common(ah), ATH_DBG_FATAL, 66fb9987d0f748c983bb795a86f47522313f701a08Sujith "Unable to update hardware queue %u!\n", qnum); 67fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -EIO; 68fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 69fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_resettxqueue(ah, qnum); 70fb9987d0f748c983bb795a86f47522313f701a08Sujith } 71fb9987d0f748c983bb795a86f47522313f701a08Sujith 72fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 73fb9987d0f748c983bb795a86f47522313f701a08Sujith} 74fb9987d0f748c983bb795a86f47522313f701a08Sujith 75fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, struct sk_buff *skb) 76fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 77fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 78fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 79fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta = tx_info->control.sta; 80fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 81fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_tx_ctl tx_ctl; 82fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id epid; 83b80841c91f42dc048a60bff5e1614a619f725e38Sujith u16 qnum; 84fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 85fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *tx_fhdr; 86da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan u8 sta_idx, vif_idx; 87fb9987d0f748c983bb795a86f47522313f701a08Sujith 88fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 89fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 90fb9987d0f748c983bb795a86f47522313f701a08Sujith 91da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan if (tx_info->control.vif && 92da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan (struct ath9k_htc_vif *) tx_info->control.vif->drv_priv) 93da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan vif_idx = ((struct ath9k_htc_vif *) 94da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan tx_info->control.vif->drv_priv)->index; 95da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan else 96da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan vif_idx = priv->nvifs; 97da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan 98fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta) { 99fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 100fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = ista->index; 101fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 102fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = 0; 103fb9987d0f748c983bb795a86f47522313f701a08Sujith } 104fb9987d0f748c983bb795a86f47522313f701a08Sujith 105fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); 106fb9987d0f748c983bb795a86f47522313f701a08Sujith 107fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 108fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_frame_hdr tx_hdr; 109fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc; 110fb9987d0f748c983bb795a86f47522313f701a08Sujith 111fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); 112fb9987d0f748c983bb795a86f47522313f701a08Sujith 113fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.node_idx = sta_idx; 114da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan tx_hdr.vif_idx = vif_idx; 115fb9987d0f748c983bb795a86f47522313f701a08Sujith 116fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 117fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_AMPDU; 118fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_AMPDU; 119fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 120fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 121fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_NORMAL; 122fb9987d0f748c983bb795a86f47522313f701a08Sujith } 123fb9987d0f748c983bb795a86f47522313f701a08Sujith 124fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 125fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 126fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 127fb9987d0f748c983bb795a86f47522313f701a08Sujith } 128fb9987d0f748c983bb795a86f47522313f701a08Sujith 129fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Check for RTS protection */ 130fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->hw->wiphy->rts_threshold != (u32) -1) 131fb9987d0f748c983bb795a86f47522313f701a08Sujith if (skb->len > priv->hw->wiphy->rts_threshold) 132fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.flags |= ATH9K_HTC_TX_RTSCTS; 133fb9987d0f748c983bb795a86f47522313f701a08Sujith 134fb9987d0f748c983bb795a86f47522313f701a08Sujith /* CTS-to-self */ 135fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(tx_hdr.flags & ATH9K_HTC_TX_RTSCTS) && 136fb9987d0f748c983bb795a86f47522313f701a08Sujith (priv->op_flags & OP_PROTECT_ENABLE)) 137fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.flags |= ATH9K_HTC_TX_CTSONLY; 138fb9987d0f748c983bb795a86f47522313f701a08Sujith 139fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 140fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 141fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 142fb9987d0f748c983bb795a86f47522313f701a08Sujith else 143fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 144fb9987d0f748c983bb795a86f47522313f701a08Sujith 145fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(tx_hdr)); 146fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); 147fb9987d0f748c983bb795a86f47522313f701a08Sujith 148fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = skb_get_queue_mapping(skb); 149fb9987d0f748c983bb795a86f47522313f701a08Sujith 150b80841c91f42dc048a60bff5e1614a619f725e38Sujith switch (qnum) { 151fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 152b80841c91f42dc048a60bff5e1614a619f725e38Sujith TX_QSTAT_INC(WME_AC_VO); 153b80841c91f42dc048a60bff5e1614a619f725e38Sujith epid = priv->data_vo_ep; 154fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 155b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 1: 1562edb4583c6a581e1e48af259db2a2d467d11551dSujith TX_QSTAT_INC(WME_AC_VI); 157fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_vi_ep; 158fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 159b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 2: 160b80841c91f42dc048a60bff5e1614a619f725e38Sujith TX_QSTAT_INC(WME_AC_BE); 161b80841c91f42dc048a60bff5e1614a619f725e38Sujith epid = priv->data_be_ep; 162fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 163b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 3: 164fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 1652edb4583c6a581e1e48af259db2a2d467d11551dSujith TX_QSTAT_INC(WME_AC_BK); 166fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_bk_ep; 167fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 168fb9987d0f748c983bb795a86f47522313f701a08Sujith } 169fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 170fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_mgmt_hdr mgmt_hdr; 171fb9987d0f748c983bb795a86f47522313f701a08Sujith 172fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); 173fb9987d0f748c983bb795a86f47522313f701a08Sujith 174fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 175fb9987d0f748c983bb795a86f47522313f701a08Sujith 176fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.node_idx = sta_idx; 177da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan mgmt_hdr.vif_idx = vif_idx; 178fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.tidno = 0; 179fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.flags = 0; 180fb9987d0f748c983bb795a86f47522313f701a08Sujith 181fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 182fb9987d0f748c983bb795a86f47522313f701a08Sujith if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 183fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 184fb9987d0f748c983bb795a86f47522313f701a08Sujith else 185fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 186fb9987d0f748c983bb795a86f47522313f701a08Sujith 187fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); 188fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); 189fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->mgmt_ep; 190fb9987d0f748c983bb795a86f47522313f701a08Sujith } 191fb9987d0f748c983bb795a86f47522313f701a08Sujith 192fb9987d0f748c983bb795a86f47522313f701a08Sujith return htc_send(priv->htc, skb, epid, &tx_ctl); 193fb9987d0f748c983bb795a86f47522313f701a08Sujith} 194fb9987d0f748c983bb795a86f47522313f701a08Sujith 195d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujithstatic bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 196d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith struct ath9k_htc_sta *ista, u8 tid) 197d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{ 198d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith bool ret = false; 199d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 200d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_lock_bh(&priv->tx_lock); 201d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) 202d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith ret = true; 203d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_unlock_bh(&priv->tx_lock); 204d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 205d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith return ret; 206d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith} 207d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 208fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_tasklet(unsigned long data) 209fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 210fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 211fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta; 212fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 213fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 214fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = NULL; 215fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 216fb9987d0f748c983bb795a86f47522313f701a08Sujith 217fb9987d0f748c983bb795a86f47522313f701a08Sujith while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { 218fb9987d0f748c983bb795a86f47522313f701a08Sujith 219fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 220fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 221fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 222ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 223ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith memset(&tx_info->status, 0, sizeof(tx_info->status)); 224fb9987d0f748c983bb795a86f47522313f701a08Sujith 225fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_lock(); 226fb9987d0f748c983bb795a86f47522313f701a08Sujith 227ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith sta = ieee80211_find_sta(priv->vif, hdr->addr1); 228ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith if (!sta) { 229ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith rcu_read_unlock(); 230ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith ieee80211_tx_status(priv->hw, skb); 231ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith continue; 232ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith } 233ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 234ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith /* Check if we need to start aggregation */ 235ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 236fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta && conf_is_ht(&priv->hw->conf) && 237d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 238fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data_qos(fc)) { 239fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc, tid; 240fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 241fb9987d0f748c983bb795a86f47522313f701a08Sujith 242fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 243fb9987d0f748c983bb795a86f47522313f701a08Sujith tid = qc[0] & 0xf; 244fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *)sta->drv_priv; 245fb9987d0f748c983bb795a86f47522313f701a08Sujith 246d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { 247fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_start_tx_ba_session(sta, tid); 248d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_lock_bh(&priv->tx_lock); 249fb9987d0f748c983bb795a86f47522313f701a08Sujith ista->tid_state[tid] = AGGR_PROGRESS; 250d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_unlock_bh(&priv->tx_lock); 251fb9987d0f748c983bb795a86f47522313f701a08Sujith } 252fb9987d0f748c983bb795a86f47522313f701a08Sujith } 253fb9987d0f748c983bb795a86f47522313f701a08Sujith } 254fb9987d0f748c983bb795a86f47522313f701a08Sujith 255fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_unlock(); 256fb9987d0f748c983bb795a86f47522313f701a08Sujith 257ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith /* Send status to mac80211 */ 258fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_tx_status(priv->hw, skb); 259fb9987d0f748c983bb795a86f47522313f701a08Sujith } 2607757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith 2617757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith /* Wake TX queues if needed */ 2627757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_lock_bh(&priv->tx_lock); 2637757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith if (priv->tx_queues_stop) { 2647757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith priv->tx_queues_stop = false; 2657757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_unlock_bh(&priv->tx_lock); 2667757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith ath_print(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 2677757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith "Waking up TX queues\n"); 2687757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith ieee80211_wake_queues(priv->hw); 2697757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith return; 2707757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith } 2717757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_unlock_bh(&priv->tx_lock); 272fb9987d0f748c983bb795a86f47522313f701a08Sujith} 273fb9987d0f748c983bb795a86f47522313f701a08Sujith 274fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 275fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id, bool txok) 276fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 277fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; 278d439260e04eca5bce88558feecee4369784f2175Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 279fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 280fb9987d0f748c983bb795a86f47522313f701a08Sujith 281fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!skb) 282fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 283fb9987d0f748c983bb795a86f47522313f701a08Sujith 284d439260e04eca5bce88558feecee4369784f2175Sujith if (ep_id == priv->mgmt_ep) { 285fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_mgmt_hdr)); 286d439260e04eca5bce88558feecee4369784f2175Sujith } else if ((ep_id == priv->data_bk_ep) || 287d439260e04eca5bce88558feecee4369784f2175Sujith (ep_id == priv->data_be_ep) || 288d439260e04eca5bce88558feecee4369784f2175Sujith (ep_id == priv->data_vi_ep) || 289d439260e04eca5bce88558feecee4369784f2175Sujith (ep_id == priv->data_vo_ep)) { 290fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_frame_hdr)); 291d439260e04eca5bce88558feecee4369784f2175Sujith } else { 292d439260e04eca5bce88558feecee4369784f2175Sujith ath_print(common, ATH_DBG_FATAL, 293d439260e04eca5bce88558feecee4369784f2175Sujith "Unsupported TX EPID: %d\n", ep_id); 294d439260e04eca5bce88558feecee4369784f2175Sujith dev_kfree_skb_any(skb); 295d439260e04eca5bce88558feecee4369784f2175Sujith return; 296d439260e04eca5bce88558feecee4369784f2175Sujith } 297fb9987d0f748c983bb795a86f47522313f701a08Sujith 298fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 299fb9987d0f748c983bb795a86f47522313f701a08Sujith 300fb9987d0f748c983bb795a86f47522313f701a08Sujith if (txok) 301fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info->flags |= IEEE80211_TX_STAT_ACK; 302fb9987d0f748c983bb795a86f47522313f701a08Sujith 303fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_tail(&priv->tx_queue, skb); 304fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->tx_tasklet); 305fb9987d0f748c983bb795a86f47522313f701a08Sujith} 306fb9987d0f748c983bb795a86f47522313f701a08Sujith 307fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv) 308fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 309fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_head_init(&priv->tx_queue); 310fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 311fb9987d0f748c983bb795a86f47522313f701a08Sujith} 312fb9987d0f748c983bb795a86f47522313f701a08Sujith 313fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv) 314fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 315fb9987d0f748c983bb795a86f47522313f701a08Sujith 316fb9987d0f748c983bb795a86f47522313f701a08Sujith} 317fb9987d0f748c983bb795a86f47522313f701a08Sujith 318e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) 319fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 320fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 321fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 322fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 323fb9987d0f748c983bb795a86f47522313f701a08Sujith int qnum; 324fb9987d0f748c983bb795a86f47522313f701a08Sujith 325fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&qi, 0, sizeof(qi)); 326ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(subtype); 327fb9987d0f748c983bb795a86f47522313f701a08Sujith 328fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); 329fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum == -1) 330fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 331fb9987d0f748c983bb795a86f47522313f701a08Sujith 332fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum >= ARRAY_SIZE(priv->hwq_map)) { 333fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 334fb9987d0f748c983bb795a86f47522313f701a08Sujith "qnum %u out of range, max %u!\n", 335fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum, (unsigned int)ARRAY_SIZE(priv->hwq_map)); 336fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_releasetxqueue(ah, qnum); 337fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 338fb9987d0f748c983bb795a86f47522313f701a08Sujith } 339fb9987d0f748c983bb795a86f47522313f701a08Sujith 340fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[subtype] = qnum; 341fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 342fb9987d0f748c983bb795a86f47522313f701a08Sujith} 343fb9987d0f748c983bb795a86f47522313f701a08Sujith 344ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) 345ca74b83b66dbd289a395c6243695d746c76676ccSujith{ 346ca74b83b66dbd289a395c6243695d746c76676ccSujith struct ath9k_tx_queue_info qi; 347ca74b83b66dbd289a395c6243695d746c76676ccSujith 348ca74b83b66dbd289a395c6243695d746c76676ccSujith memset(&qi, 0, sizeof(qi)); 349ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(0); 350ca74b83b66dbd289a395c6243695d746c76676ccSujith 351ca74b83b66dbd289a395c6243695d746c76676ccSujith return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi); 352ca74b83b66dbd289a395c6243695d746c76676ccSujith} 353ca74b83b66dbd289a395c6243695d746c76676ccSujith 354fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 355fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */ 356fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 357fb9987d0f748c983bb795a86f47522313f701a08Sujith 3580995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 3590995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW. 3600995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 3610995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) 3620995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 3630995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) 3640995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3650995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 3660995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt; 3670995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3680995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) 3690995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST 3700995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_MCAST; 3710995d110118b35c0dc5195e3ddddcc0dec263830Sujith 37294a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan if (priv->rxfilter & FIF_PROBE_REQ) 3730995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROBEREQ; 3740995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3750995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* 3760995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station 3770995d110118b35c0dc5195e3ddddcc0dec263830Sujith * mode interface or when in monitor mode. AP mode does not need this 3780995d110118b35c0dc5195e3ddddcc0dec263830Sujith * since it receives all in-BSS frames anyway. 3790995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 3800995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (((ah->opmode != NL80211_IFTYPE_AP) && 3810995d110118b35c0dc5195e3ddddcc0dec263830Sujith (priv->rxfilter & FIF_PROMISC_IN_BSS)) || 3820995d110118b35c0dc5195e3ddddcc0dec263830Sujith (ah->opmode == NL80211_IFTYPE_MONITOR)) 3830995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROM; 3840995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3850995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (priv->rxfilter & FIF_CONTROL) 3860995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_CONTROL; 3870995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3880995d110118b35c0dc5195e3ddddcc0dec263830Sujith if ((ah->opmode == NL80211_IFTYPE_STATION) && 3890995d110118b35c0dc5195e3ddddcc0dec263830Sujith !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) 3900995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_MYBEACON; 3910995d110118b35c0dc5195e3ddddcc0dec263830Sujith else 3920995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_BEACON; 3930995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3940995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (conf_is_ht(&priv->hw->conf)) 3950995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_COMP_BAR; 3960995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3970995d110118b35c0dc5195e3ddddcc0dec263830Sujith return rfilt; 3980995d110118b35c0dc5195e3ddddcc0dec263830Sujith 3990995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE 4000995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 4010995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4020995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 4030995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change. 4040995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 4050995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) 4060995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 4070995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 4080995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_common *common = ath9k_hw_common(ah); 4090995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4100995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt, mfilt[2]; 4110995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4120995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure rx filter */ 4130995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = ath9k_htc_calcrxfilter(priv); 4140995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setrxfilter(ah, rfilt); 4150995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4160995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure bssid mask */ 417364734fafbba0c3133e482db78149b9a823ae7a5Felix Fietkau ath_hw_setbssidmask(common); 4180995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4190995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure operational mode */ 4200995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setopmode(ah); 4210995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4220995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* calculate and install multicast filter */ 4230995d110118b35c0dc5195e3ddddcc0dec263830Sujith mfilt[0] = mfilt[1] = ~0; 4240995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 4250995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 4260995d110118b35c0dc5195e3ddddcc0dec263830Sujith 427fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv) 428fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 429fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_rxena(priv->ah); 4300995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_htc_opmode_init(priv); 43140346b66799b7d382e61bbb68a6b6bbdd20f320eLuis R. Rodriguez ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING)); 432fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; 433fb9987d0f748c983bb795a86f47522313f701a08Sujith} 434fb9987d0f748c983bb795a86f47522313f701a08Sujith 435fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw, 436fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rxs, 437fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 rx_rate, u8 rs_flags) 438fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 439fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_supported_band *sband; 440fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ieee80211_band band; 441fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned int i = 0; 442fb9987d0f748c983bb795a86f47522313f701a08Sujith 443fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rx_rate & 0x80) { 444fb9987d0f748c983bb795a86f47522313f701a08Sujith /* HT rate */ 445fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_HT; 446fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_2040) 447fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_40MHZ; 448fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_GI) 449fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORT_GI; 450fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = rx_rate & 0x7f; 451fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 452fb9987d0f748c983bb795a86f47522313f701a08Sujith } 453fb9987d0f748c983bb795a86f47522313f701a08Sujith 454fb9987d0f748c983bb795a86f47522313f701a08Sujith band = hw->conf.channel->band; 455fb9987d0f748c983bb795a86f47522313f701a08Sujith sband = hw->wiphy->bands[band]; 456fb9987d0f748c983bb795a86f47522313f701a08Sujith 457fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < sband->n_bitrates; i++) { 458fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value == rx_rate) { 459fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 460fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 461fb9987d0f748c983bb795a86f47522313f701a08Sujith } 462fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value_short == rx_rate) { 463fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 464fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORTPRE; 465fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 466fb9987d0f748c983bb795a86f47522313f701a08Sujith } 467fb9987d0f748c983bb795a86f47522313f701a08Sujith } 468fb9987d0f748c983bb795a86f47522313f701a08Sujith 469fb9987d0f748c983bb795a86f47522313f701a08Sujith} 470fb9987d0f748c983bb795a86f47522313f701a08Sujith 471fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, 472fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, 473fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rx_status) 474fb9987d0f748c983bb795a86f47522313f701a08Sujith 475fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 476fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 477fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 478fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = rxbuf->skb; 479fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 4804f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith struct ath_htc_rx_status *rxstatus; 481fb9987d0f748c983bb795a86f47522313f701a08Sujith int hdrlen, padpos, padsize; 482fb9987d0f748c983bb795a86f47522313f701a08Sujith int last_rssi = ATH_RSSI_DUMMY_MARKER; 483fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 484fb9987d0f748c983bb795a86f47522313f701a08Sujith 4854f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith if (skb->len <= HTC_RX_FRAME_HEADER_SIZE) { 4864f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith ath_print(common, ATH_DBG_FATAL, 4874f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith "Corrupted RX frame, dropping\n"); 4884f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 4894f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 4904f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 4914f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith rxstatus = (struct ath_htc_rx_status *)skb->data; 4924f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 4934f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith if (be16_to_cpu(rxstatus->rs_datalen) - 4944f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { 4954f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith ath_print(common, ATH_DBG_FATAL, 4964f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith "Corrupted RX data len, dropping " 4974f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith "(dlen: %d, skblen: %d)\n", 4984f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith rxstatus->rs_datalen, skb->len); 4994f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 5004f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 5014f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 5024f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith /* Get the RX status information */ 5034f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); 5044f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); 5054f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 506fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *)skb->data; 507fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 508fb9987d0f748c983bb795a86f47522313f701a08Sujith hdrlen = ieee80211_get_hdrlen_from_skb(skb); 509fb9987d0f748c983bb795a86f47522313f701a08Sujith 510fb9987d0f748c983bb795a86f47522313f701a08Sujith padpos = ath9k_cmn_padpos(fc); 511fb9987d0f748c983bb795a86f47522313f701a08Sujith 512fb9987d0f748c983bb795a86f47522313f701a08Sujith padsize = padpos & 3; 51332fbccafed7e935432b601f0453c2b702a385a25Sujith if (padsize && skb->len >= padpos+padsize+FCS_LEN) { 514fb9987d0f748c983bb795a86f47522313f701a08Sujith memmove(skb->data + padsize, skb->data, padpos); 515fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, padsize); 516fb9987d0f748c983bb795a86f47522313f701a08Sujith } 517fb9987d0f748c983bb795a86f47522313f701a08Sujith 518fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); 519fb9987d0f748c983bb795a86f47522313f701a08Sujith 520fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status != 0) { 521fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) 522fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 523fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) 524fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 525fb9987d0f748c983bb795a86f47522313f701a08Sujith 526fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { 527fb9987d0f748c983bb795a86f47522313f701a08Sujith /* FIXME */ 528fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { 529fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_ctl(fc)) 530fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 531fb9987d0f748c983bb795a86f47522313f701a08Sujith * Sometimes, we get invalid 532fb9987d0f748c983bb795a86f47522313f701a08Sujith * MIC failures on valid control frames. 533fb9987d0f748c983bb795a86f47522313f701a08Sujith * Remove these mic errors. 534fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 535fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; 536fb9987d0f748c983bb795a86f47522313f701a08Sujith else 537fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_MMIC_ERROR; 538fb9987d0f748c983bb795a86f47522313f701a08Sujith } 539fb9987d0f748c983bb795a86f47522313f701a08Sujith 540fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 541fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reject error frames with the exception of 542fb9987d0f748c983bb795a86f47522313f701a08Sujith * decryption and MIC failures. For monitor mode, 543fb9987d0f748c983bb795a86f47522313f701a08Sujith * we also ignore the CRC error. 544fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 545fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { 546fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 547fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 548fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH9K_RXERR_CRC)) 549fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 550fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 551fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 552fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 553fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 554fb9987d0f748c983bb795a86f47522313f701a08Sujith } 555fb9987d0f748c983bb795a86f47522313f701a08Sujith } 556fb9987d0f748c983bb795a86f47522313f701a08Sujith } 557fb9987d0f748c983bb795a86f47522313f701a08Sujith 558fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { 559fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 keyix; 560fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = rxbuf->rxstatus.rs_keyix; 561fb9987d0f748c983bb795a86f47522313f701a08Sujith if (keyix != ATH9K_RXKEYIX_INVALID) { 562fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 563fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (ieee80211_has_protected(fc) && 564fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len >= hdrlen + 4) { 565fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = skb->data[hdrlen + 3] >> 6; 566fb9987d0f748c983bb795a86f47522313f701a08Sujith if (test_bit(keyix, common->keymap)) 567fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 568fb9987d0f748c983bb795a86f47522313f701a08Sujith } 569fb9987d0f748c983bb795a86f47522313f701a08Sujith } 570fb9987d0f748c983bb795a86f47522313f701a08Sujith 571fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, 572fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_flags); 573fb9987d0f748c983bb795a86f47522313f701a08Sujith 574fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->op_flags & OP_ASSOCIATED) { 575fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && 576fb9987d0f748c983bb795a86f47522313f701a08Sujith !rxbuf->rxstatus.rs_moreaggr) 577fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH_RSSI_LPF(priv->rx.last_rssi, 578fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi); 579fb9987d0f748c983bb795a86f47522313f701a08Sujith 580fb9987d0f748c983bb795a86f47522313f701a08Sujith last_rssi = priv->rx.last_rssi; 581fb9987d0f748c983bb795a86f47522313f701a08Sujith 582fb9987d0f748c983bb795a86f47522313f701a08Sujith if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 583fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, 584fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH_RSSI_EP_MULTIPLIER); 585fb9987d0f748c983bb795a86f47522313f701a08Sujith 586fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_rssi < 0) 587fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_rssi = 0; 588fb9987d0f748c983bb795a86f47522313f701a08Sujith 589fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_beacon(fc)) 590fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; 591fb9987d0f748c983bb795a86f47522313f701a08Sujith } 592fb9987d0f748c983bb795a86f47522313f701a08Sujith 5937f1f5a0060e377ff6a15903487b39223e12b8568Sujith rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); 594fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->band = hw->conf.channel->band; 595fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->freq = hw->conf.channel->center_freq; 596fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 597fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->antenna = rxbuf->rxstatus.rs_antenna; 598fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_TSFT; 599fb9987d0f748c983bb795a86f47522313f701a08Sujith 600fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 601fb9987d0f748c983bb795a86f47522313f701a08Sujith 602fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next: 603fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 604fb9987d0f748c983bb795a86f47522313f701a08Sujith} 605fb9987d0f748c983bb795a86f47522313f701a08Sujith 606fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 607fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on. 608fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 609fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data) 610fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 611fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 612fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 613fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status rx_status; 614fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb; 615fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned long flags; 616bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan struct ieee80211_hdr *hdr; 617fb9987d0f748c983bb795a86f47522313f701a08Sujith 618fb9987d0f748c983bb795a86f47522313f701a08Sujith do { 619fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 620fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 621fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tmp_buf->in_process) { 622fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 623fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 624fb9987d0f748c983bb795a86f47522313f701a08Sujith } 625fb9987d0f748c983bb795a86f47522313f701a08Sujith } 626fb9987d0f748c983bb795a86f47522313f701a08Sujith 627fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 628fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 629fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 630fb9987d0f748c983bb795a86f47522313f701a08Sujith } 631fb9987d0f748c983bb795a86f47522313f701a08Sujith 632fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!rxbuf->skb) 633fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 634fb9987d0f748c983bb795a86f47522313f701a08Sujith 635fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { 636fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 637fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 638fb9987d0f748c983bb795a86f47522313f701a08Sujith } 639fb9987d0f748c983bb795a86f47522313f701a08Sujith 640fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, 641fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct ieee80211_rx_status)); 642fb9987d0f748c983bb795a86f47522313f701a08Sujith skb = rxbuf->skb; 643bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan hdr = (struct ieee80211_hdr *) skb->data; 644bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 645bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) 646bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan ieee80211_queue_work(priv->hw, &priv->ps_work); 647bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 648fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 649fb9987d0f748c983bb795a86f47522313f701a08Sujith 650fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_rx(priv->hw, skb); 651fb9987d0f748c983bb795a86f47522313f701a08Sujith 652fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 653fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue: 654fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = false; 655fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = NULL; 656fb9987d0f748c983bb795a86f47522313f701a08Sujith list_move_tail(&rxbuf->list, &priv->rx.rxbuf); 657fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = NULL; 658fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 659fb9987d0f748c983bb795a86f47522313f701a08Sujith } while (1); 660fb9987d0f748c983bb795a86f47522313f701a08Sujith 661fb9987d0f748c983bb795a86f47522313f701a08Sujith} 662fb9987d0f748c983bb795a86f47522313f701a08Sujith 663fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 664fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id) 665fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 666fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; 667fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 668fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 669fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 670fb9987d0f748c983bb795a86f47522313f701a08Sujith 671fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 672fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 673fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!tmp_buf->in_process) { 674fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 675fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 676fb9987d0f748c983bb795a86f47522313f701a08Sujith } 677fb9987d0f748c983bb795a86f47522313f701a08Sujith } 678fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 679fb9987d0f748c983bb795a86f47522313f701a08Sujith 680fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 681fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_ANY, 682fb9987d0f748c983bb795a86f47522313f701a08Sujith "No free RX buffer\n"); 683fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 684fb9987d0f748c983bb795a86f47522313f701a08Sujith } 685fb9987d0f748c983bb795a86f47522313f701a08Sujith 686fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 687fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = skb; 688fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = true; 689fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 690fb9987d0f748c983bb795a86f47522313f701a08Sujith 691fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->rx_tasklet); 692fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 693fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 694fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(skb); 695fb9987d0f748c983bb795a86f47522313f701a08Sujith} 696fb9987d0f748c983bb795a86f47522313f701a08Sujith 697fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */ 698fb9987d0f748c983bb795a86f47522313f701a08Sujith 699fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv) 700fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 701fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, *tbuf; 702fb9987d0f748c983bb795a86f47522313f701a08Sujith 703fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { 704fb9987d0f748c983bb795a86f47522313f701a08Sujith list_del(&rxbuf->list); 705fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->skb) 706fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 707fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(rxbuf); 708fb9987d0f748c983bb795a86f47522313f701a08Sujith } 709fb9987d0f748c983bb795a86f47522313f701a08Sujith} 710fb9987d0f748c983bb795a86f47522313f701a08Sujith 711fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv) 712fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 713fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 714fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 715fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf; 716fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 717fb9987d0f748c983bb795a86f47522313f701a08Sujith 718fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_LIST_HEAD(&priv->rx.rxbuf); 719fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->rx.rxbuflock); 720fb9987d0f748c983bb795a86f47522313f701a08Sujith 721fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ATH9K_HTC_RXBUF; i++) { 722fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); 723fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 724fb9987d0f748c983bb795a86f47522313f701a08Sujith ath_print(common, ATH_DBG_FATAL, 725fb9987d0f748c983bb795a86f47522313f701a08Sujith "Unable to allocate RX buffers\n"); 726fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 727fb9987d0f748c983bb795a86f47522313f701a08Sujith } 728fb9987d0f748c983bb795a86f47522313f701a08Sujith list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 729fb9987d0f748c983bb795a86f47522313f701a08Sujith } 730fb9987d0f748c983bb795a86f47522313f701a08Sujith 731fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 732fb9987d0f748c983bb795a86f47522313f701a08Sujith 733fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 734fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 735fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 736fb9987d0f748c983bb795a86f47522313f701a08Sujith} 737