htc_drv_txrx.c revision b1563a4c3d721cb0496b8e1fb874f08a8f2b62cc
1fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 2fb9987d0f748c983bb795a86f47522313f701a08Sujith * Copyright (c) 2010 Atheros Communications Inc. 3fb9987d0f748c983bb795a86f47522313f701a08Sujith * 4fb9987d0f748c983bb795a86f47522313f701a08Sujith * Permission to use, copy, modify, and/or distribute this software for any 5fb9987d0f748c983bb795a86f47522313f701a08Sujith * purpose with or without fee is hereby granted, provided that the above 6fb9987d0f748c983bb795a86f47522313f701a08Sujith * copyright notice and this permission notice appear in all copies. 7fb9987d0f748c983bb795a86f47522313f701a08Sujith * 8fb9987d0f748c983bb795a86f47522313f701a08Sujith * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9fb9987d0f748c983bb795a86f47522313f701a08Sujith * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10fb9987d0f748c983bb795a86f47522313f701a08Sujith * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11fb9987d0f748c983bb795a86f47522313f701a08Sujith * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12fb9987d0f748c983bb795a86f47522313f701a08Sujith * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13fb9987d0f748c983bb795a86f47522313f701a08Sujith * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14fb9987d0f748c983bb795a86f47522313f701a08Sujith * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 16fb9987d0f748c983bb795a86f47522313f701a08Sujith 17fb9987d0f748c983bb795a86f47522313f701a08Sujith#include "htc.h" 18fb9987d0f748c983bb795a86f47522313f701a08Sujith 19fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 20fb9987d0f748c983bb795a86f47522313f701a08Sujith/* TX */ 21fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 22fb9987d0f748c983bb795a86f47522313f701a08Sujith 23066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkaustatic const int subtype_txq_to_hwq[] = { 24066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_BE] = ATH_TXQ_AC_BE, 25066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_BK] = ATH_TXQ_AC_BK, 26066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_VI] = ATH_TXQ_AC_VI, 27066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau [WME_AC_VO] = ATH_TXQ_AC_VO, 28066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau}; 29066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau 30ca74b83b66dbd289a395c6243695d746c76676ccSujith#define ATH9K_HTC_INIT_TXQ(subtype) do { \ 31066dae93bdfcc7af5e38a33617773fd5c6457607Felix Fietkau qi.tqi_subtype = subtype_txq_to_hwq[subtype]; \ 32ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_aifs = ATH9K_TXQ_USEDEFAULT; \ 33ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmin = ATH9K_TXQ_USEDEFAULT; \ 34ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_cwmax = ATH9K_TXQ_USEDEFAULT; \ 35ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_physCompBuf = 0; \ 36ca74b83b66dbd289a395c6243695d746c76676ccSujith qi.tqi_qflags = TXQ_FLAG_TXEOLINT_ENABLE | \ 37ca74b83b66dbd289a395c6243695d746c76676ccSujith TXQ_FLAG_TXDESCINT_ENABLE; \ 38ca74b83b66dbd289a395c6243695d746c76676ccSujith } while (0) 39ca74b83b66dbd289a395c6243695d746c76676ccSujith 40fb9987d0f748c983bb795a86f47522313f701a08Sujithint get_hw_qnum(u16 queue, int *hwq_map) 41fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 42fb9987d0f748c983bb795a86f47522313f701a08Sujith switch (queue) { 43fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 44e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VO]; 45fb9987d0f748c983bb795a86f47522313f701a08Sujith case 1: 46e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_VI]; 47fb9987d0f748c983bb795a86f47522313f701a08Sujith case 2: 48e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 49fb9987d0f748c983bb795a86f47522313f701a08Sujith case 3: 50e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BK]; 51fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 52e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkau return hwq_map[WME_AC_BE]; 53fb9987d0f748c983bb795a86f47522313f701a08Sujith } 54fb9987d0f748c983bb795a86f47522313f701a08Sujith} 55fb9987d0f748c983bb795a86f47522313f701a08Sujith 56e1572c5eeca8ef87a250322364584458b2dadb35Sujithint ath_htc_txq_update(struct ath9k_htc_priv *priv, int qnum, 57e1572c5eeca8ef87a250322364584458b2dadb35Sujith struct ath9k_tx_queue_info *qinfo) 58fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 59fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 60fb9987d0f748c983bb795a86f47522313f701a08Sujith int error = 0; 61fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 62fb9987d0f748c983bb795a86f47522313f701a08Sujith 63fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_get_txq_props(ah, qnum, &qi); 64fb9987d0f748c983bb795a86f47522313f701a08Sujith 65fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_aifs = qinfo->tqi_aifs; 66fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmin = qinfo->tqi_cwmin / 2; /* XXX */ 67fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_cwmax = qinfo->tqi_cwmax; 68fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_burstTime = qinfo->tqi_burstTime; 69fb9987d0f748c983bb795a86f47522313f701a08Sujith qi.tqi_readyTime = qinfo->tqi_readyTime; 70fb9987d0f748c983bb795a86f47522313f701a08Sujith 71fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_hw_set_txq_props(ah, qnum, &qi)) { 723800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(ath9k_hw_common(ah), 733800276a40751539a920ef8e0537ef2e19126799Joe Perches "Unable to update hardware queue %u!\n", qnum); 74fb9987d0f748c983bb795a86f47522313f701a08Sujith error = -EIO; 75fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 76fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_resettxqueue(ah, qnum); 77fb9987d0f748c983bb795a86f47522313f701a08Sujith } 78fb9987d0f748c983bb795a86f47522313f701a08Sujith 79fb9987d0f748c983bb795a86f47522313f701a08Sujith return error; 80fb9987d0f748c983bb795a86f47522313f701a08Sujith} 81fb9987d0f748c983bb795a86f47522313f701a08Sujith 827d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharanint ath9k_htc_tx_start(struct ath9k_htc_priv *priv, 837d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan struct sk_buff *skb, bool is_cab) 84fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 85fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 869b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan struct ieee80211_mgmt *mgmt; 87fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 88fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta = tx_info->control.sta; 89a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan struct ieee80211_vif *vif = tx_info->control.vif; 90fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 919b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan struct ath9k_htc_vif *avp = NULL; 92fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_tx_ctl tx_ctl; 93fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id epid; 94b80841c91f42dc048a60bff5e1614a619f725e38Sujith u16 qnum; 95fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 96fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *tx_fhdr; 97da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan u8 sta_idx, vif_idx; 98fb9987d0f748c983bb795a86f47522313f701a08Sujith 99fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 100fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 101fb9987d0f748c983bb795a86f47522313f701a08Sujith 102a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 103a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out on which interface this packet has to be 104a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * sent out. 105a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 106a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (vif) { 107a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan avp = (struct ath9k_htc_vif *) vif->drv_priv; 108a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = avp->index; 109a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } else { 110a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan if (!priv->ah->is_monitoring) { 111a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 112a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan "VIF is null, but no monitor interface !\n"); 113a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan return -EINVAL; 114a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 115a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan 116a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan vif_idx = priv->mon_vif_idx; 117a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan } 118da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan 119a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan /* 120a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan * Find out which station this packet is destined for. 121a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan */ 122fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta) { 123fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *) sta->drv_priv; 124fb9987d0f748c983bb795a86f47522313f701a08Sujith sta_idx = ista->index; 125fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 126a97b478c92c14255d375ed9ceb7a882083523593Sujith Manoharan sta_idx = priv->vif_sta_pos[vif_idx]; 127fb9987d0f748c983bb795a86f47522313f701a08Sujith } 128fb9987d0f748c983bb795a86f47522313f701a08Sujith 129fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_ctl, 0, sizeof(struct ath9k_htc_tx_ctl)); 130fb9987d0f748c983bb795a86f47522313f701a08Sujith 131fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data(fc)) { 132fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_frame_hdr tx_hdr; 133dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan u32 flags = 0; 134fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc; 135fb9987d0f748c983bb795a86f47522313f701a08Sujith 136fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&tx_hdr, 0, sizeof(struct tx_frame_hdr)); 137fb9987d0f748c983bb795a86f47522313f701a08Sujith 138fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.node_idx = sta_idx; 139da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan tx_hdr.vif_idx = vif_idx; 140fb9987d0f748c983bb795a86f47522313f701a08Sujith 141fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) { 142fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_AMPDU; 143fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_AMPDU; 144fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 145fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 146fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.data_type = ATH9K_HTC_NORMAL; 147fb9987d0f748c983bb795a86f47522313f701a08Sujith } 148fb9987d0f748c983bb795a86f47522313f701a08Sujith 1493bf30b56c4f0a1c4fae34050b7db4527c92891e8Rajkumar Manoharan if (ieee80211_is_data_qos(fc)) { 150fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 151fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.tidno = qc[0] & IEEE80211_QOS_CTL_TID_MASK; 152fb9987d0f748c983bb795a86f47522313f701a08Sujith } 153fb9987d0f748c983bb795a86f47522313f701a08Sujith 154fb9987d0f748c983bb795a86f47522313f701a08Sujith /* Check for RTS protection */ 155fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->hw->wiphy->rts_threshold != (u32) -1) 156fb9987d0f748c983bb795a86f47522313f701a08Sujith if (skb->len > priv->hw->wiphy->rts_threshold) 157dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan flags |= ATH9K_HTC_TX_RTSCTS; 158fb9987d0f748c983bb795a86f47522313f701a08Sujith 159fb9987d0f748c983bb795a86f47522313f701a08Sujith /* CTS-to-self */ 160dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan if (!(flags & ATH9K_HTC_TX_RTSCTS) && 1619304c82d8f3b40eb31c2d04f5849fbd9802c06efSujith Manoharan (vif && vif->bss_conf.use_cts_prot)) 162dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan flags |= ATH9K_HTC_TX_CTSONLY; 163fb9987d0f748c983bb795a86f47522313f701a08Sujith 164dc738cb6c5d5594de4bdf3b7839a250b032152e7Rajkumar Manoharan tx_hdr.flags = cpu_to_be32(flags); 165fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 166fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tx_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 167fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 168fb9987d0f748c983bb795a86f47522313f701a08Sujith else 169fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 170fb9987d0f748c983bb795a86f47522313f701a08Sujith 171fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(tx_hdr)); 172fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &tx_hdr, sizeof(tx_hdr)); 173fb9987d0f748c983bb795a86f47522313f701a08Sujith 1747d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan if (is_cab) { 1757d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan CAB_STAT_INC; 1767d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan epid = priv->cab_ep; 1777d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan goto send; 1787d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan } 1797d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan 180fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = skb_get_queue_mapping(skb); 181fb9987d0f748c983bb795a86f47522313f701a08Sujith 182b80841c91f42dc048a60bff5e1614a619f725e38Sujith switch (qnum) { 183fb9987d0f748c983bb795a86f47522313f701a08Sujith case 0: 184b80841c91f42dc048a60bff5e1614a619f725e38Sujith TX_QSTAT_INC(WME_AC_VO); 185b80841c91f42dc048a60bff5e1614a619f725e38Sujith epid = priv->data_vo_ep; 186fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 187b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 1: 1882edb4583c6a581e1e48af259db2a2d467d11551dSujith TX_QSTAT_INC(WME_AC_VI); 189fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_vi_ep; 190fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 191b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 2: 192b80841c91f42dc048a60bff5e1614a619f725e38Sujith TX_QSTAT_INC(WME_AC_BE); 193b80841c91f42dc048a60bff5e1614a619f725e38Sujith epid = priv->data_be_ep; 194fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 195b80841c91f42dc048a60bff5e1614a619f725e38Sujith case 3: 196fb9987d0f748c983bb795a86f47522313f701a08Sujith default: 1972edb4583c6a581e1e48af259db2a2d467d11551dSujith TX_QSTAT_INC(WME_AC_BK); 198fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->data_bk_ep; 199fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 200fb9987d0f748c983bb795a86f47522313f701a08Sujith } 201fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 202fb9987d0f748c983bb795a86f47522313f701a08Sujith struct tx_mgmt_hdr mgmt_hdr; 203fb9987d0f748c983bb795a86f47522313f701a08Sujith 204fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&mgmt_hdr, 0, sizeof(struct tx_mgmt_hdr)); 205fb9987d0f748c983bb795a86f47522313f701a08Sujith 2069b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan /* 2079b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan * Set the TSF adjust value for probe response 2089b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan * frame also. 2099b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan */ 2109b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan if (avp && unlikely(ieee80211_is_probe_resp(fc))) { 2119b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan mgmt = (struct ieee80211_mgmt *)skb->data; 2129b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan mgmt->u.probe_resp.timestamp = avp->tsfadjust; 2139b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan } 2149b674a0207c9b75ddcdcdb07e46843fac8267507Sujith Manoharan 215fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_ctl.type = ATH9K_HTC_NORMAL; 216fb9987d0f748c983bb795a86f47522313f701a08Sujith 217fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.node_idx = sta_idx; 218da93f10684bfba2983a70c10b5d417232b6a5245Rajkumar Manoharan mgmt_hdr.vif_idx = vif_idx; 219fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.tidno = 0; 220fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.flags = 0; 221fb9987d0f748c983bb795a86f47522313f701a08Sujith 222fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.key_type = ath9k_cmn_get_hw_crypto_keytype(skb); 223fb9987d0f748c983bb795a86f47522313f701a08Sujith if (mgmt_hdr.key_type == ATH9K_KEY_TYPE_CLEAR) 224fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = (u8) ATH9K_TXKEYIX_INVALID; 225fb9987d0f748c983bb795a86f47522313f701a08Sujith else 226fb9987d0f748c983bb795a86f47522313f701a08Sujith mgmt_hdr.keyix = tx_info->control.hw_key->hw_key_idx; 227fb9987d0f748c983bb795a86f47522313f701a08Sujith 228fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_fhdr = skb_push(skb, sizeof(mgmt_hdr)); 229fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(tx_fhdr, (u8 *) &mgmt_hdr, sizeof(mgmt_hdr)); 230fb9987d0f748c983bb795a86f47522313f701a08Sujith epid = priv->mgmt_ep; 231fb9987d0f748c983bb795a86f47522313f701a08Sujith } 2327d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharansend: 233fb9987d0f748c983bb795a86f47522313f701a08Sujith return htc_send(priv->htc, skb, epid, &tx_ctl); 234fb9987d0f748c983bb795a86f47522313f701a08Sujith} 235fb9987d0f748c983bb795a86f47522313f701a08Sujith 236d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujithstatic bool ath9k_htc_check_tx_aggr(struct ath9k_htc_priv *priv, 237d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith struct ath9k_htc_sta *ista, u8 tid) 238d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith{ 239d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith bool ret = false; 240d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 241d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_lock_bh(&priv->tx_lock); 242d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if ((tid < ATH9K_HTC_MAX_TID) && (ista->tid_state[tid] == AGGR_STOP)) 243d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith ret = true; 244d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_unlock_bh(&priv->tx_lock); 245d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 246d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith return ret; 247d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith} 248d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith 249fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_tasklet(unsigned long data) 250fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 251fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 2522299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan struct ieee80211_vif *vif; 253fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_sta *sta; 254fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 255fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 256fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = NULL; 257fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 258fb9987d0f748c983bb795a86f47522313f701a08Sujith 259fb9987d0f748c983bb795a86f47522313f701a08Sujith while ((skb = skb_dequeue(&priv->tx_queue)) != NULL) { 260fb9987d0f748c983bb795a86f47522313f701a08Sujith 261fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *) skb->data; 262fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 263fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 2642299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan vif = tx_info->control.vif; 265ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 266ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith memset(&tx_info->status, 0, sizeof(tx_info->status)); 267fb9987d0f748c983bb795a86f47522313f701a08Sujith 2682299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan if (!vif) 2692299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan goto send_mac80211; 2702299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan 271fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_lock(); 272fb9987d0f748c983bb795a86f47522313f701a08Sujith 2732299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan sta = ieee80211_find_sta(vif, hdr->addr1); 274ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith if (!sta) { 275ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith rcu_read_unlock(); 276ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith ieee80211_tx_status(priv->hw, skb); 277ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith continue; 278ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith } 279ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 280ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith /* Check if we need to start aggregation */ 281ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith 282fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sta && conf_is_ht(&priv->hw->conf) && 283d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith !(skb->protocol == cpu_to_be16(ETH_P_PAE))) { 284fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_data_qos(fc)) { 285fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 *qc, tid; 286fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_sta *ista; 287fb9987d0f748c983bb795a86f47522313f701a08Sujith 288fb9987d0f748c983bb795a86f47522313f701a08Sujith qc = ieee80211_get_qos_ctl(hdr); 289fb9987d0f748c983bb795a86f47522313f701a08Sujith tid = qc[0] & 0xf; 290fb9987d0f748c983bb795a86f47522313f701a08Sujith ista = (struct ath9k_htc_sta *)sta->drv_priv; 291fb9987d0f748c983bb795a86f47522313f701a08Sujith 292d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith if (ath9k_htc_check_tx_aggr(priv, ista, tid)) { 293bd2ce6e43f65127bc723e7fcc044758cf8113260Sujith Manoharan ieee80211_start_tx_ba_session(sta, tid, 0); 294d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_lock_bh(&priv->tx_lock); 295fb9987d0f748c983bb795a86f47522313f701a08Sujith ista->tid_state[tid] = AGGR_PROGRESS; 296d7ca21393d39cb2e73dfc4c516e7be37ba01789eSujith spin_unlock_bh(&priv->tx_lock); 297fb9987d0f748c983bb795a86f47522313f701a08Sujith } 298fb9987d0f748c983bb795a86f47522313f701a08Sujith } 299fb9987d0f748c983bb795a86f47522313f701a08Sujith } 300fb9987d0f748c983bb795a86f47522313f701a08Sujith 301fb9987d0f748c983bb795a86f47522313f701a08Sujith rcu_read_unlock(); 302fb9987d0f748c983bb795a86f47522313f701a08Sujith 3032299423bd0e32ccef78bbf1d4075617e3fd6cfd3Sujith Manoharan send_mac80211: 304ef98c3cd9b68ed27eeb94b833f74860fa1a734b7Sujith /* Send status to mac80211 */ 305fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_tx_status(priv->hw, skb); 306fb9987d0f748c983bb795a86f47522313f701a08Sujith } 3077757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith 3087757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith /* Wake TX queues if needed */ 3097757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_lock_bh(&priv->tx_lock); 3107757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith if (priv->tx_queues_stop) { 3117757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith priv->tx_queues_stop = false; 3127757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_unlock_bh(&priv->tx_lock); 313226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(ath9k_hw_common(priv->ah), ATH_DBG_XMIT, 314226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "Waking up TX queues\n"); 3157757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith ieee80211_wake_queues(priv->hw); 3167757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith return; 3177757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith } 3187757dfed5809b03aa61c7d7f5ff8092f85df8583Sujith spin_unlock_bh(&priv->tx_lock); 319fb9987d0f748c983bb795a86f47522313f701a08Sujith} 320fb9987d0f748c983bb795a86f47522313f701a08Sujith 321fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_txep(void *drv_priv, struct sk_buff *skb, 322fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id, bool txok) 323fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 324fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *) drv_priv; 325d439260e04eca5bce88558feecee4369784f2175Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 326fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_tx_info *tx_info; 327fb9987d0f748c983bb795a86f47522313f701a08Sujith 328fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!skb) 329fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 330fb9987d0f748c983bb795a86f47522313f701a08Sujith 331d439260e04eca5bce88558feecee4369784f2175Sujith if (ep_id == priv->mgmt_ep) { 332fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_mgmt_hdr)); 333d439260e04eca5bce88558feecee4369784f2175Sujith } else if ((ep_id == priv->data_bk_ep) || 334d439260e04eca5bce88558feecee4369784f2175Sujith (ep_id == priv->data_be_ep) || 335d439260e04eca5bce88558feecee4369784f2175Sujith (ep_id == priv->data_vi_ep) || 3367d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan (ep_id == priv->data_vo_ep) || 3377d547eb4bb664c5a6b7c8790c2ecb0aec5d15385Sujith Manoharan (ep_id == priv->cab_ep)) { 338fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, sizeof(struct tx_frame_hdr)); 339d439260e04eca5bce88558feecee4369784f2175Sujith } else { 3403800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unsupported TX EPID: %d\n", ep_id); 341d439260e04eca5bce88558feecee4369784f2175Sujith dev_kfree_skb_any(skb); 342d439260e04eca5bce88558feecee4369784f2175Sujith return; 343d439260e04eca5bce88558feecee4369784f2175Sujith } 344fb9987d0f748c983bb795a86f47522313f701a08Sujith 345fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info = IEEE80211_SKB_CB(skb); 346fb9987d0f748c983bb795a86f47522313f701a08Sujith 347fb9987d0f748c983bb795a86f47522313f701a08Sujith if (txok) 348fb9987d0f748c983bb795a86f47522313f701a08Sujith tx_info->flags |= IEEE80211_TX_STAT_ACK; 349fb9987d0f748c983bb795a86f47522313f701a08Sujith 350fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_tail(&priv->tx_queue, skb); 351fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->tx_tasklet); 352fb9987d0f748c983bb795a86f47522313f701a08Sujith} 353fb9987d0f748c983bb795a86f47522313f701a08Sujith 354fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_tx_init(struct ath9k_htc_priv *priv) 355fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 356fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_queue_head_init(&priv->tx_queue); 357fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 358fb9987d0f748c983bb795a86f47522313f701a08Sujith} 359fb9987d0f748c983bb795a86f47522313f701a08Sujith 360fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_tx_cleanup(struct ath9k_htc_priv *priv) 361fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 362fb9987d0f748c983bb795a86f47522313f701a08Sujith 363fb9987d0f748c983bb795a86f47522313f701a08Sujith} 364fb9987d0f748c983bb795a86f47522313f701a08Sujith 365e8c35a77e3408171852bde4914b650cf5b83e0d1Felix Fietkaubool ath9k_htc_txq_setup(struct ath9k_htc_priv *priv, int subtype) 366fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 367fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 368fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 369fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_tx_queue_info qi; 370fb9987d0f748c983bb795a86f47522313f701a08Sujith int qnum; 371fb9987d0f748c983bb795a86f47522313f701a08Sujith 372fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(&qi, 0, sizeof(qi)); 373ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(subtype); 374fb9987d0f748c983bb795a86f47522313f701a08Sujith 375fb9987d0f748c983bb795a86f47522313f701a08Sujith qnum = ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_DATA, &qi); 376fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum == -1) 377fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 378fb9987d0f748c983bb795a86f47522313f701a08Sujith 379fb9987d0f748c983bb795a86f47522313f701a08Sujith if (qnum >= ARRAY_SIZE(priv->hwq_map)) { 3803800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "qnum %u out of range, max %zu!\n", 3813800276a40751539a920ef8e0537ef2e19126799Joe Perches qnum, ARRAY_SIZE(priv->hwq_map)); 382fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_releasetxqueue(ah, qnum); 383fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 384fb9987d0f748c983bb795a86f47522313f701a08Sujith } 385fb9987d0f748c983bb795a86f47522313f701a08Sujith 386fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->hwq_map[subtype] = qnum; 387fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 388fb9987d0f748c983bb795a86f47522313f701a08Sujith} 389fb9987d0f748c983bb795a86f47522313f701a08Sujith 390ca74b83b66dbd289a395c6243695d746c76676ccSujithint ath9k_htc_cabq_setup(struct ath9k_htc_priv *priv) 391ca74b83b66dbd289a395c6243695d746c76676ccSujith{ 392ca74b83b66dbd289a395c6243695d746c76676ccSujith struct ath9k_tx_queue_info qi; 393ca74b83b66dbd289a395c6243695d746c76676ccSujith 394ca74b83b66dbd289a395c6243695d746c76676ccSujith memset(&qi, 0, sizeof(qi)); 395ca74b83b66dbd289a395c6243695d746c76676ccSujith ATH9K_HTC_INIT_TXQ(0); 396ca74b83b66dbd289a395c6243695d746c76676ccSujith 397ca74b83b66dbd289a395c6243695d746c76676ccSujith return ath9k_hw_setuptxqueue(priv->ah, ATH9K_TX_QUEUE_CAB, &qi); 398ca74b83b66dbd289a395c6243695d746c76676ccSujith} 399ca74b83b66dbd289a395c6243695d746c76676ccSujith 400fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 401fb9987d0f748c983bb795a86f47522313f701a08Sujith/* RX */ 402fb9987d0f748c983bb795a86f47522313f701a08Sujith/******/ 403fb9987d0f748c983bb795a86f47522313f701a08Sujith 4040995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 4050995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Calculate the RX filter to be set in the HW. 4060995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 4070995d110118b35c0dc5195e3ddddcc0dec263830Sujithu32 ath9k_htc_calcrxfilter(struct ath9k_htc_priv *priv) 4080995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 4090995d110118b35c0dc5195e3ddddcc0dec263830Sujith#define RX_FILTER_PRESERVE (ATH9K_RX_FILTER_PHYERR | ATH9K_RX_FILTER_PHYRADAR) 4100995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4110995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 4120995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt; 4130995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4140995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = (ath9k_hw_getrxfilter(ah) & RX_FILTER_PRESERVE) 4150995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_UCAST | ATH9K_RX_FILTER_BCAST 4160995d110118b35c0dc5195e3ddddcc0dec263830Sujith | ATH9K_RX_FILTER_MCAST; 4170995d110118b35c0dc5195e3ddddcc0dec263830Sujith 41894a40c0c6bcc47ceba12e0247c5a23fb1e6c81e4Rajkumar Manoharan if (priv->rxfilter & FIF_PROBE_REQ) 4190995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROBEREQ; 4200995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4210995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* 4220995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station 4230995d110118b35c0dc5195e3ddddcc0dec263830Sujith * mode interface or when in monitor mode. AP mode does not need this 4240995d110118b35c0dc5195e3ddddcc0dec263830Sujith * since it receives all in-BSS frames anyway. 4250995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 4260995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (((ah->opmode != NL80211_IFTYPE_AP) && 4270995d110118b35c0dc5195e3ddddcc0dec263830Sujith (priv->rxfilter & FIF_PROMISC_IN_BSS)) || 4284825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan ah->is_monitoring) 4290995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_PROM; 4300995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4310995d110118b35c0dc5195e3ddddcc0dec263830Sujith if (priv->rxfilter & FIF_CONTROL) 4320995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_CONTROL; 4330995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4340995d110118b35c0dc5195e3ddddcc0dec263830Sujith if ((ah->opmode == NL80211_IFTYPE_STATION) && 4350995d110118b35c0dc5195e3ddddcc0dec263830Sujith !(priv->rxfilter & FIF_BCN_PRBRESP_PROMISC)) 4360995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_MYBEACON; 4370995d110118b35c0dc5195e3ddddcc0dec263830Sujith else 4380995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_BEACON; 4390995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4404825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (conf_is_ht(&priv->hw->conf)) { 4410995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt |= ATH9K_RX_FILTER_COMP_BAR; 4424825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_UNCOMP_BA_BAR; 4434825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan } 4444825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan 4454825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan if (priv->rxfilter & FIF_PSPOLL) 4464825f54a44fc7280bf02c6d48c83d7a3df864e17Sujith Manoharan rfilt |= ATH9K_RX_FILTER_PSPOLL; 4470995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4480995d110118b35c0dc5195e3ddddcc0dec263830Sujith return rfilt; 4490995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4500995d110118b35c0dc5195e3ddddcc0dec263830Sujith#undef RX_FILTER_PRESERVE 4510995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 4520995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4530995d110118b35c0dc5195e3ddddcc0dec263830Sujith/* 4540995d110118b35c0dc5195e3ddddcc0dec263830Sujith * Recv initialization for opmode change. 4550995d110118b35c0dc5195e3ddddcc0dec263830Sujith */ 4560995d110118b35c0dc5195e3ddddcc0dec263830Sujithstatic void ath9k_htc_opmode_init(struct ath9k_htc_priv *priv) 4570995d110118b35c0dc5195e3ddddcc0dec263830Sujith{ 4580995d110118b35c0dc5195e3ddddcc0dec263830Sujith struct ath_hw *ah = priv->ah; 4590995d110118b35c0dc5195e3ddddcc0dec263830Sujith u32 rfilt, mfilt[2]; 4600995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4610995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* configure rx filter */ 4620995d110118b35c0dc5195e3ddddcc0dec263830Sujith rfilt = ath9k_htc_calcrxfilter(priv); 4630995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setrxfilter(ah, rfilt); 4640995d110118b35c0dc5195e3ddddcc0dec263830Sujith 4650995d110118b35c0dc5195e3ddddcc0dec263830Sujith /* calculate and install multicast filter */ 4660995d110118b35c0dc5195e3ddddcc0dec263830Sujith mfilt[0] = mfilt[1] = ~0; 4670995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_hw_setmcastfilter(ah, mfilt[0], mfilt[1]); 4680995d110118b35c0dc5195e3ddddcc0dec263830Sujith} 4690995d110118b35c0dc5195e3ddddcc0dec263830Sujith 470fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_host_rx_init(struct ath9k_htc_priv *priv) 471fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 472fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_hw_rxena(priv->ah); 4730995d110118b35c0dc5195e3ddddcc0dec263830Sujith ath9k_htc_opmode_init(priv); 47440346b66799b7d382e61bbb68a6b6bbdd20f320eLuis R. Rodriguez ath9k_hw_startpcureceive(priv->ah, (priv->op_flags & OP_SCANNING)); 475fb9987d0f748c983bb795a86f47522313f701a08Sujith priv->rx.last_rssi = ATH_RSSI_DUMMY_MARKER; 476fb9987d0f748c983bb795a86f47522313f701a08Sujith} 477fb9987d0f748c983bb795a86f47522313f701a08Sujith 478fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic void ath9k_process_rate(struct ieee80211_hw *hw, 479fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rxs, 480fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 rx_rate, u8 rs_flags) 481fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 482fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_supported_band *sband; 483fb9987d0f748c983bb795a86f47522313f701a08Sujith enum ieee80211_band band; 484fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned int i = 0; 485fb9987d0f748c983bb795a86f47522313f701a08Sujith 486fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rx_rate & 0x80) { 487fb9987d0f748c983bb795a86f47522313f701a08Sujith /* HT rate */ 488fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_HT; 489fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_2040) 490fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_40MHZ; 491fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rs_flags & ATH9K_RX_GI) 492fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORT_GI; 493fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = rx_rate & 0x7f; 494fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 495fb9987d0f748c983bb795a86f47522313f701a08Sujith } 496fb9987d0f748c983bb795a86f47522313f701a08Sujith 497fb9987d0f748c983bb795a86f47522313f701a08Sujith band = hw->conf.channel->band; 498fb9987d0f748c983bb795a86f47522313f701a08Sujith sband = hw->wiphy->bands[band]; 499fb9987d0f748c983bb795a86f47522313f701a08Sujith 500fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < sband->n_bitrates; i++) { 501fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value == rx_rate) { 502fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 503fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 504fb9987d0f748c983bb795a86f47522313f701a08Sujith } 505fb9987d0f748c983bb795a86f47522313f701a08Sujith if (sband->bitrates[i].hw_value_short == rx_rate) { 506fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->rate_idx = i; 507fb9987d0f748c983bb795a86f47522313f701a08Sujith rxs->flag |= RX_FLAG_SHORTPRE; 508fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 509fb9987d0f748c983bb795a86f47522313f701a08Sujith } 510fb9987d0f748c983bb795a86f47522313f701a08Sujith } 511fb9987d0f748c983bb795a86f47522313f701a08Sujith 512fb9987d0f748c983bb795a86f47522313f701a08Sujith} 513fb9987d0f748c983bb795a86f47522313f701a08Sujith 514fb9987d0f748c983bb795a86f47522313f701a08Sujithstatic bool ath9k_rx_prepare(struct ath9k_htc_priv *priv, 515fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, 516fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status *rx_status) 517fb9987d0f748c983bb795a86f47522313f701a08Sujith 518fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 519fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hdr *hdr; 520fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_hw *hw = priv->hw; 521fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb = rxbuf->skb; 522fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(priv->ah); 5234f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith struct ath_htc_rx_status *rxstatus; 524fb9987d0f748c983bb795a86f47522313f701a08Sujith int hdrlen, padpos, padsize; 525fb9987d0f748c983bb795a86f47522313f701a08Sujith int last_rssi = ATH_RSSI_DUMMY_MARKER; 526fb9987d0f748c983bb795a86f47522313f701a08Sujith __le16 fc; 527fb9987d0f748c983bb795a86f47522313f701a08Sujith 528b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan if (skb->len < HTC_RX_FRAME_HEADER_SIZE) { 529b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan ath_err(common, "Corrupted RX frame, dropping (len: %d)\n", 530b1563a4c3d721cb0496b8e1fb874f08a8f2b62ccSujith Manoharan skb->len); 5314f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 5324f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 5334f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 5344f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith rxstatus = (struct ath_htc_rx_status *)skb->data; 5354f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 5364f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith if (be16_to_cpu(rxstatus->rs_datalen) - 5374f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith (skb->len - HTC_RX_FRAME_HEADER_SIZE) != 0) { 5383800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, 5393800276a40751539a920ef8e0537ef2e19126799Joe Perches "Corrupted RX data len, dropping (dlen: %d, skblen: %d)\n", 5403800276a40751539a920ef8e0537ef2e19126799Joe Perches rxstatus->rs_datalen, skb->len); 5414f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith goto rx_next; 5424f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith } 5434f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 544719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan ath9k_htc_err_stat_rx(priv, rxstatus); 545719c4cf6b1b113e9caf377c6607ae45758a85871Sujith Manoharan 5464f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith /* Get the RX status information */ 5474f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith memcpy(&rxbuf->rxstatus, rxstatus, HTC_RX_FRAME_HEADER_SIZE); 5484f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith skb_pull(skb, HTC_RX_FRAME_HEADER_SIZE); 5494f824719a2729f1a6bb78de20c4d3b3dbdd81a09Sujith 550fb9987d0f748c983bb795a86f47522313f701a08Sujith hdr = (struct ieee80211_hdr *)skb->data; 551fb9987d0f748c983bb795a86f47522313f701a08Sujith fc = hdr->frame_control; 552fb9987d0f748c983bb795a86f47522313f701a08Sujith hdrlen = ieee80211_get_hdrlen_from_skb(skb); 553fb9987d0f748c983bb795a86f47522313f701a08Sujith 554fb9987d0f748c983bb795a86f47522313f701a08Sujith padpos = ath9k_cmn_padpos(fc); 555fb9987d0f748c983bb795a86f47522313f701a08Sujith 556fb9987d0f748c983bb795a86f47522313f701a08Sujith padsize = padpos & 3; 55732fbccafed7e935432b601f0453c2b702a385a25Sujith if (padsize && skb->len >= padpos+padsize+FCS_LEN) { 558fb9987d0f748c983bb795a86f47522313f701a08Sujith memmove(skb->data + padsize, skb->data, padpos); 559fb9987d0f748c983bb795a86f47522313f701a08Sujith skb_pull(skb, padsize); 560fb9987d0f748c983bb795a86f47522313f701a08Sujith } 561fb9987d0f748c983bb795a86f47522313f701a08Sujith 562fb9987d0f748c983bb795a86f47522313f701a08Sujith memset(rx_status, 0, sizeof(struct ieee80211_rx_status)); 563fb9987d0f748c983bb795a86f47522313f701a08Sujith 564fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status != 0) { 565fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_CRC) 566fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_FAILED_FCS_CRC; 567fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_PHY) 568fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 569fb9987d0f748c983bb795a86f47522313f701a08Sujith 570fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT) { 571fb9987d0f748c983bb795a86f47522313f701a08Sujith /* FIXME */ 572fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (rxbuf->rxstatus.rs_status & ATH9K_RXERR_MIC) { 573fb9987d0f748c983bb795a86f47522313f701a08Sujith if (ieee80211_is_ctl(fc)) 574fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 575fb9987d0f748c983bb795a86f47522313f701a08Sujith * Sometimes, we get invalid 576fb9987d0f748c983bb795a86f47522313f701a08Sujith * MIC failures on valid control frames. 577fb9987d0f748c983bb795a86f47522313f701a08Sujith * Remove these mic errors. 578fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 579fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_status &= ~ATH9K_RXERR_MIC; 580fb9987d0f748c983bb795a86f47522313f701a08Sujith else 581fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_MMIC_ERROR; 582fb9987d0f748c983bb795a86f47522313f701a08Sujith } 583fb9987d0f748c983bb795a86f47522313f701a08Sujith 584fb9987d0f748c983bb795a86f47522313f701a08Sujith /* 585fb9987d0f748c983bb795a86f47522313f701a08Sujith * Reject error frames with the exception of 586fb9987d0f748c983bb795a86f47522313f701a08Sujith * decryption and MIC failures. For monitor mode, 587fb9987d0f748c983bb795a86f47522313f701a08Sujith * we also ignore the CRC error. 588fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 589fb9987d0f748c983bb795a86f47522313f701a08Sujith if (priv->ah->opmode == NL80211_IFTYPE_MONITOR) { 590fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 591fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC | 592fb9987d0f748c983bb795a86f47522313f701a08Sujith ATH9K_RXERR_CRC)) 593fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 594fb9987d0f748c983bb795a86f47522313f701a08Sujith } else { 595fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->rxstatus.rs_status & 596fb9987d0f748c983bb795a86f47522313f701a08Sujith ~(ATH9K_RXERR_DECRYPT | ATH9K_RXERR_MIC)) { 597fb9987d0f748c983bb795a86f47522313f701a08Sujith goto rx_next; 598fb9987d0f748c983bb795a86f47522313f701a08Sujith } 599fb9987d0f748c983bb795a86f47522313f701a08Sujith } 600fb9987d0f748c983bb795a86f47522313f701a08Sujith } 601fb9987d0f748c983bb795a86f47522313f701a08Sujith 602fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!(rxbuf->rxstatus.rs_status & ATH9K_RXERR_DECRYPT)) { 603fb9987d0f748c983bb795a86f47522313f701a08Sujith u8 keyix; 604fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = rxbuf->rxstatus.rs_keyix; 605fb9987d0f748c983bb795a86f47522313f701a08Sujith if (keyix != ATH9K_RXKEYIX_INVALID) { 606fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 607fb9987d0f748c983bb795a86f47522313f701a08Sujith } else if (ieee80211_has_protected(fc) && 608fb9987d0f748c983bb795a86f47522313f701a08Sujith skb->len >= hdrlen + 4) { 609fb9987d0f748c983bb795a86f47522313f701a08Sujith keyix = skb->data[hdrlen + 3] >> 6; 610fb9987d0f748c983bb795a86f47522313f701a08Sujith if (test_bit(keyix, common->keymap)) 611fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->flag |= RX_FLAG_DECRYPTED; 612fb9987d0f748c983bb795a86f47522313f701a08Sujith } 613fb9987d0f748c983bb795a86f47522313f701a08Sujith } 614fb9987d0f748c983bb795a86f47522313f701a08Sujith 615fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_process_rate(hw, rx_status, rxbuf->rxstatus.rs_rate, 616fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->rxstatus.rs_flags); 617fb9987d0f748c983bb795a86f47522313f701a08Sujith 6187c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (rxbuf->rxstatus.rs_rssi != ATH9K_RSSI_BAD && 6197c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan !rxbuf->rxstatus.rs_moreaggr) 6207c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan ATH_RSSI_LPF(priv->rx.last_rssi, 6217c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi); 622fb9987d0f748c983bb795a86f47522313f701a08Sujith 6237c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan last_rssi = priv->rx.last_rssi; 624fb9987d0f748c983bb795a86f47522313f701a08Sujith 6257c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (likely(last_rssi != ATH_RSSI_DUMMY_MARKER)) 6267c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi = ATH_EP_RND(last_rssi, 6277c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan ATH_RSSI_EP_MULTIPLIER); 628fb9987d0f748c983bb795a86f47522313f701a08Sujith 6297c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (rxbuf->rxstatus.rs_rssi < 0) 6307c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan rxbuf->rxstatus.rs_rssi = 0; 631fb9987d0f748c983bb795a86f47522313f701a08Sujith 6327c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan if (ieee80211_is_beacon(fc)) 6337c277349ecbd66e19fad3d949fa6ef6c131a3b62Sujith Manoharan priv->ah->stats.avgbrssi = rxbuf->rxstatus.rs_rssi; 634fb9987d0f748c983bb795a86f47522313f701a08Sujith 6357f1f5a0060e377ff6a15903487b39223e12b8568Sujith rx_status->mactime = be64_to_cpu(rxbuf->rxstatus.rs_tstamp); 636fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->band = hw->conf.channel->band; 637fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->freq = hw->conf.channel->center_freq; 638fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->signal = rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR; 639fb9987d0f748c983bb795a86f47522313f701a08Sujith rx_status->antenna = rxbuf->rxstatus.rs_antenna; 6406ebacbb79d2d05978ba50a24d8cbe2a76ff2014cJohannes Berg rx_status->flag |= RX_FLAG_MACTIME_MPDU; 641fb9987d0f748c983bb795a86f47522313f701a08Sujith 642fb9987d0f748c983bb795a86f47522313f701a08Sujith return true; 643fb9987d0f748c983bb795a86f47522313f701a08Sujith 644fb9987d0f748c983bb795a86f47522313f701a08Sujithrx_next: 645fb9987d0f748c983bb795a86f47522313f701a08Sujith return false; 646fb9987d0f748c983bb795a86f47522313f701a08Sujith} 647fb9987d0f748c983bb795a86f47522313f701a08Sujith 648fb9987d0f748c983bb795a86f47522313f701a08Sujith/* 649fb9987d0f748c983bb795a86f47522313f701a08Sujith * FIXME: Handle FLUSH later on. 650fb9987d0f748c983bb795a86f47522313f701a08Sujith */ 651fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_tasklet(unsigned long data) 652fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 653fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)data; 654fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 655fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ieee80211_rx_status rx_status; 656fb9987d0f748c983bb795a86f47522313f701a08Sujith struct sk_buff *skb; 657fb9987d0f748c983bb795a86f47522313f701a08Sujith unsigned long flags; 658bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan struct ieee80211_hdr *hdr; 659fb9987d0f748c983bb795a86f47522313f701a08Sujith 660fb9987d0f748c983bb795a86f47522313f701a08Sujith do { 661fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 662fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 663fb9987d0f748c983bb795a86f47522313f701a08Sujith if (tmp_buf->in_process) { 664fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 665fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 666fb9987d0f748c983bb795a86f47522313f701a08Sujith } 667fb9987d0f748c983bb795a86f47522313f701a08Sujith } 668fb9987d0f748c983bb795a86f47522313f701a08Sujith 669fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 670fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 671fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 672fb9987d0f748c983bb795a86f47522313f701a08Sujith } 673fb9987d0f748c983bb795a86f47522313f701a08Sujith 674fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!rxbuf->skb) 675fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 676fb9987d0f748c983bb795a86f47522313f701a08Sujith 677fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!ath9k_rx_prepare(priv, rxbuf, &rx_status)) { 678fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 679fb9987d0f748c983bb795a86f47522313f701a08Sujith goto requeue; 680fb9987d0f748c983bb795a86f47522313f701a08Sujith } 681fb9987d0f748c983bb795a86f47522313f701a08Sujith 682fb9987d0f748c983bb795a86f47522313f701a08Sujith memcpy(IEEE80211_SKB_RXCB(rxbuf->skb), &rx_status, 683fb9987d0f748c983bb795a86f47522313f701a08Sujith sizeof(struct ieee80211_rx_status)); 684fb9987d0f748c983bb795a86f47522313f701a08Sujith skb = rxbuf->skb; 685bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan hdr = (struct ieee80211_hdr *) skb->data; 686bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 687bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan if (ieee80211_is_beacon(hdr->frame_control) && priv->ps_enabled) 688bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan ieee80211_queue_work(priv->hw, &priv->ps_work); 689bde748a40d4d5a9915def6772e208848c105e616Vivek Natarajan 690fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 691fb9987d0f748c983bb795a86f47522313f701a08Sujith 692fb9987d0f748c983bb795a86f47522313f701a08Sujith ieee80211_rx(priv->hw, skb); 693fb9987d0f748c983bb795a86f47522313f701a08Sujith 694fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_irqsave(&priv->rx.rxbuflock, flags); 695fb9987d0f748c983bb795a86f47522313f701a08Sujithrequeue: 696fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = false; 697fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = NULL; 698fb9987d0f748c983bb795a86f47522313f701a08Sujith list_move_tail(&rxbuf->list, &priv->rx.rxbuf); 699fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = NULL; 700fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock_irqrestore(&priv->rx.rxbuflock, flags); 701fb9987d0f748c983bb795a86f47522313f701a08Sujith } while (1); 702fb9987d0f748c983bb795a86f47522313f701a08Sujith 703fb9987d0f748c983bb795a86f47522313f701a08Sujith} 704fb9987d0f748c983bb795a86f47522313f701a08Sujith 705fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_htc_rxep(void *drv_priv, struct sk_buff *skb, 706fb9987d0f748c983bb795a86f47522313f701a08Sujith enum htc_endpoint_id ep_id) 707fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 708fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_priv *priv = (struct ath9k_htc_priv *)drv_priv; 709fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 710fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 711fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf = NULL, *tmp_buf = NULL; 712fb9987d0f748c983bb795a86f47522313f701a08Sujith 713fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 714fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry(tmp_buf, &priv->rx.rxbuf, list) { 715fb9987d0f748c983bb795a86f47522313f701a08Sujith if (!tmp_buf->in_process) { 716fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = tmp_buf; 717fb9987d0f748c983bb795a86f47522313f701a08Sujith break; 718fb9987d0f748c983bb795a86f47522313f701a08Sujith } 719fb9987d0f748c983bb795a86f47522313f701a08Sujith } 720fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 721fb9987d0f748c983bb795a86f47522313f701a08Sujith 722fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 723226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches ath_dbg(common, ATH_DBG_ANY, 724226afe68fdbd1aa3680158aca0a3631cbd019626Joe Perches "No free RX buffer\n"); 725fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 726fb9987d0f748c983bb795a86f47522313f701a08Sujith } 727fb9987d0f748c983bb795a86f47522313f701a08Sujith 728fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock(&priv->rx.rxbuflock); 729fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->skb = skb; 730fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf->in_process = true; 731fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_unlock(&priv->rx.rxbuflock); 732fb9987d0f748c983bb795a86f47522313f701a08Sujith 733fb9987d0f748c983bb795a86f47522313f701a08Sujith tasklet_schedule(&priv->rx_tasklet); 734fb9987d0f748c983bb795a86f47522313f701a08Sujith return; 735fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 736fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(skb); 737fb9987d0f748c983bb795a86f47522313f701a08Sujith} 738fb9987d0f748c983bb795a86f47522313f701a08Sujith 739fb9987d0f748c983bb795a86f47522313f701a08Sujith/* FIXME: Locking for cleanup/init */ 740fb9987d0f748c983bb795a86f47522313f701a08Sujith 741fb9987d0f748c983bb795a86f47522313f701a08Sujithvoid ath9k_rx_cleanup(struct ath9k_htc_priv *priv) 742fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 743fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf, *tbuf; 744fb9987d0f748c983bb795a86f47522313f701a08Sujith 745fb9987d0f748c983bb795a86f47522313f701a08Sujith list_for_each_entry_safe(rxbuf, tbuf, &priv->rx.rxbuf, list) { 746fb9987d0f748c983bb795a86f47522313f701a08Sujith list_del(&rxbuf->list); 747fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf->skb) 748fb9987d0f748c983bb795a86f47522313f701a08Sujith dev_kfree_skb_any(rxbuf->skb); 749fb9987d0f748c983bb795a86f47522313f701a08Sujith kfree(rxbuf); 750fb9987d0f748c983bb795a86f47522313f701a08Sujith } 751fb9987d0f748c983bb795a86f47522313f701a08Sujith} 752fb9987d0f748c983bb795a86f47522313f701a08Sujith 753fb9987d0f748c983bb795a86f47522313f701a08Sujithint ath9k_rx_init(struct ath9k_htc_priv *priv) 754fb9987d0f748c983bb795a86f47522313f701a08Sujith{ 755fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_hw *ah = priv->ah; 756fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath_common *common = ath9k_hw_common(ah); 757fb9987d0f748c983bb795a86f47522313f701a08Sujith struct ath9k_htc_rxbuf *rxbuf; 758fb9987d0f748c983bb795a86f47522313f701a08Sujith int i = 0; 759fb9987d0f748c983bb795a86f47522313f701a08Sujith 760fb9987d0f748c983bb795a86f47522313f701a08Sujith INIT_LIST_HEAD(&priv->rx.rxbuf); 761fb9987d0f748c983bb795a86f47522313f701a08Sujith spin_lock_init(&priv->rx.rxbuflock); 762fb9987d0f748c983bb795a86f47522313f701a08Sujith 763fb9987d0f748c983bb795a86f47522313f701a08Sujith for (i = 0; i < ATH9K_HTC_RXBUF; i++) { 764fb9987d0f748c983bb795a86f47522313f701a08Sujith rxbuf = kzalloc(sizeof(struct ath9k_htc_rxbuf), GFP_KERNEL); 765fb9987d0f748c983bb795a86f47522313f701a08Sujith if (rxbuf == NULL) { 7663800276a40751539a920ef8e0537ef2e19126799Joe Perches ath_err(common, "Unable to allocate RX buffers\n"); 767fb9987d0f748c983bb795a86f47522313f701a08Sujith goto err; 768fb9987d0f748c983bb795a86f47522313f701a08Sujith } 769fb9987d0f748c983bb795a86f47522313f701a08Sujith list_add_tail(&rxbuf->list, &priv->rx.rxbuf); 770fb9987d0f748c983bb795a86f47522313f701a08Sujith } 771fb9987d0f748c983bb795a86f47522313f701a08Sujith 772fb9987d0f748c983bb795a86f47522313f701a08Sujith return 0; 773fb9987d0f748c983bb795a86f47522313f701a08Sujith 774fb9987d0f748c983bb795a86f47522313f701a08Sujitherr: 775fb9987d0f748c983bb795a86f47522313f701a08Sujith ath9k_rx_cleanup(priv); 776fb9987d0f748c983bb795a86f47522313f701a08Sujith return -ENOMEM; 777fb9987d0f748c983bb795a86f47522313f701a08Sujith} 778