htc_drv_txrx.c revision 1f83b0492939ec94bcab868f338139a7de521863
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 25b68138e5659cbfd5df2879d17f9ba0b66477fecSujith Manoharan * Copyright (c) 2010-2011 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[] = { 24bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan [IEEE80211_AC_BE] = ATH_TXQ_AC_BE, 25bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan [IEEE80211_AC_BK] = ATH_TXQ_AC_BK, 26bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan [IEEE80211_AC_VI] = ATH_TXQ_AC_VI, 27bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan [IEEE80211_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: 44bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan return hwq_map[IEEE80211_AC_VO]; 45fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 46bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan return hwq_map[IEEE80211_AC_VI]; 47fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 48bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan return hwq_map[IEEE80211_AC_BE]; 49fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 50bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan return hwq_map[IEEE80211_AC_BK]; 51fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 52bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan return hwq_map[IEEE80211_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 10227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv, 10327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan u16 qnum) 104d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan{ 105d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan enum htc_endpoint_id epid; 106d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 107d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan switch (qnum) { 108d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 0: 109bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan TX_QSTAT_INC(IEEE80211_AC_VO); 110d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_vo_ep; 111d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 112d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 1: 113bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan TX_QSTAT_INC(IEEE80211_AC_VI); 114d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_vi_ep; 115d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 116d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 2: 117bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan TX_QSTAT_INC(IEEE80211_AC_BE); 118d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_be_ep; 119d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 120d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan case 3: 121d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan default: 122bea843c73854becf998047a83af22a90de3fd19bSujith Manoharan TX_QSTAT_INC(IEEE80211_AC_BK); 123d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan epid = priv->data_bk_ep; 124d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan break; 125d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan } 126d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 127d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan return epid; 128d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan} 129d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan 13027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline struct sk_buff_head* 13127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanget_htc_epid_queue(struct ath9k_htc_priv *priv, u8 epid) 13227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{ 13327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 13427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff_head *epid_queue = NULL; 13527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 13627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (epid == priv->mgmt_ep) 13727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.mgmt_ep_queue; 13827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else if (epid == priv->cab_ep) 13927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.cab_ep_queue; 14027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else if (epid == priv->data_be_ep) 14127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.data_be_queue; 14227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else if (epid == priv->data_bk_ep) 14327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.data_bk_queue; 14427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else if (epid == priv->data_vi_ep) 14527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.data_vi_queue; 14627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else if (epid == priv->data_vo_ep) 14727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = &priv->tx.data_vo_queue; 14827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan else 14927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath_err(common, "Invalid EPID: %d\n", epid); 15027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 15127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return epid_queue; 15227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan} 15327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 1542c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan/* 1552c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan * Removes the driver header and returns the TX slot number 1562c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan */ 157729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharanstatic inline int strip_drv_header(struct ath9k_htc_priv *priv, 158729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct sk_buff *skb) 159729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan{ 160729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 161729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 1622c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan int slot; 163729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 164729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 165729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 166729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan if (tx_ctl->epid == priv->mgmt_ep) { 1672c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct tx_mgmt_hdr *tx_mhdr = 1682c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan (struct tx_mgmt_hdr *)skb->data; 1692c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = tx_mhdr->cookie; 170729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan skb_pull(skb, sizeof(struct tx_mgmt_hdr)); 171729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } else if ((tx_ctl->epid == priv->data_bk_ep) || 172729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_be_ep) || 173729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_vi_ep) || 174729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->data_vo_ep) || 175729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan (tx_ctl->epid == priv->cab_ep)) { 1762c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct tx_frame_hdr *tx_fhdr = 1772c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan (struct tx_frame_hdr *)skb->data; 1782c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = tx_fhdr->cookie; 179729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan skb_pull(skb, sizeof(struct tx_frame_hdr)); 180729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } else { 181729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan ath_err(common, "Unsupported EPID: %d\n", tx_ctl->epid); 1822c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan slot = -EINVAL; 183729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan } 184729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 1852c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan return slot; 186729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan} 187729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 188e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 189e1572c5eeca8ef87a250322364584458b2dadb35Sujith struct ath9k_tx_queue_info *qinfo) 190fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 191fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 192fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 193fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 194fb9987d0f748c983bb795a86f47522313f701a08Sujith 195fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_get_txq_props(ah, qnum, &qi); 196fb9987d0f748c983bb795a86f47522313f701a08Sujith 197fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = qinfo->tqi_aifs; 198fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ 199fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = qinfo->tqi_cwmax; 200fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_burstTime = qinfo->tqi_burstTime; 201fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_readyTime = qinfo->tqi_readyTime; 202fb9987d0f748c983bb795a86f47522313f701a08Sujith 203fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 2043800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(ath9k_hw_common(ah), 2053800276a40751539a920ef8e0537ef2e19126799Joe Perches "Unable to update hardware queue %u!\n", qnum); 206fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -EIO; 207fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 208fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_resettxqueue(ah, qnum); 209fb9987d0f748c983bb795a86f47522313f701a08Sujith } 210fb9987d0f748c983bb795a86f47522313f701a08Sujith 211fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 212fb9987d0f748c983bb795a86f47522313f701a08Sujith} 213fb9987d0f748c983bb795a86f47522313f701a08Sujith 214821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharanstatic void ath9k_htc_tx_mgmt(struct ath9k_htc_priv *priv, 215821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ath9k_htc_vif *avp, 216821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct sk_buff *skb, 217821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u8 sta_idx, u8 vif_idx, u8 slot) 218821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan{ 219821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 220821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_mgmt *mgmt; 221821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_hdr *hdr; 222821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct tx_mgmt_hdr mgmt_hdr; 223821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 224821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u8 *tx_fhdr; 225821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 226821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 227821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan hdr = (struct ieee80211_hdr *) skb->data; 228821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 229821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memset(tx_ctl, 0, sizeof(*tx_ctl)); 230821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); 231821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 232821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan /* 233821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * Set the TSF adjust value for probe response 234821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * frame also. 235821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan */ 236821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (avp && unlikely(ieee80211_is_probe_resp(hdr->frame_control))) { 237821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt = (struct ieee80211_mgmt *)skb->data; 238821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt->u.probe_resp.timestamp = avp->tsfadjust; 239821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan } 240821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 241821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->type = ATH9K_HTC_MGMT; 242821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 243821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.node_idx = sta_idx; 244821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.vif_idx = vif_idx; 245821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.tidno = 0; 246821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.flags = 0; 247821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.cookie = slot; 248821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 249821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 250821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 251821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 252821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan else 253821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 254821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 255821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); 256821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); 257821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->epid = priv->mgmt_ep; 258821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan} 259821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 260821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharanstatic void ath9k_htc_tx_data(struct ath9k_htc_priv *priv, 261821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_vif *vif, 262821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct sk_buff *skb, 263821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u8 sta_idx, u8 vif_idx, u8 slot, 264821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan bool is_cab) 265821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan{ 266821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 267821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ieee80211_hdr *hdr; 268821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 269821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan struct tx_frame_hdr tx_hdr; 270821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u32 flags = 0; 271821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u8 *qc, *tx_fhdr; 272821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan u16 qnum; 273821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 274821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 275821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan hdr = (struct ieee80211_hdr *) skb->data; 276821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 277821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memset(tx_ctl, 0, sizeof(*tx_ctl)); 278821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); 279821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 280821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.node_idx = sta_idx; 281821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.vif_idx = vif_idx; 282821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.cookie = slot; 283821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 284821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan /* 285821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * This is a bit redundant but it helps to get 286821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * the per-packet index quickly when draining the 287821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * TX queue in the HIF layer. Otherwise we would 288821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan * have to parse the packet contents ... 289821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan */ 290821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->sta_idx = sta_idx; 291821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 292821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 293821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->type = ATH9K_HTC_AMPDU; 294821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.data_type = ATH9K_HTC_AMPDU; 295821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan } else { 296821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->type = ATH9K_HTC_NORMAL; 297821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.data_type = ATH9K_HTC_NORMAL; 298821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan } 299821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 300821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (ieee80211_is_data_qos(hdr->frame_control)) { 301821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan qc = ieee80211_get_qos_ctl(hdr); 302821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 303821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan } 304821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 305821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan /* Check for RTS protection */ 306821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (priv->hw->wiphy->rts_threshold != (u32) -1) 307821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (skb->len > priv->hw->wiphy->rts_threshold) 308821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan flags |= ATH9K_HTC_TX_RTSCTS; 309821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 310821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan /* CTS-to-self */ 311821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (!(flags & ATH9K_HTC_TX_RTSCTS) && 312821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan (vif && vif->bss_conf.use_cts_prot)) 313821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan flags |= ATH9K_HTC_TX_CTSONLY; 314821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 315821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.flags = cpu_to_be32(flags); 316821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 317821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 318821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 319821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan else 320821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 321821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 322821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_fhdr = skb_push(skb, sizeof(tx_hdr)); 323821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); 324821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 325821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (is_cab) { 326821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan CAB_STAT_INC; 327821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->epid = priv->cab_ep; 328821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan return; 329821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan } 330821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 331821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan qnum = skb_get_queue_mapping(skb); 332821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan tx_ctl->epid = get_htc_epid(priv, qnum); 333821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan} 334821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan 3357d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharanint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, 33636323f817af0376c78612cfdab714b0feb05fea5Thomas Huehn struct ieee80211_sta *sta, 3372c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan struct sk_buff *skb, 3382c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan u8 slot, bool is_cab) 339fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 340fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 341fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 342a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan struct ieee80211_vif *vif = tx_info->control.vif; 343fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 3449b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan struct ath9k_htc_vif *avp = NULL; 345da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan u8 sta_idx, vif_idx; 346fb9987d0f748c983bb795a86f47522313f701a08Sujith 347fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 348fb9987d0f748c983bb795a86f47522313f701a08Sujith 349a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 350a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out on which interface this packet has to be 351a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * sent out. 352a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 353a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (vif) { 354a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan avp = (struct ath9k_htc_vif *) vif->drv_priv; 355a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = avp->index; 356a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } else { 357a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (!priv->ah->is_monitoring) { 358d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches ath_dbg(ath9k_hw_common(priv->ah), XMIT, 359a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan "VIF is null, but no monitor interface !\n"); 360a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan return -EINVAL; 361a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 362a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan 363a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = priv->mon_vif_idx; 364a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 365da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan 366a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 367a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out which station this packet is destined for. 368a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 369fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta) { 370fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 371fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = ista->index; 372fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 373a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan sta_idx = priv->vif_sta_pos[vif_idx]; 374fb9987d0f748c983bb795a86f47522313f701a08Sujith } 375fb9987d0f748c983bb795a86f47522313f701a08Sujith 376821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan if (ieee80211_is_data(hdr->frame_control)) 377821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan ath9k_htc_tx_data(priv, vif, skb, 378821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan sta_idx, vif_idx, slot, is_cab); 379821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan else 380821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan ath9k_htc_tx_mgmt(priv, avp, skb, 381821f9414c0546fbc99a999e9dc613d1756e1de8aSujith Manoharan sta_idx, vif_idx, slot); 382fb9987d0f748c983bb795a86f47522313f701a08Sujith 383fb9987d0f748c983bb795a86f47522313f701a08Sujith 384d67ee5339363608adce786ec8fd62a0fb2b66116Sujith Manoharan return htc_send(priv->htc, skb); 385fb9987d0f748c983bb795a86f47522313f701a08Sujith} 386fb9987d0f748c983bb795a86f47522313f701a08Sujith 387f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic inline bool __ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 388f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_sta *ista, u8 tid) 389d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{ 390d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith bool ret = false; 391d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 392658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 393d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) 394d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith ret = true; 395658ef04fd42a587b17a379ad9208023473442dddSujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 396d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 397d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith return ret; 398d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith} 399d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 400f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 401f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_vif *vif, 402f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct sk_buff *skb) 403fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 404fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta; 405fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 406fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 407fb9987d0f748c983bb795a86f47522313f701a08Sujith 408f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan hdr = (struct ieee80211_hdr *) skb->data; 409f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan fc = hdr->frame_control; 410fb9987d0f748c983bb795a86f47522313f701a08Sujith 411f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_lock(); 412729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 413f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan sta = ieee80211_find_sta(vif, hdr->addr1); 414f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (!sta) { 415f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_unlock(); 416f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan return; 417f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 418ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 419f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (sta && conf_is_ht(&priv->hw->conf) && 420f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 421f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (ieee80211_is_data_qos(fc)) { 422f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan u8 *qc, tid; 423f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_sta *ista; 424fb9987d0f748c983bb795a86f47522313f701a08Sujith 425f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan qc = ieee80211_get_qos_ctl(hdr); 426f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tid = qc[0] & 0xf; 427f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ista = (struct ath9k_htc_sta *)sta->drv_priv; 428f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (__ath9k_htc_check_tx_aggr(priv, ista, tid)) { 429f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ieee80211_start_tx_ba_session(sta, tid, 0); 430f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 431f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ista->tid_state[tid] = AGGR_PROGRESS; 432f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 433f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 434f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 435f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 436f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan 437f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan rcu_read_unlock(); 438f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan} 439729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 440f2820f4583b233827f10d91adea70225e196d852Sujith Manoharanstatic void ath9k_htc_tx_process(struct ath9k_htc_priv *priv, 44127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff *skb, 44227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct __wmi_event_txstatus *txs) 443f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{ 444f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_vif *vif; 445f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 446f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ieee80211_tx_info *tx_info; 44727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct ieee80211_tx_rate *rate; 44827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct ieee80211_conf *cur_conf = &priv->hw->conf; 449f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan bool txok; 450f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan int slot; 451d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa int hdrlen, padsize; 452729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan 453f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan slot = strip_drv_header(priv, skb); 454f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (slot < 0) { 455f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan dev_kfree_skb_any(skb); 456f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan return; 457f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan } 4582299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan 459f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tx_ctl = HTC_SKB_CB(skb); 460f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan txok = tx_ctl->txok; 461f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan tx_info = IEEE80211_SKB_CB(skb); 462f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan vif = tx_info->control.vif; 46327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate = &tx_info->status.rates[0]; 464fb9987d0f748c983bb795a86f47522313f701a08Sujith 465f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan memset(&tx_info->status, 0, sizeof(tx_info->status)); 466ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 467f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan /* 468f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan * URB submission failed for this frame, it never reached 469f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan * the target. 470f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan */ 47127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (!txok || !vif || !txs) 472f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan goto send_mac80211; 473ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 47427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_ACK) 47527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan tx_info->flags |= IEEE80211_TX_STAT_ACK; 47627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 47727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_FILT) 47827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan tx_info->flags |= IEEE80211_TX_STAT_TX_FILTERED; 47927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 48027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_RTC_CTS) 48127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->flags |= IEEE80211_TX_RC_USE_RTS_CTS; 48227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 48327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->count = 1; 48427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->idx = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_RATE); 48527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 48627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_MCS) { 48727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->flags |= IEEE80211_TX_RC_MCS; 48827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 48927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_CW40) 49027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH; 49127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (txs->ts_flags & ATH9K_HTC_TXSTAT_SGI) 49227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->flags |= IEEE80211_TX_RC_SHORT_GI; 49327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } else { 494675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan if (cur_conf->chandef.chan->band == IEEE80211_BAND_5GHZ) 49527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan rate->idx += 4; /* No CCK rates */ 49627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 497fb9987d0f748c983bb795a86f47522313f701a08Sujith 498f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ath9k_htc_check_tx_aggr(priv, vif, skb); 499fb9987d0f748c983bb795a86f47522313f701a08Sujith 500f2820f4583b233827f10d91adea70225e196d852Sujith Manoharansend_mac80211: 501f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 502f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan if (WARN_ON(--priv->tx.queued_cnt < 0)) 503f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan priv->tx.queued_cnt = 0; 504f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 505fb9987d0f748c983bb795a86f47522313f701a08Sujith 506f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ath9k_htc_tx_clear_slot(priv, slot); 507fb9987d0f748c983bb795a86f47522313f701a08Sujith 508d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa /* Remove padding before handing frame back to mac80211 */ 509d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa hdrlen = ieee80211_get_hdrlen_from_skb(skb); 510d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa 511d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa padsize = hdrlen & 3; 512d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa if (padsize && skb->len > hdrlen + padsize) { 513d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa memmove(skb->data + padsize, skb->data, hdrlen); 514d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa skb_pull(skb, padsize); 515d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa } 516d2e9fc141e2aa21f4b35ee27072d84e9aa6e2ba0Helmut Schaa 517f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan /* Send status to mac80211 */ 518f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan ieee80211_tx_status(priv->hw, skb); 519f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan} 5208e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan 52127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline void ath9k_htc_tx_drainq(struct ath9k_htc_priv *priv, 52227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff_head *queue) 52327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{ 52427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff *skb; 52527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 52627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan while ((skb = skb_dequeue(queue)) != NULL) { 52727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_process(priv, skb, NULL); 52827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 52927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan} 53027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 531b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharanvoid ath9k_htc_tx_drain(struct ath9k_htc_priv *priv) 532b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan{ 533859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath9k_htc_tx_event *event, *tmp; 534859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 53527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 53627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan priv->tx.flags |= ATH9K_HTC_OP_TX_DRAIN; 53727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 538b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 539b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan /* 540b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan * Ensure that all pending TX frames are flushed, 54127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan * and that the TX completion/failed tasklets is killed. 542b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan */ 543b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan htc_stop(priv->htc); 54427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan tasklet_kill(&priv->wmi->wmi_event_tasklet); 54527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan tasklet_kill(&priv->tx_failed_tasklet); 546b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 54727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.mgmt_ep_queue); 54827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.cab_ep_queue); 54927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.data_be_queue); 55027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.data_bk_queue); 55127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.data_vi_queue); 55227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.data_vo_queue); 55327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); 554b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 555859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan /* 556859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan * The TX cleanup timer has already been killed. 557859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan */ 558859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_lock_bh(&priv->wmi->event_lock); 559859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { 560859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_del(&event->list); 561859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan kfree(event); 562859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 563859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_unlock_bh(&priv->wmi->event_lock); 564859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 56527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 56627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan priv->tx.flags &= ~ATH9K_HTC_OP_TX_DRAIN; 56727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 568b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan} 569b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 57027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanvoid ath9k_tx_failed_tasklet(unsigned long data) 571f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan{ 572f2820f4583b233827f10d91adea70225e196d852Sujith Manoharan struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 5732c5d57f004673a9c8658e20b1fa3f992b5a10f70Sujith Manoharan 57427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_lock_bh(&priv->tx.tx_lock); 57527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (priv->tx.flags & ATH9K_HTC_OP_TX_DRAIN) { 57627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 57727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return; 57827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 57927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_bh(&priv->tx.tx_lock); 58027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 58127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_drainq(priv, &priv->tx.tx_failed); 58227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan} 58327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 58427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic inline bool check_cookie(struct ath9k_htc_priv *priv, 58527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff *skb, 58627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan u8 cookie, u8 epid) 58727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{ 58827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan u8 fcookie = 0; 58927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 59027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (epid == priv->mgmt_ep) { 59127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct tx_mgmt_hdr *hdr; 59227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan hdr = (struct tx_mgmt_hdr *) skb->data; 59327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan fcookie = hdr->cookie; 59427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } else if ((epid == priv->data_bk_ep) || 59527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan (epid == priv->data_be_ep) || 59627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan (epid == priv->data_vi_ep) || 59727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan (epid == priv->data_vo_ep) || 59827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan (epid == priv->cab_ep)) { 59927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct tx_frame_hdr *hdr; 60027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan hdr = (struct tx_frame_hdr *) skb->data; 60127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan fcookie = hdr->cookie; 60227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 60327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 60427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (fcookie == cookie) 60527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return true; 60627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 60727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return false; 60827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan} 60927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 61027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanstatic struct sk_buff* ath9k_htc_tx_get_packet(struct ath9k_htc_priv *priv, 61127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct __wmi_event_txstatus *txs) 61227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{ 61327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 61427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff_head *epid_queue; 61527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff *skb, *tmp; 61627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan unsigned long flags; 61727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan u8 epid = MS(txs->ts_rate, ATH9K_HTC_TXSTAT_EPID); 61827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 61927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = get_htc_epid_queue(priv, epid); 62027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (!epid_queue) 62127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return NULL; 62227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 62327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_lock_irqsave(&epid_queue->lock, flags); 62427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_walk_safe(epid_queue, skb, tmp) { 62527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (check_cookie(priv, skb, txs->cookie, epid)) { 62627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan __skb_unlink(skb, epid_queue); 62727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_irqrestore(&epid_queue->lock, flags); 62827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return skb; 62927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 630fb9987d0f748c983bb795a86f47522313f701a08Sujith } 63127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan spin_unlock_irqrestore(&epid_queue->lock, flags); 63227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 633d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches ath_dbg(common, XMIT, "No matching packet for cookie: %d, epid: %d\n", 63427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan txs->cookie, epid); 6357757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith 63627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return NULL; 63727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan} 63827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 63927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharanvoid ath9k_htc_txstatus(struct ath9k_htc_priv *priv, void *wmi_event) 64027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan{ 64127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct wmi_event_txstatus *txs = (struct wmi_event_txstatus *)wmi_event; 64227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct __wmi_event_txstatus *__txs; 64327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff *skb; 644859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath9k_htc_tx_event *tx_pend; 64527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan int i; 64627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 64727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan for (i = 0; i < txs->cnt; i++) { 64827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan WARN_ON(txs->cnt > HTC_MAX_TX_STATUS); 64927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 65027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan __txs = &txs->txstatus[i]; 65127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 65227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb = ath9k_htc_tx_get_packet(priv, __txs); 653859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (!skb) { 654859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan /* 655859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan * Store this event, so that the TX cleanup 656859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan * routine can check later for the needed packet. 657859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan */ 658859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan tx_pend = kzalloc(sizeof(struct ath9k_htc_tx_event), 659859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan GFP_ATOMIC); 660859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (!tx_pend) 661859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan continue; 662859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 663859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan memcpy(&tx_pend->txs, __txs, 664859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan sizeof(struct __wmi_event_txstatus)); 665859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 666859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_lock(&priv->wmi->event_lock); 667859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_add_tail(&tx_pend->list, 668859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan &priv->wmi->pending_tx_events); 669859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_unlock(&priv->wmi->event_lock); 670859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 67127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan continue; 672859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 67327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 67427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan ath9k_htc_tx_process(priv, skb, __txs); 675b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan } 676b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 6777757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith /* Wake TX queues if needed */ 6788e86a54715c4102a8ed697939de9ebd9715dc59cSujith Manoharan ath9k_htc_check_wake_queues(priv); 679fb9987d0f748c983bb795a86f47522313f701a08Sujith} 680fb9987d0f748c983bb795a86f47522313f701a08Sujith 681fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 682fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id, bool txok) 683fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 684fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; 685729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 68627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan struct sk_buff_head *epid_queue; 687fb9987d0f748c983bb795a86f47522313f701a08Sujith 688729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl = HTC_SKB_CB(skb); 689729bd3ab460d3bb8236cc8f6fd0289201124112dSujith Manoharan tx_ctl->txok = txok; 690859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan tx_ctl->timestamp = jiffies; 691fb9987d0f748c983bb795a86f47522313f701a08Sujith 69227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (!txok) { 693b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan skb_queue_tail(&priv->tx.tx_failed, skb); 69427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan tasklet_schedule(&priv->tx_failed_tasklet); 69527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return; 69627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 69727876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan 69827876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan epid_queue = get_htc_epid_queue(priv, ep_id); 69927876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan if (!epid_queue) { 70027876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan dev_kfree_skb_any(skb); 70127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan return; 70227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan } 703b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan 70427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_tail(epid_queue, skb); 705fb9987d0f748c983bb795a86f47522313f701a08Sujith} 706fb9987d0f748c983bb795a86f47522313f701a08Sujith 707859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanstatic inline bool check_packet(struct ath9k_htc_priv *priv, struct sk_buff *skb) 708859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{ 709859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 710859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath9k_htc_tx_ctl *tx_ctl; 711859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 712859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan tx_ctl = HTC_SKB_CB(skb); 713859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 714859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (time_after(jiffies, 715859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan tx_ctl->timestamp + 716859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan msecs_to_jiffies(ATH9K_HTC_TX_TIMEOUT_INTERVAL))) { 717d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches ath_dbg(common, XMIT, "Dropping a packet due to TX timeout\n"); 718859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan return true; 719859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 720859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 721859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan return false; 722859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan} 723859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 724859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanstatic void ath9k_htc_tx_cleanup_queue(struct ath9k_htc_priv *priv, 725859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct sk_buff_head *epid_queue) 726859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{ 727859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan bool process = false; 728859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan unsigned long flags; 729859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct sk_buff *skb, *tmp; 730859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct sk_buff_head queue; 731859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 732859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan skb_queue_head_init(&queue); 733859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 734859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_lock_irqsave(&epid_queue->lock, flags); 735859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan skb_queue_walk_safe(epid_queue, skb, tmp) { 736859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (check_packet(priv, skb)) { 737859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan __skb_unlink(skb, epid_queue); 738859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan __skb_queue_tail(&queue, skb); 739859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan process = true; 740859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 741859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 742859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_unlock_irqrestore(&epid_queue->lock, flags); 743859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 744859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (process) { 745859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan skb_queue_walk_safe(&queue, skb, tmp) { 746859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan __skb_unlink(skb, &queue); 747859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_process(priv, skb, NULL); 748859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 749859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 750859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan} 751859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 752859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharanvoid ath9k_htc_tx_cleanup_timer(unsigned long data) 753859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan{ 754859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) data; 755859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath_common *common = ath9k_hw_common(priv->ah); 756859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct ath9k_htc_tx_event *event, *tmp; 757859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan struct sk_buff *skb; 758859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 759859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_lock(&priv->wmi->event_lock); 760859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_for_each_entry_safe(event, tmp, &priv->wmi->pending_tx_events, list) { 761859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 762859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan skb = ath9k_htc_tx_get_packet(priv, &event->txs); 763859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (skb) { 764d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches ath_dbg(common, XMIT, 765859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan "Found packet for cookie: %d, epid: %d\n", 766859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan event->txs.cookie, 767859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan MS(event->txs.ts_rate, ATH9K_HTC_TXSTAT_EPID)); 768859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 769859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_process(priv, skb, &event->txs); 770859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_del(&event->list); 771859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan kfree(event); 772859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan continue; 773859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 774859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 775859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan if (++event->count >= ATH9K_HTC_TX_TIMEOUT_COUNT) { 776859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan list_del(&event->list); 777859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan kfree(event); 778859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 779859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan } 780859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan spin_unlock(&priv->wmi->event_lock); 781859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 782859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan /* 783859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan * Check if status-pending packets have to be cleaned up. 784859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan */ 785859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.mgmt_ep_queue); 786859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.cab_ep_queue); 787859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_be_queue); 788859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_bk_queue); 789859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vi_queue); 790859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_tx_cleanup_queue(priv, &priv->tx.data_vo_queue); 791859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 792859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan /* Wake TX queues if needed */ 793859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan ath9k_htc_check_wake_queues(priv); 794859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 795859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan mod_timer(&priv->tx.cleanup_timer, 796859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan jiffies + msecs_to_jiffies(ATH9K_HTC_TX_CLEANUP_INTERVAL)); 797859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan} 798859c3ca1e4608615788dc6cbc199210fe4b5efa2Sujith Manoharan 799fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv) 800fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 80127876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.mgmt_ep_queue); 80227876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.cab_ep_queue); 80327876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.data_be_queue); 80427876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.data_bk_queue); 80527876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.data_vi_queue); 80627876a29de221186c9d5883e5fe5f6da18ef9a45Sujith Manoharan skb_queue_head_init(&priv->tx.data_vo_queue); 807b587fc81a80b9656f64e89fe0a106ffa4b35abcaSujith Manoharan skb_queue_head_init(&priv->tx.tx_failed); 808fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 809fb9987d0f748c983bb795a86f47522313f701a08Sujith} 810fb9987d0f748c983bb795a86f47522313f701a08Sujith 811fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv) 812fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 813fb9987d0f748c983bb795a86f47522313f701a08Sujith 814fb9987d0f748c983bb795a86f47522313f701a08Sujith} 815fb9987d0f748c983bb795a86f47522313f701a08Sujith 816e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) 817fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 818fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 819fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 820fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 821fb9987d0f748c983bb795a86f47522313f701a08Sujith int qnum; 822fb9987d0f748c983bb795a86f47522313f701a08Sujith 823fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&qi, 0, sizeof(qi)); 824ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(subtype); 825fb9987d0f748c983bb795a86f47522313f701a08Sujith 826fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); 827fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum == -1) 828fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 829fb9987d0f748c983bb795a86f47522313f701a08Sujith 830fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum >= ARRAY_SIZE(priv->hwq_map)) { 8313800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "qnum %u out of range, max %zu!\n", 8323800276a40751539a920ef8e0537ef2e19126799Joe Perches qnum, ARRAY_SIZE(priv->hwq_map)); 833fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_releasetxqueue(ah, qnum); 834fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 835fb9987d0f748c983bb795a86f47522313f701a08Sujith } 836fb9987d0f748c983bb795a86f47522313f701a08Sujith 837fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[subtype] = qnum; 838fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 839fb9987d0f748c983bb795a86f47522313f701a08Sujith} 840fb9987d0f748c983bb795a86f47522313f701a08Sujith 841ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) 842ca74b83b66dbd289a395c6243695d746c76676ccSujith{ 843ca74b83b66dbd289a395c6243695d746c76676ccSujith struct ath9k_tx_queue_info qi; 844ca74b83b66dbd289a395c6243695d746c76676ccSujith 845ca74b83b66dbd289a395c6243695d746c76676ccSujith memset(&qi, 0, sizeof(qi)); 846ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(0); 847ca74b83b66dbd289a395c6243695d746c76676ccSujith 848ca74b83b66dbd289a395c6243695d746c76676ccSujith return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi); 849ca74b83b66dbd289a395c6243695d746c76676ccSujith} 850ca74b83b66dbd289a395c6243695d746c76676ccSujith 851fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 852fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */ 853fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 854fb9987d0f748c983bb795a86f47522313f701a08Sujith 8550995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 8560995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW. 8570995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 8580995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) 8590995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 8600995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) 8610995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8620995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 8630995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt; 8640995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8650995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) 8660995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST 8670995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_MCAST; 8680995d110118b35c0dc5195e3ddddcc0dec263830Sujith 86994a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan if (priv->rxfilter & FIF_PROBE_REQ) 8700995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROBEREQ; 8710995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8720995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* 8730995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station 8740995d110118b35c0dc5195e3ddddcc0dec263830Sujith * mode interface or when in monitor mode. AP mode does not need this 8750995d110118b35c0dc5195e3ddddcc0dec263830Sujith * since it receives all in-BSS frames anyway. 8760995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 8770995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (((ah->opmode != NL80211_IFTYPE_AP) && 8780995d110118b35c0dc5195e3ddddcc0dec263830Sujith (priv->rxfilter & FIF_PROMISC_IN_BSS)) || 8794825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan ah->is_monitoring) 8800995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROM; 8810995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8820995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (priv->rxfilter & FIF_CONTROL) 8830995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_CONTROL; 8840995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8850995d110118b35c0dc5195e3ddddcc0dec263830Sujith if ((ah->opmode == NL80211_IFTYPE_STATION) && 88633a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan (priv->nvifs <= 1) && 8870995d110118b35c0dc5195e3ddddcc0dec263830Sujith !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) 8880995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_MYBEACON; 8890995d110118b35c0dc5195e3ddddcc0dec263830Sujith else 8900995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_BEACON; 8910995d110118b35c0dc5195e3ddddcc0dec263830Sujith 8924825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (conf_is_ht(&priv->hw->conf)) { 8930995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_COMP_BAR; 8944825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; 8954825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan } 8964825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan 8974825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (priv->rxfilter & FIF_PSPOLL) 8984825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_PSPOLL; 8990995d110118b35c0dc5195e3ddddcc0dec263830Sujith 900594e65b633e0b76db1d8e7359e4efb2d60fba20dJavier Cardona if (priv->nvifs > 1 || priv->rxfilter & FIF_OTHER_BSS) 90133a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL; 90233a5315f97e5b3964183f0cf74768ac47eabe631Sujith Manoharan 9030995d110118b35c0dc5195e3ddddcc0dec263830Sujith return rfilt; 9040995d110118b35c0dc5195e3ddddcc0dec263830Sujith 9050995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE 9060995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 9070995d110118b35c0dc5195e3ddddcc0dec263830Sujith 9080995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 9090995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change. 9100995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 9110995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) 9120995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 9130995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 9140995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt, mfilt[2]; 9150995d110118b35c0dc5195e3ddddcc0dec263830Sujith 9160995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure rx filter */ 9170995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = ath9k_htc_calcrxfilter(priv); 9180995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setrxfilter(ah, rfilt); 9190995d110118b35c0dc5195e3ddddcc0dec263830Sujith 9200995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* calculate and install multicast filter */ 9210995d110118b35c0dc5195e3ddddcc0dec263830Sujith mfilt[0] = mfilt[1] = ~0; 9220995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 9230995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 9240995d110118b35c0dc5195e3ddddcc0dec263830Sujith 925fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv) 926fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 927fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_rxena(priv->ah); 9280995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_htc_opmode_init(priv); 929d8a2c51cdcaee0131c88f49d64b84f1c7361d72cSujith Manoharan ath9k_hw_startpcureceive(priv->ah, test_bit(OP_SCANNING, &priv->op_flags)); 930fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; 931fb9987d0f748c983bb795a86f47522313f701a08Sujith} 932fb9987d0f748c983bb795a86f47522313f701a08Sujith 933fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw, 934fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rxs, 935fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 rx_rate, u8 rs_flags) 936fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 937fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_supported_band *sband; 938fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ieee80211_band band; 939fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned int i = 0; 940fb9987d0f748c983bb795a86f47522313f701a08Sujith 941fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rx_rate & 0x80) { 942fb9987d0f748c983bb795a86f47522313f701a08Sujith /* HT rate */ 943fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_HT; 944fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_2040) 945fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_40MHZ; 946fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_GI) 947fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORT_GI; 948fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = rx_rate & 0x7f; 949fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 950fb9987d0f748c983bb795a86f47522313f701a08Sujith } 951fb9987d0f748c983bb795a86f47522313f701a08Sujith 952675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan band = hw->conf.chandef.chan->band; 953fb9987d0f748c983bb795a86f47522313f701a08Sujith sband = hw->wiphy->bands[band]; 954fb9987d0f748c983bb795a86f47522313f701a08Sujith 955fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < sband->n_bitrates; i++) { 956fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value == rx_rate) { 957fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 958fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 959fb9987d0f748c983bb795a86f47522313f701a08Sujith } 960fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value_short == rx_rate) { 961fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 962fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORTPRE; 963fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 964fb9987d0f748c983bb795a86f47522313f701a08Sujith } 965fb9987d0f748c983bb795a86f47522313f701a08Sujith } 966fb9987d0f748c983bb795a86f47522313f701a08Sujith 967fb9987d0f748c983bb795a86f47522313f701a08Sujith} 968fb9987d0f748c983bb795a86f47522313f701a08Sujith 9691f83b0492939ec94bcab868f338139a7de521863Oleksij Rempelstatic inline void convert_htc_flag(struct ath_rx_status *rx_stats, 9701f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel struct ath_htc_rx_status *rxstatus) 9711f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel{ 9721f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->flag = 0; 9731f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel if (rxstatus->rs_flags & ATH9K_RX_2040) 9741f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->flag |= RX_FLAG_40MHZ; 9751f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel if (rxstatus->rs_flags & ATH9K_RX_GI) 9761f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->flag |= RX_FLAG_SHORT_GI; 9771f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel} 9781f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel 9791f83b0492939ec94bcab868f338139a7de521863Oleksij Rempelstatic void rx_status_htc_to_ath(struct ath_rx_status *rx_stats, 9801f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel struct ath_htc_rx_status *rxstatus) 9811f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel{ 9821f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_datalen = rxstatus->rs_datalen; 9831f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_status = rxstatus->rs_status; 9841f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_phyerr = rxstatus->rs_phyerr; 9851f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_rssi = rxstatus->rs_rssi; 9861f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_keyix = rxstatus->rs_keyix; 9871f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_rate = rxstatus->rs_rate; 9881f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_antenna = rxstatus->rs_antenna; 9891f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_more = rxstatus->rs_more; 9901f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel 9911f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel memcpy(rx_stats->rs_rssi_ctl, rxstatus->rs_rssi_ctl, 9921f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel sizeof(rx_stats->rs_rssi_ctl)); 9931f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel memcpy(rx_stats->rs_rssi_ext, rxstatus->rs_rssi_ext, 9941f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel sizeof(rx_stats->rs_rssi_ext)); 9951f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel 9961f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_isaggr = rxstatus->rs_isaggr; 9971f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_moreaggr = rxstatus->rs_moreaggr; 9981f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_stats->rs_num_delims = rxstatus->rs_num_delims; 9991f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel convert_htc_flag(rx_stats, rxstatus); 10001f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel} 10011f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel 1002fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, 1003fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, 1004fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rx_status) 1005fb9987d0f748c983bb795a86f47522313f701a08Sujith 1006fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 1007fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 1008fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 1009fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = rxbuf->skb; 1010fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 10114f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith struct ath_htc_rx_status *rxstatus; 10121f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel struct ath_rx_status rx_stats; 1013c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau int hdrlen, padsize; 1014fb9987d0f748c983bb795a86f47522313f701a08Sujith int last_rssi = ATH_RSSI_DUMMY_MARKER; 1015fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 1016fb9987d0f748c983bb795a86f47522313f701a08Sujith 1017b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { 1018b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", 1019b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan skb->len); 10204f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 10214f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 10224f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 10234f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith rxstatus = (struct ath_htc_rx_status *)skb->data; 10244f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 10254f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith if (be16_to_cpu(rxstatus->rs_datalen) - 10264f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { 10273800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, 10283800276a40751539a920ef8e0537ef2e19126799Joe Perches "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", 10293800276a40751539a920ef8e0537ef2e19126799Joe Perches rxstatus->rs_datalen, skb->len); 10304f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 10314f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 10324f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 1033719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan ath9k_htc_err_stat_rx(priv, rxstatus); 1034719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan 10354f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith /* Get the RX status information */ 10364f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); 10374f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); 10384f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 1039fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *)skb->data; 1040fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 1041fb9987d0f748c983bb795a86f47522313f701a08Sujith hdrlen = ieee80211_get_hdrlen_from_skb(skb); 1042fb9987d0f748c983bb795a86f47522313f701a08Sujith 1043c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau padsize = hdrlen & 3; 1044c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau if (padsize && skb->len >= hdrlen+padsize+FCS_LEN) { 1045c60c99298c50b698b0bbbe0e0146c965c322b8c1Felix Fietkau memmove(skb->data + padsize, skb->data, hdrlen); 1046fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, padsize); 1047fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1048fb9987d0f748c983bb795a86f47522313f701a08Sujith 1049fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); 1050fb9987d0f748c983bb795a86f47522313f701a08Sujith 10511f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel rx_status_htc_to_ath(&rx_stats, &rxbuf->rxstatus); 10521f83b0492939ec94bcab868f338139a7de521863Oleksij Rempel 1053fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status != 0) { 1054fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) 1055fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 1056fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) 1057fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 1058fb9987d0f748c983bb795a86f47522313f701a08Sujith 1059fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { 1060fb9987d0f748c983bb795a86f47522313f701a08Sujith /* FIXME */ 1061fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { 1062fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_ctl(fc)) 1063fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 1064fb9987d0f748c983bb795a86f47522313f701a08Sujith * Sometimes, we get invalid 1065fb9987d0f748c983bb795a86f47522313f701a08Sujith * MIC failures on valid control frames. 1066fb9987d0f748c983bb795a86f47522313f701a08Sujith * Remove these mic errors. 1067fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 1068fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; 1069fb9987d0f748c983bb795a86f47522313f701a08Sujith else 1070fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_MMIC_ERROR; 1071fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1072fb9987d0f748c983bb795a86f47522313f701a08Sujith 1073fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 1074fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reject error frames with the exception of 1075fb9987d0f748c983bb795a86f47522313f701a08Sujith * decryption and MIC failures. For monitor mode, 1076fb9987d0f748c983bb795a86f47522313f701a08Sujith * we also ignore the CRC error. 1077fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 1078fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { 1079fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 1080fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 1081fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH9K_RXERR_CRC)) 1082fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 1083fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 1084fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 1085fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 1086fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 1087fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1088fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1089fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1090fb9987d0f748c983bb795a86f47522313f701a08Sujith 1091fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { 1092fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 keyix; 1093fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = rxbuf->rxstatus.rs_keyix; 1094fb9987d0f748c983bb795a86f47522313f701a08Sujith if (keyix != ATH9K_RXKEYIX_INVALID) { 1095fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 1096fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (ieee80211_has_protected(fc) && 1097fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len >= hdrlen + 4) { 1098fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = skb->data[hdrlen + 3] >> 6; 1099fb9987d0f748c983bb795a86f47522313f701a08Sujith if (test_bit(keyix, common->keymap)) 1100fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 1101fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1102fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1103fb9987d0f748c983bb795a86f47522313f701a08Sujith 1104fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, 1105fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_flags); 1106fb9987d0f748c983bb795a86f47522313f701a08Sujith 11077c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && 11087c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan !rxbuf->rxstatus.rs_moreaggr) 11097c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan ATH_RSSI_LPF(priv->rx.last_rssi, 11107c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi); 1111fb9987d0f748c983bb795a86f47522313f701a08Sujith 11127c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan last_rssi = priv->rx.last_rssi; 1113fb9987d0f748c983bb795a86f47522313f701a08Sujith 1114aeb0e356ec6e0d11b8369bbbb32ae81b92a1a46bOleksij Rempel if (ath_is_mybeacon(common, hdr)) { 1115838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau s8 rssi = rxbuf->rxstatus.rs_rssi; 1116fb9987d0f748c983bb795a86f47522313f701a08Sujith 1117838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 1118838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau rssi = ATH_EP_RND(last_rssi, ATH_RSSI_EP_MULTIPLIER); 1119fb9987d0f748c983bb795a86f47522313f701a08Sujith 1120838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau if (rssi < 0) 1121838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau rssi = 0; 1122838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau 1123838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau priv->ah->stats.avgbrssi = rssi; 1124838f427955dcfd16858b0108ce29029da0d56a4eFelix Fietkau } 1125fb9987d0f748c983bb795a86f47522313f701a08Sujith 11267f1f5a0060e377ff6a15903487b39223e12b8568Sujith rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); 1127675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan rx_status->band = hw->conf.chandef.chan->band; 1128675a0b049abf6edf30f8dd84c5610b6edc2296c8Karl Beldan rx_status->freq = hw->conf.chandef.chan->center_freq; 1129fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 1130fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->antenna = rxbuf->rxstatus.rs_antenna; 113175d7dbc280bb75d2bdce59c5969a812f38255f54Thomas Pedersen rx_status->flag |= RX_FLAG_MACTIME_END; 1132fb9987d0f748c983bb795a86f47522313f701a08Sujith 1133fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 1134fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next: 1135fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 1136fb9987d0f748c983bb795a86f47522313f701a08Sujith} 1137fb9987d0f748c983bb795a86f47522313f701a08Sujith 1138fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 1139fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on. 1140fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 1141fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data) 1142fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 1143fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 1144fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 1145fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status rx_status; 1146fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb; 1147fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned long flags; 1148bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan struct ieee80211_hdr *hdr; 1149fb9987d0f748c983bb795a86f47522313f701a08Sujith 1150fb9987d0f748c983bb795a86f47522313f701a08Sujith do { 1151fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 1152fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 1153fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tmp_buf->in_process) { 1154fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 1155fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 1156fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1157fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1158fb9987d0f748c983bb795a86f47522313f701a08Sujith 1159fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 1160fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 1161fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 1162fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1163fb9987d0f748c983bb795a86f47522313f701a08Sujith 1164fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!rxbuf->skb) 1165fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 1166fb9987d0f748c983bb795a86f47522313f701a08Sujith 1167fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { 1168fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 1169fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 1170fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1171fb9987d0f748c983bb795a86f47522313f701a08Sujith 1172fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, 1173fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct ieee80211_rx_status)); 1174fb9987d0f748c983bb795a86f47522313f701a08Sujith skb = rxbuf->skb; 1175bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan hdr = (struct ieee80211_hdr *) skb->data; 1176bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 1177bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) 1178bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan ieee80211_queue_work(priv->hw, &priv->ps_work); 1179bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 1180fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 1181fb9987d0f748c983bb795a86f47522313f701a08Sujith 1182fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_rx(priv->hw, skb); 1183fb9987d0f748c983bb795a86f47522313f701a08Sujith 1184fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 1185fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue: 1186fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = false; 1187fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = NULL; 1188fb9987d0f748c983bb795a86f47522313f701a08Sujith list_move_tail(&rxbuf->list, &priv->rx.rxbuf); 1189fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = NULL; 1190fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 1191fb9987d0f748c983bb795a86f47522313f701a08Sujith } while (1); 1192fb9987d0f748c983bb795a86f47522313f701a08Sujith 1193fb9987d0f748c983bb795a86f47522313f701a08Sujith} 1194fb9987d0f748c983bb795a86f47522313f701a08Sujith 1195fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 1196fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id) 1197fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 1198fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; 1199fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 1200fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 1201fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 1202fb9987d0f748c983bb795a86f47522313f701a08Sujith 1203fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 1204fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 1205fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!tmp_buf->in_process) { 1206fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 1207fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 1208fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1209fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1210fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 1211fb9987d0f748c983bb795a86f47522313f701a08Sujith 1212fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 1213d2182b69dcb6a68b1ef6070b2efd094e13dea3f1Joe Perches ath_dbg(common, ANY, "No free RX buffer\n"); 1214fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 1215fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1216fb9987d0f748c983bb795a86f47522313f701a08Sujith 1217fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 1218fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = skb; 1219fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = true; 1220fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 1221fb9987d0f748c983bb795a86f47522313f701a08Sujith 1222fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->rx_tasklet); 1223fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 1224fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 1225fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(skb); 1226fb9987d0f748c983bb795a86f47522313f701a08Sujith} 1227fb9987d0f748c983bb795a86f47522313f701a08Sujith 1228fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */ 1229fb9987d0f748c983bb795a86f47522313f701a08Sujith 1230fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv) 1231fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 1232fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, *tbuf; 1233fb9987d0f748c983bb795a86f47522313f701a08Sujith 1234fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { 1235fb9987d0f748c983bb795a86f47522313f701a08Sujith list_del(&rxbuf->list); 1236fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->skb) 1237fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 1238fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(rxbuf); 1239fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1240fb9987d0f748c983bb795a86f47522313f701a08Sujith} 1241fb9987d0f748c983bb795a86f47522313f701a08Sujith 1242fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv) 1243fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 1244fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 1245fb9987d0f748c983bb795a86f47522313f701a08Sujith 1246fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_LIST_HEAD(&priv->rx.rxbuf); 1247fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->rx.rxbuflock); 1248fb9987d0f748c983bb795a86f47522313f701a08Sujith 1249fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ATH9K_HTC_RXBUF; i++) { 125014f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches struct ath9k_htc_rxbuf *rxbuf = 125114f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); 125214f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches if (rxbuf == NULL) 1253fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 125414f8dc49532f765968ff37c3b99edbeb99004aceJoe Perches 1255fb9987d0f748c983bb795a86f47522313f701a08Sujith list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 1256fb9987d0f748c983bb795a86f47522313f701a08Sujith } 1257fb9987d0f748c983bb795a86f47522313f701a08Sujith 1258fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 1259fb9987d0f748c983bb795a86f47522313f701a08Sujith 1260fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 1261fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 1262fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 1263fb9987d0f748c983bb795a86f47522313f701a08Sujith} 1264