htc_drv_txrx.c revision b587fc81a80b9656f64e89fe0a106ffa4b35abca
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 23066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkaustatic const int subtype_txq_to_hwq[] = { 24066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_BE] = ATH_TXQ_AC_BE, 25066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_BK] = ATH_TXQ_AC_BK, 26066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_VI] = ATH_TXQ_AC_VI, 27066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_VO] = ATH_TXQ_AC_VO, 28066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau}; 29066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau 30ca74b83b66dbd289a395c6243695d746c76676ccSujith#define ATH9K_HTC_INIT_TXQ(subtype) do { \ 31066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \ 32ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \ 33ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \ 34ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \ 35ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_physCompBuf = 0; \ 36ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \ 37ca74b83b66dbd289a395c6243695d746c76676ccSujith TXQ_FLAG_TXDESCINT_ENABLE; \ 38ca74b83b66dbd289a395c6243695d746c76676ccSujith } while (0) 39ca74b83b66dbd289a395c6243695d746c76676ccSujith 40fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map) 41fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 42fb9987d0f748c983bb795a86f47522313f701a08Sujith switch (queue) { 43fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 44e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VO]; 45fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 46e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VI]; 47fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 48e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 49fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 50e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BK]; 51fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 52e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 53fb9987d0f748c983bb795a86f47522313f701a08Sujith } 54fb9987d0f748c983bb795a86f47522313f701a08Sujith} 55fb9987d0f748c983bb795a86f47522313f701a08Sujith 568e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharanvoid ath9k_htc_check_stop_queues(struct ath9k_htc_priv *priv) 578e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan{ 588e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 598e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan priv->tx.queued_cnt++; 608e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan if ((priv->tx.queued_cnt >= ATH9K_HTC_TX_THRESHOLD) && 618e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan !(priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { 628e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan priv->tx.flags |= ATH9K_HTC_OP_TX_QUEUES_STOP; 638e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan ieee80211_stop_queues(priv->hw); 648e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan } 658e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 668e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan} 678e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan 688e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharanvoid ath9k_htc_check_wake_queues(struct ath9k_htc_priv *priv) 698e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan{ 708e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 718e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan if ((priv->tx.queued_cnt < ATH9K_HTC_TX_THRESHOLD) && 728e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan (priv->tx.flags & ATH9K_HTC_OP_TX_QUEUES_STOP)) { 738e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan priv->tx.flags &= ~ATH9K_HTC_OP_TX_QUEUES_STOP; 748e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan ieee80211_wake_queues(priv->hw); 758e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan } 768e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 778e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan} 788e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan 792c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharanint ath9k_htc_tx_get_slot(struct ath9k_htc_priv *priv) 802c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan{ 812c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan int slot; 822c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 832c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 842c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = find_first_zero_bit(priv->tx.tx_slot, MAX_TX_BUF_NUM); 852c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan if (slot >= MAX_TX_BUF_NUM) { 862c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 872c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan return -ENOBUFS; 882c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan } 892c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan __set_bit(slot, priv->tx.tx_slot); 902c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 912c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 922c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan return slot; 932c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan} 942c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 952c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharanvoid ath9k_htc_tx_clear_slot(struct ath9k_htc_priv *priv, int slot) 962c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan{ 972c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 982c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan __clear_bit(slot, priv->tx.tx_slot); 992c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 1002c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan} 1012c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 102d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharanstatic enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, 103d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan u16 qnum) 104d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan{ 105d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan enum htc_endpoint_id epid; 106d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 107d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan switch (qnum) { 108d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 0: 109d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan TX_QSTAT_INC(WME_AC_VO); 110d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_vo_ep; 111d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 112d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 1: 113d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan TX_QSTAT_INC(WME_AC_VI); 114d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_vi_ep; 115d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 116d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 2: 117d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan TX_QSTAT_INC(WME_AC_BE); 118d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_be_ep; 119d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 120d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 3: 121d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan default: 122d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan TX_QSTAT_INC(WME_AC_BK); 123d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_bk_ep; 124d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 125d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan } 126d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 127d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan return epid; 128d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan} 129d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 1302c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan/* 1312c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan * Removes the driver header and returns the TX slot number 1322c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan */ 133729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharanstatic inline int strip_drv_header(struct ath9k_htc_priv *priv, 134729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct sk_buff *skb) 135729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan{ 136729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 137729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 1382c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan int slot; 139729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 140729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 141729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 142729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan if (tx_ctl->epid == priv->mgmt_ep) { 1432c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct tx_mgmt_hdr *tx_mhdr = 1442c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan (struct tx_mgmt_hdr *)skb->data; 1452c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = tx_mhdr->cookie; 146729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan skb_pull(skb, sizeof(struct tx_mgmt_hdr)); 147729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } else if ((tx_ctl->epid == priv->data_bk_ep) || 148729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_be_ep) || 149729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_vi_ep) || 150729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_vo_ep) || 151729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->cab_ep)) { 1522c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct tx_frame_hdr *tx_fhdr = 1532c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan (struct tx_frame_hdr *)skb->data; 1542c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = tx_fhdr->cookie; 155729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan skb_pull(skb, sizeof(struct tx_frame_hdr)); 156729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } else { 157729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); 1582c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = -EINVAL; 159729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } 160729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 1612c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan return slot; 162729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan} 163729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 164e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 165e1572c5eeca8ef87a250322364584458b2dadb35Sujith struct ath9k_tx_queue_info *qinfo) 166fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 167fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 168fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 169fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 170fb9987d0f748c983bb795a86f47522313f701a08Sujith 171fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_get_txq_props(ah, qnum, &qi); 172fb9987d0f748c983bb795a86f47522313f701a08Sujith 173fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = qinfo->tqi_aifs; 174fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ 175fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = qinfo->tqi_cwmax; 176fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_burstTime = qinfo->tqi_burstTime; 177fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_readyTime = qinfo->tqi_readyTime; 178fb9987d0f748c983bb795a86f47522313f701a08Sujith 179fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 1803800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(ath9k_hw_common(ah), 1813800276a40751539a920ef8e0537ef2e19126799Joe Perches "Unable to update hardware queue %u!\n", qnum); 182fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -EIO; 183fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 184fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_resettxqueue(ah, qnum); 185fb9987d0f748c983bb795a86f47522313f701a08Sujith } 186fb9987d0f748c983bb795a86f47522313f701a08Sujith 187fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 188fb9987d0f748c983bb795a86f47522313f701a08Sujith} 189fb9987d0f748c983bb795a86f47522313f701a08Sujith 1907d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharanint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, 1912c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct sk_buff *skb, 1922c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan u8 slot, bool is_cab) 193fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 194fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 1959b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan struct ieee80211_mgmt *mgmt; 196fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 197fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta = tx_info->control.sta; 198a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan struct ieee80211_vif *vif = tx_info->control.vif; 199fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 2009b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan struct ath9k_htc_vif *avp = NULL; 20140dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 202b80841c91f42dc048a60bff5e1614a619f725e38Sujith u16 qnum; 203fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 204fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *tx_fhdr; 205da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan u8 sta_idx, vif_idx; 206fb9987d0f748c983bb795a86f47522313f701a08Sujith 20740dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan tx_ctl = HTC_SKB_CB(skb); 20840dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan memset(tx_ctl, 0, sizeof(*tx_ctl)); 20940dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan 210fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 211fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 212fb9987d0f748c983bb795a86f47522313f701a08Sujith 213a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 214a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out on which interface this packet has to be 215a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * sent out. 216a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 217a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (vif) { 218a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan avp = (struct ath9k_htc_vif *) vif->drv_priv; 219a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = avp->index; 220a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } else { 221a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (!priv->ah->is_monitoring) { 222a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 223a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan "VIF is null, but no monitor interface !\n"); 224a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan return -EINVAL; 225a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 226a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan 227a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = priv->mon_vif_idx; 228a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 229da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan 230a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 231a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out which station this packet is destined for. 232a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 233fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta) { 234fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 235fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = ista->index; 236fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 237a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan sta_idx = priv->vif_sta_pos[vif_idx]; 238fb9987d0f748c983bb795a86f47522313f701a08Sujith } 239fb9987d0f748c983bb795a86f47522313f701a08Sujith 240fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 241fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_frame_hdr tx_hdr; 242dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan u32 flags = 0; 243fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc; 244fb9987d0f748c983bb795a86f47522313f701a08Sujith 245fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); 246fb9987d0f748c983bb795a86f47522313f701a08Sujith 247fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.node_idx = sta_idx; 248da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan tx_hdr.vif_idx = vif_idx; 2492c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan tx_hdr.cookie = slot; 250fb9987d0f748c983bb795a86f47522313f701a08Sujith 251fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 25240dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan tx_ctl->type = ATH9K_HTC_AMPDU; 253fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_AMPDU; 254fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 25540dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan tx_ctl->type = ATH9K_HTC_NORMAL; 256fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_NORMAL; 257fb9987d0f748c983bb795a86f47522313f701a08Sujith } 258fb9987d0f748c983bb795a86f47522313f701a08Sujith 2593bf30b56c4f0a1c4fae34050b7db4527c92891e8Rajkumar Manoharan if (ieee80211_is_data_qos(fc)) { 260fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 261fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 262fb9987d0f748c983bb795a86f47522313f701a08Sujith } 263fb9987d0f748c983bb795a86f47522313f701a08Sujith 264fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Check for RTS protection */ 265fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->hw->wiphy->rts_threshold != (u32) -1) 266fb9987d0f748c983bb795a86f47522313f701a08Sujith if (skb->len > priv->hw->wiphy->rts_threshold) 267dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan flags |= ATH9K_HTC_TX_RTSCTS; 268fb9987d0f748c983bb795a86f47522313f701a08Sujith 269fb9987d0f748c983bb795a86f47522313f701a08Sujith /* CTS-to-self */ 270dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan if (!(flags & ATH9K_HTC_TX_RTSCTS) && 2719304c82d8f3b40eb31c2d04f5849fbd9802c06efSujith Manoharan (vif && vif->bss_conf.use_cts_prot)) 272dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan flags |= ATH9K_HTC_TX_CTSONLY; 273fb9987d0f748c983bb795a86f47522313f701a08Sujith 274dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan tx_hdr.flags = cpu_to_be32(flags); 275fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 276fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 277fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 278fb9987d0f748c983bb795a86f47522313f701a08Sujith else 279fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 280fb9987d0f748c983bb795a86f47522313f701a08Sujith 281fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(tx_hdr)); 282fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); 283fb9987d0f748c983bb795a86f47522313f701a08Sujith 2847d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan if (is_cab) { 2857d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan CAB_STAT_INC; 286d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan tx_ctl->epid = priv->cab_ep; 2877d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan goto send; 2887d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan } 2897d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan 290fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = skb_get_queue_mapping(skb); 291d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan tx_ctl->epid = get_htc_epid(priv, qnum); 292fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 293fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_mgmt_hdr mgmt_hdr; 294fb9987d0f748c983bb795a86f47522313f701a08Sujith 295fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); 296fb9987d0f748c983bb795a86f47522313f701a08Sujith 2979b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan /* 2989b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan * Set the TSF adjust value for probe response 2999b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan * frame also. 3009b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan */ 3019b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan if (avp && unlikely(ieee80211_is_probe_resp(fc))) { 3029b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan mgmt = (struct ieee80211_mgmt *)skb->data; 3039b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan mgmt->u.probe_resp.timestamp = avp->tsfadjust; 3049b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan } 3059b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan 30640dc9e4b86963b77918f1b8fa02b98c1e420a7e1Sujith Manoharan tx_ctl->type = ATH9K_HTC_MGMT; 307fb9987d0f748c983bb795a86f47522313f701a08Sujith 308fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.node_idx = sta_idx; 309da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan mgmt_hdr.vif_idx = vif_idx; 310fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.tidno = 0; 311fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.flags = 0; 3122c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan mgmt_hdr.cookie = slot; 313fb9987d0f748c983bb795a86f47522313f701a08Sujith 314fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 315fb9987d0f748c983bb795a86f47522313f701a08Sujith if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 316fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 317fb9987d0f748c983bb795a86f47522313f701a08Sujith else 318fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 319fb9987d0f748c983bb795a86f47522313f701a08Sujith 320fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); 321fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); 322d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan tx_ctl->epid = priv->mgmt_ep; 323fb9987d0f748c983bb795a86f47522313f701a08Sujith } 3247d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharansend: 325d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan return htc_send(priv->htc, skb); 326fb9987d0f748c983bb795a86f47522313f701a08Sujith} 327fb9987d0f748c983bb795a86f47522313f701a08Sujith 328f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 329f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_sta *ista, u8 tid) 330d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{ 331d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith bool ret = false; 332d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 333658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 334d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) 335d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith ret = true; 336658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 337d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 338d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith return ret; 339d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith} 340d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 341f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 342f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_vif *vif, 343f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct sk_buff *skb) 344fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 345fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta; 346fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 347fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 348fb9987d0f748c983bb795a86f47522313f701a08Sujith 349f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan hdr = (struct ieee80211_hdr *) skb->data; 350f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan fc = hdr->frame_control; 351fb9987d0f748c983bb795a86f47522313f701a08Sujith 352f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_lock(); 353729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 354f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan sta = ieee80211_find_sta(vif, hdr->addr1); 355f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (!sta) { 356f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_unlock(); 357f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan return; 358f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 359ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 360f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (sta && conf_is_ht(&priv->hw->conf) && 361f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 362f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (ieee80211_is_data_qos(fc)) { 363f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan u8 *qc, tid; 364f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_sta *ista; 365fb9987d0f748c983bb795a86f47522313f701a08Sujith 366f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan qc = ieee80211_get_qos_ctl(hdr); 367f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tid = qc[0] & 0xf; 368f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ista = (struct ath9k_htc_sta *)sta->drv_priv; 369f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { 370f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ieee80211_start_tx_ba_session(sta, tid, 0); 371f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 372f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ista->tid_state[tid] = AGGR_PROGRESS; 373f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 374f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 375f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 376f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 377f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan 378f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_unlock(); 379f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan} 380729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 381f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, 382f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct sk_buff *skb) 383f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{ 384f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_vif *vif; 385f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 386f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_tx_info *tx_info; 387f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan bool txok; 388f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan int slot; 389729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 390f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan slot = strip_drv_header(priv, skb); 391f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (slot < 0) { 392f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan dev_kfree_skb_any(skb); 393f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan return; 394f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 3952299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan 396f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tx_ctl = HTC_SKB_CB(skb); 397f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan txok = tx_ctl->txok; 398f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tx_info = IEEE80211_SKB_CB(skb); 399f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan vif = tx_info->control.vif; 400fb9987d0f748c983bb795a86f47522313f701a08Sujith 401f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan memset(&tx_info->status, 0, sizeof(tx_info->status)); 402ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 403f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan /* 404f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan * URB submission failed for this frame, it never reached 405f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan * the target. 406f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan */ 407f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (!txok || !vif) 408f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan goto send_mac80211; 409ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 410f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tx_info->flags |= IEEE80211_TX_STAT_ACK; 411fb9987d0f748c983bb795a86f47522313f701a08Sujith 412f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ath9k_htc_check_tx_aggr(priv, vif, skb); 413fb9987d0f748c983bb795a86f47522313f701a08Sujith 414f2820f4583b233827f10d91adea70225e196d852Sujith Manoharansend_mac80211: 415f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 416f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (WARN_ON(--priv->tx.queued_cnt < 0)) 417f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan priv->tx.queued_cnt = 0; 418f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 419fb9987d0f748c983bb795a86f47522313f701a08Sujith 420f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ath9k_htc_tx_clear_slot(priv, slot); 421fb9987d0f748c983bb795a86f47522313f701a08Sujith 422f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan /* Send status to mac80211 */ 423f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ieee80211_tx_status(priv->hw, skb); 424f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan} 4258e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan 426b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharanvoid ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) 427b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan{ 428b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan struct sk_buff *skb = NULL; 429b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 430b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan /* 431b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan * Ensure that all pending TX frames are flushed, 432b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan * and that the TX completion tasklet is killed. 433b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan */ 434b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan htc_stop(priv->htc); 435b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan tasklet_kill(&priv->tx_tasklet); 436b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 437b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { 438b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan ath9k_htc_tx_process(priv, skb); 439b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan } 440b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 441b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { 442b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan ath9k_htc_tx_process(priv, skb); 443b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan } 444b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan} 445b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 446f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanvoid ath9k_tx_tasklet(unsigned long data) 447f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{ 448f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 449f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct sk_buff *skb = NULL; 4502c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 451f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan while ((skb = skb_dequeue(&priv->tx.tx_queue)) != NULL) { 452f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ath9k_htc_tx_process(priv, skb); 453fb9987d0f748c983bb795a86f47522313f701a08Sujith } 4547757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith 455b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan while ((skb = skb_dequeue(&priv->tx.tx_failed)) != NULL) { 456b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan ath9k_htc_tx_process(priv, skb); 457b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan } 458b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 4597757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith /* Wake TX queues if needed */ 4608e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan ath9k_htc_check_wake_queues(priv); 461fb9987d0f748c983bb795a86f47522313f701a08Sujith} 462fb9987d0f748c983bb795a86f47522313f701a08Sujith 463fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 464fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id, bool txok) 465fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 466fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; 467729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 468fb9987d0f748c983bb795a86f47522313f701a08Sujith 469729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 470729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl->txok = txok; 471fb9987d0f748c983bb795a86f47522313f701a08Sujith 472b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan if (txok) 473b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan skb_queue_tail(&priv->tx.tx_queue, skb); 474b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan else 475b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan skb_queue_tail(&priv->tx.tx_failed, skb); 476b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 477fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->tx_tasklet); 478fb9987d0f748c983bb795a86f47522313f701a08Sujith} 479fb9987d0f748c983bb795a86f47522313f701a08Sujith 480fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv) 481fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 482658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan skb_queue_head_init(&priv->tx.tx_queue); 483b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan skb_queue_head_init(&priv->tx.tx_failed); 484fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 485fb9987d0f748c983bb795a86f47522313f701a08Sujith} 486fb9987d0f748c983bb795a86f47522313f701a08Sujith 487fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv) 488fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 489fb9987d0f748c983bb795a86f47522313f701a08Sujith 490fb9987d0f748c983bb795a86f47522313f701a08Sujith} 491fb9987d0f748c983bb795a86f47522313f701a08Sujith 492e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) 493fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 494fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 495fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 496fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 497fb9987d0f748c983bb795a86f47522313f701a08Sujith int qnum; 498fb9987d0f748c983bb795a86f47522313f701a08Sujith 499fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&qi, 0, sizeof(qi)); 500ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(subtype); 501fb9987d0f748c983bb795a86f47522313f701a08Sujith 502fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); 503fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum == -1) 504fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 505fb9987d0f748c983bb795a86f47522313f701a08Sujith 506fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum >= ARRAY_SIZE(priv->hwq_map)) { 5073800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "qnum %u out of range, max %zu!\n", 5083800276a40751539a920ef8e0537ef2e19126799Joe Perches qnum, ARRAY_SIZE(priv->hwq_map)); 509fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_releasetxqueue(ah, qnum); 510fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 511fb9987d0f748c983bb795a86f47522313f701a08Sujith } 512fb9987d0f748c983bb795a86f47522313f701a08Sujith 513fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[subtype] = qnum; 514fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 515fb9987d0f748c983bb795a86f47522313f701a08Sujith} 516fb9987d0f748c983bb795a86f47522313f701a08Sujith 517ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) 518ca74b83b66dbd289a395c6243695d746c76676ccSujith{ 519ca74b83b66dbd289a395c6243695d746c76676ccSujith struct ath9k_tx_queue_info qi; 520ca74b83b66dbd289a395c6243695d746c76676ccSujith 521ca74b83b66dbd289a395c6243695d746c76676ccSujith memset(&qi, 0, sizeof(qi)); 522ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(0); 523ca74b83b66dbd289a395c6243695d746c76676ccSujith 524ca74b83b66dbd289a395c6243695d746c76676ccSujith return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi); 525ca74b83b66dbd289a395c6243695d746c76676ccSujith} 526ca74b83b66dbd289a395c6243695d746c76676ccSujith 527fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 528fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */ 529fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 530fb9987d0f748c983bb795a86f47522313f701a08Sujith 5310995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 5320995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW. 5330995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 5340995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) 5350995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 5360995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) 5370995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5380995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 5390995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt; 5400995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5410995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) 5420995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST 5430995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_MCAST; 5440995d110118b35c0dc5195e3ddddcc0dec263830Sujith 54594a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan if (priv->rxfilter & FIF_PROBE_REQ) 5460995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROBEREQ; 5470995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5480995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* 5490995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station 5500995d110118b35c0dc5195e3ddddcc0dec263830Sujith * mode interface or when in monitor mode. AP mode does not need this 5510995d110118b35c0dc5195e3ddddcc0dec263830Sujith * since it receives all in-BSS frames anyway. 5520995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 5530995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (((ah->opmode != NL80211_IFTYPE_AP) && 5540995d110118b35c0dc5195e3ddddcc0dec263830Sujith (priv->rxfilter & FIF_PROMISC_IN_BSS)) || 5554825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan ah->is_monitoring) 5560995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROM; 5570995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5580995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (priv->rxfilter & FIF_CONTROL) 5590995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_CONTROL; 5600995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5610995d110118b35c0dc5195e3ddddcc0dec263830Sujith if ((ah->opmode == NL80211_IFTYPE_STATION) && 5620995d110118b35c0dc5195e3ddddcc0dec263830Sujith !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) 5630995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_MYBEACON; 5640995d110118b35c0dc5195e3ddddcc0dec263830Sujith else 5650995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_BEACON; 5660995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5674825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (conf_is_ht(&priv->hw->conf)) { 5680995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_COMP_BAR; 5694825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; 5704825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan } 5714825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan 5724825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (priv->rxfilter & FIF_PSPOLL) 5734825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_PSPOLL; 5740995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5750995d110118b35c0dc5195e3ddddcc0dec263830Sujith return rfilt; 5760995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5770995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE 5780995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 5790995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5800995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 5810995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change. 5820995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 5830995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) 5840995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 5850995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 5860995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt, mfilt[2]; 5870995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5880995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure rx filter */ 5890995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = ath9k_htc_calcrxfilter(priv); 5900995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setrxfilter(ah, rfilt); 5910995d110118b35c0dc5195e3ddddcc0dec263830Sujith 5920995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* calculate and install multicast filter */ 5930995d110118b35c0dc5195e3ddddcc0dec263830Sujith mfilt[0] = mfilt[1] = ~0; 5940995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 5950995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 5960995d110118b35c0dc5195e3ddddcc0dec263830Sujith 597fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv) 598fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 599fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_rxena(priv->ah); 6000995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_htc_opmode_init(priv); 60140346b66799b7d382e61bbb68a6b6bbdd20f320eLuis R. Rodriguez ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING)); 602fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; 603fb9987d0f748c983bb795a86f47522313f701a08Sujith} 604fb9987d0f748c983bb795a86f47522313f701a08Sujith 605fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw, 606fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rxs, 607fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 rx_rate, u8 rs_flags) 608fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 609fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_supported_band *sband; 610fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ieee80211_band band; 611fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned int i = 0; 612fb9987d0f748c983bb795a86f47522313f701a08Sujith 613fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rx_rate & 0x80) { 614fb9987d0f748c983bb795a86f47522313f701a08Sujith /* HT rate */ 615fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_HT; 616fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_2040) 617fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_40MHZ; 618fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_GI) 619fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORT_GI; 620fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = rx_rate & 0x7f; 621fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 622fb9987d0f748c983bb795a86f47522313f701a08Sujith } 623fb9987d0f748c983bb795a86f47522313f701a08Sujith 624fb9987d0f748c983bb795a86f47522313f701a08Sujith band = hw->conf.channel->band; 625fb9987d0f748c983bb795a86f47522313f701a08Sujith sband = hw->wiphy->bands[band]; 626fb9987d0f748c983bb795a86f47522313f701a08Sujith 627fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < sband->n_bitrates; i++) { 628fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value == rx_rate) { 629fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 630fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 631fb9987d0f748c983bb795a86f47522313f701a08Sujith } 632fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value_short == rx_rate) { 633fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 634fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORTPRE; 635fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 636fb9987d0f748c983bb795a86f47522313f701a08Sujith } 637fb9987d0f748c983bb795a86f47522313f701a08Sujith } 638fb9987d0f748c983bb795a86f47522313f701a08Sujith 639fb9987d0f748c983bb795a86f47522313f701a08Sujith} 640fb9987d0f748c983bb795a86f47522313f701a08Sujith 641fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, 642fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, 643fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rx_status) 644fb9987d0f748c983bb795a86f47522313f701a08Sujith 645fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 646fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 647fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 648fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = rxbuf->skb; 649fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 6504f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith struct ath_htc_rx_status *rxstatus; 651fb9987d0f748c983bb795a86f47522313f701a08Sujith int hdrlen, padpos, padsize; 652fb9987d0f748c983bb795a86f47522313f701a08Sujith int last_rssi = ATH_RSSI_DUMMY_MARKER; 653fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 654fb9987d0f748c983bb795a86f47522313f701a08Sujith 655b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { 656b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", 657b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan skb->len); 6584f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 6594f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 6604f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 6614f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith rxstatus = (struct ath_htc_rx_status *)skb->data; 6624f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 6634f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith if (be16_to_cpu(rxstatus->rs_datalen) - 6644f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { 6653800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, 6663800276a40751539a920ef8e0537ef2e19126799Joe Perches "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", 6673800276a40751539a920ef8e0537ef2e19126799Joe Perches rxstatus->rs_datalen, skb->len); 6684f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 6694f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 6704f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 671719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan ath9k_htc_err_stat_rx(priv, rxstatus); 672719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan 6734f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith /* Get the RX status information */ 6744f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); 6754f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); 6764f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 677fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *)skb->data; 678fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 679fb9987d0f748c983bb795a86f47522313f701a08Sujith hdrlen = ieee80211_get_hdrlen_from_skb(skb); 680fb9987d0f748c983bb795a86f47522313f701a08Sujith 681fb9987d0f748c983bb795a86f47522313f701a08Sujith padpos = ath9k_cmn_padpos(fc); 682fb9987d0f748c983bb795a86f47522313f701a08Sujith 683fb9987d0f748c983bb795a86f47522313f701a08Sujith padsize = padpos & 3; 68432fbccafed7e935432b601f0453c2b702a385a25Sujith if (padsize && skb->len >= padpos+padsize+FCS_LEN) { 685fb9987d0f748c983bb795a86f47522313f701a08Sujith memmove(skb->data + padsize, skb->data, padpos); 686fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, padsize); 687fb9987d0f748c983bb795a86f47522313f701a08Sujith } 688fb9987d0f748c983bb795a86f47522313f701a08Sujith 689fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); 690fb9987d0f748c983bb795a86f47522313f701a08Sujith 691fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status != 0) { 692fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) 693fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 694fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) 695fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 696fb9987d0f748c983bb795a86f47522313f701a08Sujith 697fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { 698fb9987d0f748c983bb795a86f47522313f701a08Sujith /* FIXME */ 699fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { 700fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_ctl(fc)) 701fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 702fb9987d0f748c983bb795a86f47522313f701a08Sujith * Sometimes, we get invalid 703fb9987d0f748c983bb795a86f47522313f701a08Sujith * MIC failures on valid control frames. 704fb9987d0f748c983bb795a86f47522313f701a08Sujith * Remove these mic errors. 705fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 706fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; 707fb9987d0f748c983bb795a86f47522313f701a08Sujith else 708fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_MMIC_ERROR; 709fb9987d0f748c983bb795a86f47522313f701a08Sujith } 710fb9987d0f748c983bb795a86f47522313f701a08Sujith 711fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 712fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reject error frames with the exception of 713fb9987d0f748c983bb795a86f47522313f701a08Sujith * decryption and MIC failures. For monitor mode, 714fb9987d0f748c983bb795a86f47522313f701a08Sujith * we also ignore the CRC error. 715fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 716fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { 717fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 718fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 719fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH9K_RXERR_CRC)) 720fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 721fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 722fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 723fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 724fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 725fb9987d0f748c983bb795a86f47522313f701a08Sujith } 726fb9987d0f748c983bb795a86f47522313f701a08Sujith } 727fb9987d0f748c983bb795a86f47522313f701a08Sujith } 728fb9987d0f748c983bb795a86f47522313f701a08Sujith 729fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { 730fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 keyix; 731fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = rxbuf->rxstatus.rs_keyix; 732fb9987d0f748c983bb795a86f47522313f701a08Sujith if (keyix != ATH9K_RXKEYIX_INVALID) { 733fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 734fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (ieee80211_has_protected(fc) && 735fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len >= hdrlen + 4) { 736fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = skb->data[hdrlen + 3] >> 6; 737fb9987d0f748c983bb795a86f47522313f701a08Sujith if (test_bit(keyix, common->keymap)) 738fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 739fb9987d0f748c983bb795a86f47522313f701a08Sujith } 740fb9987d0f748c983bb795a86f47522313f701a08Sujith } 741fb9987d0f748c983bb795a86f47522313f701a08Sujith 742fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, 743fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_flags); 744fb9987d0f748c983bb795a86f47522313f701a08Sujith 7457c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && 7467c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan !rxbuf->rxstatus.rs_moreaggr) 7477c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan ATH_RSSI_LPF(priv->rx.last_rssi, 7487c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi); 749fb9987d0f748c983bb795a86f47522313f701a08Sujith 7507c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan last_rssi = priv->rx.last_rssi; 751fb9987d0f748c983bb795a86f47522313f701a08Sujith 7527c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 7537c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, 7547c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan ATH_RSSI_EP_MULTIPLIER); 755fb9987d0f748c983bb795a86f47522313f701a08Sujith 7567c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (rxbuf->rxstatus.rs_rssi < 0) 7577c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi = 0; 758fb9987d0f748c983bb795a86f47522313f701a08Sujith 7597c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (ieee80211_is_beacon(fc)) 7607c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; 761fb9987d0f748c983bb795a86f47522313f701a08Sujith 7627f1f5a0060e377ff6a15903487b39223e12b8568Sujith rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); 763fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->band = hw->conf.channel->band; 764fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->freq = hw->conf.channel->center_freq; 765fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 766fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->antenna = rxbuf->rxstatus.rs_antenna; 7676ebacbb79d2d05978ba50a24d8cbe2a76ff2014cJohannes Berg rx_status->flag |= RX_FLAG_MACTIME_MPDU; 768fb9987d0f748c983bb795a86f47522313f701a08Sujith 769fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 770fb9987d0f748c983bb795a86f47522313f701a08Sujith 771fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next: 772fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 773fb9987d0f748c983bb795a86f47522313f701a08Sujith} 774fb9987d0f748c983bb795a86f47522313f701a08Sujith 775fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 776fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on. 777fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 778fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data) 779fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 780fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 781fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 782fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status rx_status; 783fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb; 784fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned long flags; 785bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan struct ieee80211_hdr *hdr; 786fb9987d0f748c983bb795a86f47522313f701a08Sujith 787fb9987d0f748c983bb795a86f47522313f701a08Sujith do { 788fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 789fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 790fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tmp_buf->in_process) { 791fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 792fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 793fb9987d0f748c983bb795a86f47522313f701a08Sujith } 794fb9987d0f748c983bb795a86f47522313f701a08Sujith } 795fb9987d0f748c983bb795a86f47522313f701a08Sujith 796fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 797fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 798fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 799fb9987d0f748c983bb795a86f47522313f701a08Sujith } 800fb9987d0f748c983bb795a86f47522313f701a08Sujith 801fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!rxbuf->skb) 802fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 803fb9987d0f748c983bb795a86f47522313f701a08Sujith 804fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { 805fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 806fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 807fb9987d0f748c983bb795a86f47522313f701a08Sujith } 808fb9987d0f748c983bb795a86f47522313f701a08Sujith 809fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, 810fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct ieee80211_rx_status)); 811fb9987d0f748c983bb795a86f47522313f701a08Sujith skb = rxbuf->skb; 812bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan hdr = (struct ieee80211_hdr *) skb->data; 813bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 814bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) 815bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan ieee80211_queue_work(priv->hw, &priv->ps_work); 816bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 817fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 818fb9987d0f748c983bb795a86f47522313f701a08Sujith 819fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_rx(priv->hw, skb); 820fb9987d0f748c983bb795a86f47522313f701a08Sujith 821fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 822fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue: 823fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = false; 824fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = NULL; 825fb9987d0f748c983bb795a86f47522313f701a08Sujith list_move_tail(&rxbuf->list, &priv->rx.rxbuf); 826fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = NULL; 827fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 828fb9987d0f748c983bb795a86f47522313f701a08Sujith } while (1); 829fb9987d0f748c983bb795a86f47522313f701a08Sujith 830fb9987d0f748c983bb795a86f47522313f701a08Sujith} 831fb9987d0f748c983bb795a86f47522313f701a08Sujith 832fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 833fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id) 834fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 835fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; 836fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 837fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 838fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 839fb9987d0f748c983bb795a86f47522313f701a08Sujith 840fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 841fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 842fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!tmp_buf->in_process) { 843fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 844fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 845fb9987d0f748c983bb795a86f47522313f701a08Sujith } 846fb9987d0f748c983bb795a86f47522313f701a08Sujith } 847fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 848fb9987d0f748c983bb795a86f47522313f701a08Sujith 849fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 850226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_ANY, 851226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "No free RX buffer\n"); 852fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 853fb9987d0f748c983bb795a86f47522313f701a08Sujith } 854fb9987d0f748c983bb795a86f47522313f701a08Sujith 855fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 856fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = skb; 857fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = true; 858fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 859fb9987d0f748c983bb795a86f47522313f701a08Sujith 860fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->rx_tasklet); 861fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 862fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 863fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(skb); 864fb9987d0f748c983bb795a86f47522313f701a08Sujith} 865fb9987d0f748c983bb795a86f47522313f701a08Sujith 866fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */ 867fb9987d0f748c983bb795a86f47522313f701a08Sujith 868fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv) 869fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 870fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, *tbuf; 871fb9987d0f748c983bb795a86f47522313f701a08Sujith 872fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { 873fb9987d0f748c983bb795a86f47522313f701a08Sujith list_del(&rxbuf->list); 874fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->skb) 875fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 876fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(rxbuf); 877fb9987d0f748c983bb795a86f47522313f701a08Sujith } 878fb9987d0f748c983bb795a86f47522313f701a08Sujith} 879fb9987d0f748c983bb795a86f47522313f701a08Sujith 880fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv) 881fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 882fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 883fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 884fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf; 885fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 886fb9987d0f748c983bb795a86f47522313f701a08Sujith 887fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_LIST_HEAD(&priv->rx.rxbuf); 888fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->rx.rxbuflock); 889fb9987d0f748c983bb795a86f47522313f701a08Sujith 890fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ATH9K_HTC_RXBUF; i++) { 891fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); 892fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 8933800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to allocate RX buffers\n"); 894fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 895fb9987d0f748c983bb795a86f47522313f701a08Sujith } 896fb9987d0f748c983bb795a86f47522313f701a08Sujith list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 897fb9987d0f748c983bb795a86f47522313f701a08Sujith } 898fb9987d0f748c983bb795a86f47522313f701a08Sujith 899fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 900fb9987d0f748c983bb795a86f47522313f701a08Sujith 901fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 902fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 903fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 904fb9987d0f748c983bb795a86f47522313f701a08Sujith} 905