1f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* 2f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This file is part of wl1271 3f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 4f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Copyright (C) 2009 Nokia Corporation 5f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 6f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Contact: Luciano Coelho <luciano.coelho@nokia.com> 7f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 8f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is free software; you can redistribute it and/or 9f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * modify it under the terms of the GNU General Public License 10f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * version 2 as published by the Free Software Foundation. 11f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 12f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * This program is distributed in the hope that it will be useful, but 13f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * WITHOUT ANY WARRANTY; without even the implied warranty of 14f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * General Public License for more details. 16f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 17f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * You should have received a copy of the GNU General Public License 18f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * along with this program; if not, write to the Free Software 19f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 20f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 02110-1301 USA 21f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho * 22f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho */ 23f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 24f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/kernel.h> 25f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho#include <linux/module.h> 26c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov#include <linux/etherdevice.h> 278910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov#include <linux/spinlock.h> 28f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 29c31be25a7144ebc9b7a22128909bac7654d4c46bLuciano Coelho#include "wlcore.h" 300f4e31222a2c0b93f25a87effd2033cb78c7a79cLuciano Coelho#include "debug.h" 3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h" 3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "ps.h" 3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "tx.h" 3456d4f8f685c073c7ed7203b78c57f5d893d65102Arik Nemtsov#include "event.h" 35b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov#include "hw_ops.h" 36f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3700782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho/* 3800782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * TODO: this is here just for now, it must be removed when the data 3900782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * operations are in place. 4000782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho */ 4100782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho#include "../wl12xx/reg.h" 4200782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho 43536129c8ad35de87ff2f864f205a54ac32bfebccEliad Pellerstatic int wl1271_set_default_wep_key(struct wl1271 *wl, 44536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct wl12xx_vif *wlvif, u8 id) 457f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov{ 467f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov int ret; 47536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); 487f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 497f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (is_ap) 50c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, 51a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller wlvif->ap.bcast_hlid); 527f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov else 53154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); 547f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 557f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (ret < 0) 567f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return ret; 577f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 587f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); 597f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return 0; 607f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov} 617f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 6225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 6425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv int id; 6525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6672b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc); 6772b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (id >= wl->num_tx_desc) 6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return -EBUSY; 6925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 7025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv __set_bit(id, wl->tx_frames_map); 7125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = skb; 7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt++; 7325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return id; 7425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv} 75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 76872b345fbaef290f890d0bbd34b78ab50269980fArik Nemtsovvoid wl1271_free_tx_id(struct wl1271 *wl, int id) 7725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{ 7825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (__test_and_clear_bit(id, wl->tx_frames_map)) { 7972b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc)) 80ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 81ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv 8225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 8325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 8425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 85f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 86872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl1271_free_tx_id); 87f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 8899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 89187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov struct wl12xx_vif *wlvif, 9099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 9199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 9299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 9399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 94187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 95187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 96187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov if (!ieee80211_is_auth(hdr->frame_control)) 97187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov return; 98187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov 9999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 10099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 10199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 10299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 10399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 104028e7243ac411c3aba7a754bcc775c2fbb0b3e5cEliad Peller wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1); 105187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov 106187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov /* 107187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov * ROC for 1 second on the AP channel for completing the connection. 108187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov * Note the ROC will be continued by the update_sta_state callbacks 109187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov * once the station reaches the associated state. 110187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov */ 111187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov wlcore_update_inconn_sta(wl, wlvif, NULL, true); 112187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov wlvif->pending_auth_reply_time = jiffies; 113187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov cancel_delayed_work(&wlvif->pending_auth_complete_work); 114187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov ieee80211_queue_delayed_work(wl->hw, 115187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov &wlvif->pending_auth_complete_work, 116187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT)); 11799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 11899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 119c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerstatic void wl1271_tx_regulate_link(struct wl1271 *wl, 120c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller struct wl12xx_vif *wlvif, 121c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller u8 hlid) 122b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 12337c68ea6997aac2faf21b83c28eda3b1659c4d45Arik Nemtsov bool fw_ps; 1249b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov u8 tx_pkts; 125b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 126c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (WARN_ON(!test_bit(hlid, wlvif->links_map))) 127b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 128b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 1295e74b3aa6ffd80128e3df605bf27d8a6a3c04997Eliad Peller fw_ps = test_bit(hlid, &wl->ap_fw_ps_map); 1309b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov tx_pkts = wl->links[hlid].allocated_pkts; 131b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 132b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 133b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 134b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 1359a1009684df5295883ba2eb85066a23ed3c3f6a6Arik Nemtsov * Make an exception if this is the only connected link. In this 1369a1009684df5295883ba2eb85066a23ed3c3f6a6Arik Nemtsov * case FW-memory congestion is less of a problem. 13741ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller * Note that a single connected STA means 2*ap_count + 1 active links, 13841ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller * since we must account for the global and broadcast AP links 13941ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller * for each AP. The "fw_ps" check assures us the other link is a STA 14041ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller * connected to the AP. Otherwise the FW would not set the PSM bit. 141b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 14241ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps && 14337c68ea6997aac2faf21b83c28eda3b1659c4d45Arik Nemtsov tx_pkts >= WL1271_PS_STA_MAX_PACKETS) 1446e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller wl12xx_ps_link_start(wl, wlvif, hlid, true); 145b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 146b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 147f8e0af6b8732b47c2531a280753d29a4ca2d114bArik Nemtsovbool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) 148f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 149f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->dummy_packet == skb; 150f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 151872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl12xx_is_dummy_packet); 152f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 1532b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsovstatic u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1542b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov struct sk_buff *skb, struct ieee80211_sta *sta) 155a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 1562b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov if (sta) { 157a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 158a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1592b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov wl_sta = (struct wl1271_station *)sta->drv_priv; 160a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl_sta->hlid; 161a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 162a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_hdr *hdr; 163a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 16453d40d0b863e22b697f8d85e1f95cb6f9d2d95b1Eliad Peller if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) 165f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->system_hlid; 166f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 167a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov hdr = (struct ieee80211_hdr *)skb->data; 16845b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) 169a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller return wlvif->ap.bcast_hlid; 17045b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller else 17145b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller return wlvif->ap.global_hlid; 172a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 173a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 174a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 175d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pelleru8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1762b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov struct sk_buff *skb, struct ieee80211_sta *sta) 177f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 178dabf37dba405565ab46f4d1821c781730285b9edEliad Peller struct ieee80211_tx_info *control; 179dabf37dba405565ab46f4d1821c781730285b9edEliad Peller 180536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (wlvif->bss_type == BSS_TYPE_AP_BSS) 1812b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); 182f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 183dabf37dba405565ab46f4d1821c781730285b9edEliad Peller control = IEEE80211_SKB_CB(skb); 184dabf37dba405565ab46f4d1821c781730285b9edEliad Peller if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) { 185dabf37dba405565ab46f4d1821c781730285b9edEliad Peller wl1271_debug(DEBUG_TX, "tx offchannel"); 186dabf37dba405565ab46f4d1821c781730285b9edEliad Peller return wlvif->dev_hlid; 187dabf37dba405565ab46f4d1821c781730285b9edEliad Peller } 188dabf37dba405565ab46f4d1821c781730285b9edEliad Peller 1893230f35e09f386ee604f55450dcd26098a3c4bc3Eliad Peller return wlvif->sta.hlid; 190f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 191f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 192b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsovunsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, 193b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov unsigned int packet_length) 1940da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{ 1959fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) || 1969fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)) 197f83985bb5f8f0f25d44ab7b108a709a52aa1c5e0Arik Nemtsov return ALIGN(packet_length, WL1271_TX_ALIGN_TO); 1989fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis else 1999fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); 2000da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv} 201b3b4b4b812018a06221b6d7b88a5540fccae2940Arik NemtsovEXPORT_SYMBOL(wlcore_calc_packet_alignment); 2020da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv 203a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, 204536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, u32 buf_offset, 20532bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov u8 hlid, bool is_gem) 206f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 207f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 208f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 2095c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 210742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int id, ret = -EBUSY, ac; 21132bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov u32 spare_blocks; 212f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 21326a309c7586140afd40628a7031993afbaae0f07Igal Chernobelsky if (buf_offset + total_len > wl->aggr_buf_size) 2146c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 215a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 21632bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem); 21732bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov 218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 21925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 220f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 221f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 222f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 223b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); 22448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 225f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 226f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 227f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 228f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2294a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, 2304a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov spare_blocks); 231ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 232f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 233f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 234f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 2357bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov wl->tx_allocated_blocks += total_blocks; 236f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2379be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov /* 2389be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov * If the FW was empty before, arm the Tx watchdog. Also do 2399be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov * this on the first Tx after resume, as we always cancel the 2409be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov * watchdog on suspend. 2419be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov */ 2429be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov if (wl->tx_allocated_blocks == total_blocks || 2439be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags)) 24455df5afb13718cda49128fa5985556df91d07765Arik Nemtsov wl12xx_rearm_tx_watchdog_locked(wl); 24555df5afb13718cda49128fa5985556df91d07765Arik Nemtsov 246742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 247742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov wl->tx_allocated_pkts[ac]++; 248bf54e301671a6ece6c94550294dc7faf14158cd3Arik Nemtsov 2499ebcb232158c737db21e22b7bfdc4fc6d661ea8cArik Nemtsov if (test_bit(hlid, wl->links_map)) 2509b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov wl->links[hlid].allocated_pkts++; 25109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 252f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 253f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 256f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 257781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 25825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 259781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 260f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 261f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 263f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 264a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, 265536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, 266536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct ieee80211_tx_info *control, u8 hlid) 267f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 268ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 2706f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov int ac, rate_idx; 271ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 272cf00f379d82d170712150588accd2ebe316c2226John W. Linville u16 tx_attr = 0; 273f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller __le16 frame_control; 274f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller struct ieee80211_hdr *hdr; 275f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller u8 *frame_start; 276a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller bool is_dummy; 277f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 279f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_start = (u8 *)(desc + 1); 280f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller hdr = (struct ieee80211_hdr *)(frame_start + extra); 281f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_control = hdr->frame_control; 282f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2831e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 2841e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 285f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller int hdrlen = ieee80211_hdrlen(frame_control); 286f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller memmove(frame_start, hdr, hdrlen); 2872fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov skb_set_network_header(skb, skb_network_offset(skb) + extra); 2881e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 2891e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 290f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 291ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 292ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 293ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 294c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 295a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 2960f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) 297c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 298c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 299c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 300f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 301db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller /* queue */ 302c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 303db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller desc->tid = skb->priority; 304c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 305a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller if (is_dummy) { 306ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 307ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * FW expects the dummy packet to have an invalid session id - 308ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * any session id that is different than the one set in the join 309ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 31098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller tx_attr = (SESSION_COUNTER_INVALID << 311ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_OFST_SESSION_COUNTER) & 312ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_SESSION_COUNTER; 313ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 314ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; 3150f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller } else if (wlvif) { 3163ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov u8 session_id = wl->session_ids[hlid]; 3173ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov 3183ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) && 3193ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov (wlvif->bss_type == BSS_TYPE_AP_BSS)) 3203ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov session_id = 0; 3213ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov 322ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* configure the tx attributes */ 3233ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER; 324ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 325ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 32679b122dc51797b650201f21360481a0450e9b7e4Eliad Peller desc->hlid = hlid; 3270f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif) 328a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller rate_idx = 0; 329a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { 3308f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira /* 3314340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller * if the packets are data packets 3328f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira * send them with AP rate policies (EAPOLs are an exception), 3338f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira * otherwise use default basic rates 3348f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira */ 335bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky if (skb->protocol == cpu_to_be16(ETH_P_PAE)) 3368f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira rate_idx = wlvif->sta.basic_rate_idx; 337bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky else if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) 338bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky rate_idx = wlvif->sta.p2p_rate_idx; 3394340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller else if (ieee80211_is_data(frame_control)) 340e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.ap_rate_idx; 341c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 342e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.basic_rate_idx; 343c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 344a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller if (hlid == wlvif->ap.global_hlid) 345e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.mgmt_rate_idx; 346bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky else if (hlid == wlvif->ap.bcast_hlid || 347c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov skb->protocol == cpu_to_be16(ETH_P_PAE) || 348c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov !ieee80211_is_data(frame_control)) 349c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov /* 350c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov * send non-data, bcast and EAPOLs using the 351c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov * min basic rate 352c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov */ 353e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.bcast_rate_idx; 354e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov else 355e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.ucast_rate_idx[ac]; 356c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 357c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 358c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 359d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 360f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller /* for WEP shared auth - no fw encryption is needed */ 361f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller if (ieee80211_is_auth(frame_control) && 362f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller ieee80211_has_protected(frame_control)) 363f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; 364f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller 3652a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky /* send EAPOL frames as voice */ 3662a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO) 3672a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky tx_attr |= TX_HW_ATTR_EAPOL_FRAME; 3682a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky 369d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 3706f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov 3712fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov wlcore_hw_set_tx_desc_csum(wl, desc, skb); 3726f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov wlcore_hw_set_tx_desc_data_len(wl, desc, skb); 373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 376a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, 377930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov struct sk_buff *skb, u32 buf_offset, u8 hlid) 378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 382a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 383536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_dummy; 38432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov bool is_gem = false; 385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3867a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (!skb) { 3877a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira wl1271_error("discarding null skb"); 388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 3897a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira } 390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 391930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov if (hlid == WL12XX_INVALID_LINK_ID) { 392930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_error("invalid hlid. dropping skb 0x%p", skb); 393930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov return -EINVAL; 394930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov } 395930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov 396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 398536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 399536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller 4002c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 4012c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 40297359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 4035ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller extra = WL1271_EXTRA_SPACE_TKIP; 404f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 405f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 4067f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 4077f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 4087f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 4097f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 4107f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 4117f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 413bf9d5d28aabc6e420a0b6fb3a24b93046878e864Victor Goldenshtein if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) { 414536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller ret = wl1271_set_default_wep_key(wl, wlvif, idx); 415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 417f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller wlvif->default_key = idx; 418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 41932bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov 42032bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov is_gem = (cipher == WL1271_CIPHER_SUITE_GEM); 421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 42209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 42332bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid, 42432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov is_gem); 425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 427f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 428a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); 429fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov 4300f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { 431187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, wlvif, skb); 432c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_tx_regulate_link(wl, wlvif, hlid); 433b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 43499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 435a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 43648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * The length of each packet is stored in terms of 43748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * words. Thus, we must pad the skb data to make sure its 43848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * length is aligned. The number of padding bytes is computed 43948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * and set in wl1271_tx_fill_hdr. 44048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * In special cases, we want to align to a specific block size 44148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * (eg. for wl128x with SDIO we align to 256). 442a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 443b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov total_len = wlcore_calc_packet_alignment(wl, skb->len); 44448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 445a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 446a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 447f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 448990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv /* Revert side effects in the dummy packet skb, so it can be reused */ 449536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (is_dummy) 450990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 451990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 452a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 455af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, 456af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller enum ieee80211_band rate_band) 457830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 458830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 459830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 460830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 461830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 462af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller band = wl->hw->wiphy->bands[rate_band]; 463830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 464830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 465830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 466830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 467830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 468830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 469b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov /* MCS rates indication are on bits 16 - 31 */ 47018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 47118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 472b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov for (bit = 0; bit < 16; bit++) { 47318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 47418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 47518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 47618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 47718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 478830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 479830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 480830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 481a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 4822fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 483708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov int i; 4841c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov struct wl12xx_vif *wlvif; 4852fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 4861c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov wl12xx_for_each_wlvif(wl, wlvif) { 4871c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 4881c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i, 4891c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WLCORE_QUEUE_STOP_REASON_WATERMARK) && 4901c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov wlvif->tx_queue_count[i] <= 4911c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WL1271_TX_QUEUE_LOW_WATERMARK) 4921c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov /* firmware buffer has space, restart queues */ 4931c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov wlcore_wake_queue(wl, wlvif, i, 4941c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WLCORE_QUEUE_STOP_REASON_WATERMARK); 495708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov } 4962fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 4972fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 4982fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 4990e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic int wlcore_select_ac(struct wl1271 *wl) 500742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov{ 501742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int i, q = -1, ac; 502742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov u32 min_pkts = 0xffffffff; 503742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 504742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* 505742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * Find a non-empty ac where: 506742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 1. There are packets to transmit 507742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 2. The FW has the least allocated blocks 508742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 509742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * We prioritize the ACs according to VO>VI>BE>BK 510742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov */ 511742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 512742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(i); 5130e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (wl->tx_queue_count[ac] && 5140e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov wl->tx_allocated_pkts[ac] < min_pkts) { 515742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov q = ac; 516742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov min_pkts = wl->tx_allocated_pkts[q]; 517742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 518742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 519742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 5200e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov return q; 521742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov} 522742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 5230e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl, 5240e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov struct wl1271_link *lnk, u8 q) 5256742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 526d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 5276742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 5286742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5290e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = skb_dequeue(&lnk->tx_queue[q]); 5306742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 5316742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 5326246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 533f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 5348591d42452f16b1888419da4456142864b08ef9eArik Nemtsov if (lnk->wlvif) { 5358591d42452f16b1888419da4456142864b08ef9eArik Nemtsov WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0); 5368591d42452f16b1888419da4456142864b08ef9eArik Nemtsov lnk->wlvif->tx_queue_count[q]--; 5378591d42452f16b1888419da4456142864b08ef9eArik Nemtsov } 5386742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5396742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 5406742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5416742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 5426742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5436742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5440e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl, 5450e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov u8 hlid, u8 ac, 5460e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov u8 *low_prio_hlid) 5470e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov{ 5480e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov struct wl1271_link *lnk = &wl->links[hlid]; 5490e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 550f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) { 5510e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (*low_prio_hlid == WL12XX_INVALID_LINK_ID && 552f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov !skb_queue_empty(&lnk->tx_queue[ac]) && 553f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov wlcore_hw_lnk_low_prio(wl, hlid, lnk)) 5540e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov /* we found the first non-empty low priority queue */ 5550e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov *low_prio_hlid = hlid; 5560e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 5570e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov return NULL; 5580e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov } 5590e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 5600e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov return wlcore_lnk_dequeue(wl, lnk, ac); 5610e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov} 5620e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 5630e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl, 5640e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov struct wl12xx_vif *wlvif, 5650e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov u8 ac, u8 *hlid, 5660e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov u8 *low_prio_hlid) 567a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 568a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 569a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 570a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 571a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 572da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller start_hlid = (wlvif->last_tx_hlid + 1) % wl->num_links; 573a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 574a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 575da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller for (i = 0; i < wl->num_links; i++) { 576da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller h = (start_hlid + i) % wl->num_links; 577a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 578742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* only consider connected stations */ 579c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (!test_bit(h, wlvif->links_map)) 580742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 581742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 5820e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = wlcore_lnk_dequeue_high_prio(wl, h, ac, 5830e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov low_prio_hlid); 584d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 585742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 586742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 587d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = h; 588d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller break; 589a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 590a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 591d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 5924438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller wlvif->last_tx_hlid = 0; 593a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 594930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov *hlid = wlvif->last_tx_hlid; 595a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 596a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 597a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 598930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) 599a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 600990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv unsigned long flags; 601e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller struct wl12xx_vif *wlvif = wl->last_wlvif; 602990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv struct sk_buff *skb = NULL; 6030e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov int ac; 6040e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov u8 low_prio_hlid = WL12XX_INVALID_LINK_ID; 6050e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6060e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov ac = wlcore_select_ac(wl); 6070e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (ac < 0) 6080e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov goto out; 609990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 61049c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* continue from last wlvif (round robin) */ 611e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (wlvif) { 612e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif_continue(wl, wlvif) { 6130e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (!wlvif->tx_queue_count[ac]) 6140e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov continue; 6150e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6160e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, 6170e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov &low_prio_hlid); 6180e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (!skb) 6190e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov continue; 6200e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6210e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov wl->last_wlvif = wlvif; 6220e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov break; 623e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 624e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 625e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller 62649c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* dequeue from the system HLID before the restarting wlvif list */ 627930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov if (!skb) { 6280e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid, 6290e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov ac, &low_prio_hlid); 6300e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (skb) { 6310e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov *hlid = wl->system_hlid; 6320e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov wl->last_wlvif = NULL; 6330e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov } 634930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov } 63549c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 6360e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov /* Do a new pass over the wlvif list. But no need to continue 6370e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov * after last_wlvif. The previous pass should have found it. */ 638e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (!skb) { 639e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif(wl, wlvif) { 6400e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (!wlvif->tx_queue_count[ac]) 6410e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov goto next; 6420e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6430e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid, 6440e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov &low_prio_hlid); 645e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (skb) { 646e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl->last_wlvif = wlvif; 647e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller break; 648e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 64949c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 6500e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovnext: 65149c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov if (wlvif == wl->last_wlvif) 65249c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov break; 653e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 654a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller } 655a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 6560e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov /* no high priority skbs found - but maybe a low priority one? */ 6570e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) { 6580e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov struct wl1271_link *lnk = &wl->links[low_prio_hlid]; 6590e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov skb = wlcore_lnk_dequeue(wl, lnk, ac); 6600e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6610e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov WARN_ON(!skb); /* we checked this before */ 6620e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov *hlid = low_prio_hlid; 6630e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6640e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov /* ensure proper round robin in the vif/link levels */ 6650e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov wl->last_wlvif = lnk->wlvif; 6660e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov if (lnk->wlvif) 6670e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov lnk->wlvif->last_tx_hlid = low_prio_hlid; 6680e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 6690e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov } 6700e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov 671abca1237820a7d9a087b2744a2abd1026364d7b7Arik Nemtsovout: 672990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!skb && 673990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 674f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q; 675f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov 676990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl->dummy_packet; 677930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov *hlid = wl->system_hlid; 678f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 679990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_lock_irqsave(&wl->wl_lock, flags); 6806246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 681f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 682990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 683990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } 684990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 685990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return skb; 686a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 687a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 688d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, 689930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov struct sk_buff *skb, u8 hlid) 6906742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 6916742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 6926742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 6936742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 694990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 695990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 696d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller } else { 697a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 698a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 699a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 700da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller wlvif->last_tx_hlid = (hlid + wl->num_links - 1) % 701da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller wl->num_links; 702a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 703a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 7046742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 705f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]++; 7068591d42452f16b1888419da4456142864b08ef9eArik Nemtsov if (wlvif) 7078591d42452f16b1888419da4456142864b08ef9eArik Nemtsov wlvif->tx_queue_count[q]++; 7086742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 7096742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 7106742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 71177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb) 71277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{ 71377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 71477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 71577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller return ieee80211_is_data_present(hdr->frame_control); 71677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller} 71777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 7189eb599e9c62dcfd4efece1936c385381b366b684Eliad Pellervoid wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) 7199eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller{ 7209eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl12xx_vif *wlvif; 7219eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u32 timeout; 7229eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u8 hlid; 7239eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7249eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.interval) 7259eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 7269eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7279eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.always && 7289eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) 7299eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 7309eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7319eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller timeout = wl->conf.rx_streaming.duration; 7329eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_for_each_wlvif_sta(wl, wlvif) { 7339eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool found = false; 734da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller for_each_set_bit(hlid, active_hlids, wl->num_links) { 7359eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (test_bit(hlid, wlvif->links_map)) { 7369eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller found = true; 7379eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller break; 7389eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 7399eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 7409eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7419eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!found) 7429eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller continue; 7439eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7449eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller /* enable rx streaming */ 7450744bdb60b51dce54553d5af9a6133f1fe419032Eliad Peller if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) 7469eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller ieee80211_queue_work(wl->hw, 7479eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller &wlvif->rx_streaming_enable_work); 7489eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7499eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller mod_timer(&wlvif->rx_streaming_timer, 7509eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller jiffies + msecs_to_jiffies(timeout)); 7519eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 7529eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller} 7539eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 7547a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira/* 7557a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * Returns failure values only in case of failed bus ops within this function. 7567a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * wl1271_prepare_tx_frame retvals won't be returned in order to avoid 7577a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * triggering recovery by higher layers when not necessary. 7587a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery 7597a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame 7607a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING 7617a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * within prepare_tx_frame code but there's nothing we should do about those 7627a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * as well. 7637a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira */ 764eb96f841b9563ba34969be25615548635728faf5Ido Yarivint wlcore_tx_work_locked(struct wl1271 *wl) 765f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 766a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller struct wl12xx_vif *wlvif; 767f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 7689eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl1271_tx_hw_descr *desc; 7699fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis u32 buf_offset = 0, last_len = 0; 7706c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 771da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0}; 772eb96f841b9563ba34969be25615548635728faf5Ido Yariv int ret = 0; 7737a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira int bus_ret = 0; 774930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov u8 hlid; 775f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 7764cc533830b7e6b309e8b73196c410951fc2bed91Ido Yariv if (unlikely(wl->state != WLCORE_STATE_ON)) 7777a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira return 0; 778f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 779930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov while ((skb = wl1271_skb_dequeue(wl, &hlid))) { 7800f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 7819eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool has_data = false; 7829eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 783a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wlvif = NULL; 784f4d02007cdd56c59bdb9362c699875cb2d02c0feArik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb)) 7850f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller wlvif = wl12xx_vif_to_data(info->control.vif); 786930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov else 787930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov hlid = wl->system_hlid; 788a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 7899eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller has_data = wlvif && wl1271_tx_is_data_present(skb); 790930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset, 791930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov hlid); 7926c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 793a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 7946c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 7956c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 7966c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 797930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 7989fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis 7999fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, 8009fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis last_len); 8017a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, 8027a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira wl->aggr_buf, buf_offset, true); 8037a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 804eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 805eb96f841b9563ba34969be25615548635728faf5Ido Yariv 8066c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 8076c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 8086c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 8096c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 8106c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 8116c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 812a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 813a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 814930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 815a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 816a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 817ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 8195de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller if (wl12xx_is_dummy_packet(wl, skb)) 8205de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller /* 8215de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * fw still expects dummy packet, 8225de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * so re-enqueue it 8235de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller */ 824930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 8255de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller else 8265de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller ieee80211_free_txskb(wl->hw, skb); 827ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 8299fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis last_len = ret; 8309fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset += last_len; 831a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 8329eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (has_data) { 8339eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller desc = (struct wl1271_tx_hw_descr *) skb->data; 8349eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller __set_bit(desc->hlid, active_hlids); 8359eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 837f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 838ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 839a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 8409fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); 8417a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, 8427a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira buf_offset, true); 8437a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 844eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 845eb96f841b9563ba34969be25615548635728faf5Ido Yariv 8466c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 8476c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 8486c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 849606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 850606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 851606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 852606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 853b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { 8547a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS, 855b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv wl->tx_packets_count); 8567a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 857b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv goto out; 858b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv } 859606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 860a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 861a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 8629eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_rearm_rx_streaming(wl, active_hlids); 863eb96f841b9563ba34969be25615548635728faf5Ido Yariv 864eb96f841b9563ba34969be25615548635728faf5Ido Yarivout: 8657a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira return bus_ret; 866a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 867f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 868a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 869a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 870a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 871c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller int ret; 872a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 873a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 874c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller ret = wl1271_ps_elp_wakeup(wl); 875c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller if (ret < 0) 876c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller goto out; 877c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 878eb96f841b9563ba34969be25615548635728faf5Ido Yariv ret = wlcore_tx_work_locked(wl); 879eb96f841b9563ba34969be25615548635728faf5Ido Yariv if (ret < 0) { 880eb96f841b9563ba34969be25615548635728faf5Ido Yariv wl12xx_queue_recovery_work(wl); 881eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 882eb96f841b9563ba34969be25615548635728faf5Ido Yariv } 883c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 884c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller wl1271_ps_elp_sleep(wl); 885c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout: 886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 889d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchsstatic u8 wl1271_tx_get_rate_flags(u8 rate_class_index) 890d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs{ 891defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs u8 flags = 0; 892defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs 89343a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov /* 89443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * TODO: use wl12xx constants when this code is moved to wl12xx, as 89543a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * only it uses Tx-completion. 89643a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov */ 89743a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov if (rate_class_index <= 8) 898defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_MCS; 89943a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov 90043a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov /* 90143a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * TODO: use wl12xx constants when this code is moved to wl12xx, as 90243a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * only it uses Tx-completion. 90343a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov */ 90443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov if (rate_class_index == 0) 905defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_SHORT_GI; 90643a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov 907defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs return flags; 908d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs} 909d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs 910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 91448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct ieee80211_vif *vif; 91548e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct wl12xx_vif *wlvif; 916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 91831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 919d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs u8 rate_flags = 0; 92031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 92372b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 931990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 932ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl1271_free_tx_id(wl, id); 933ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi return; 934ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 935ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 93648e93e402ad19f570bae323b07911bdf6562af8eEliad Peller /* info->control is valid as long as we don't update info->status */ 93748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller vif = info->control.vif; 93848e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif = wl12xx_vif_to_data(vif); 93948e93e402ad19f570bae323b07911bdf6562af8eEliad Peller 94031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 94131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 94231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 943f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 94443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov rate = wlcore_rate_to_idx(wl, result->rate_class_index, 9451b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wlvif->band); 946d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); 94731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 94831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 94931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 95031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 951f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 952f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 95331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 95431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 955d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs info->status.rates[0].flags = rate_flags; 95631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 95731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 958f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 959f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 9601e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 9611e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 9621e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 9631e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 9642c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 9652c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 96697359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 9671e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 9685ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, 9695ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller hdrlen); 9705ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 9711e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 972f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 973f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 974f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 975f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 976f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 977f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 978f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 979a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 98092ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller queue_work(wl->freezable_wq, &wl->netstack_work); 98125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 982f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 983f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 984f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 985045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivint wlcore_tx_complete(struct wl1271 *wl) 986f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 9872c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches struct wl1271_acx_mem_map *memmap = wl->target_mem_map; 988ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 989f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 990045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv int ret; 991f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 992f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 993045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result), 994045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv wl->tx_res_if, sizeof(*wl->tx_res_if), false); 995045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv if (ret < 0) 996045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv goto out; 997045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv 998ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 999ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 1000ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 1001b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) + 1002b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv offsetof(struct wl1271_tx_hw_res_if, 1003b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv tx_result_host_counter), fw_counter); 1004b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv if (ret < 0) 1005b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv goto out; 1006ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 1007ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 100806f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 1009f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1010f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 1011ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 1012f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 1013f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1014f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 1015f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 1016f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 1017f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 1018f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1019f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 1020f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 1021f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 1022f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1023f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 1024f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1025045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv 1026045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivout: 1027045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv return ret; 1028f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1029045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido YarivEXPORT_SYMBOL(wlcore_tx_complete); 1030f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1031a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 1032a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 1033a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 1034f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int i; 1035a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 10361d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 1037f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int total[NUM_TX_QUEUES]; 10388591d42452f16b1888419da4456142864b08ef9eArik Nemtsov struct wl1271_link *lnk = &wl->links[hlid]; 1039a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1040a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 1041f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i] = 0; 10428591d42452f16b1888419da4456142864b08ef9eArik Nemtsov while ((skb = skb_dequeue(&lnk->tx_queue[i]))) { 1043a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 104479ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 104579ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb)) { 104679ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info = IEEE80211_SKB_CB(skb); 104779ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].idx = -1; 104879ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].count = 0; 104979ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov ieee80211_tx_status_ni(wl->hw, skb); 105079ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov } 105179ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 1052f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i]++; 1053a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 1054a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 1055a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1056a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 10578591d42452f16b1888419da4456142864b08ef9eArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 1058f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] -= total[i]; 10598591d42452f16b1888419da4456142864b08ef9eArik Nemtsov if (lnk->wlvif) 10608591d42452f16b1888419da4456142864b08ef9eArik Nemtsov lnk->wlvif->tx_queue_count[i] -= total[i]; 10618591d42452f16b1888419da4456142864b08ef9eArik Nemtsov } 1062a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 1063a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1064a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 1065a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 1066a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 10677dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */ 1068d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellervoid wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1069f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1070f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 1071f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1072f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 1073da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller for_each_set_bit(i, wlvif->links_map, wl->num_links) { 10745a99610c99625ae86d76014da25659dff72e8792Arik Nemtsov if (wlvif->bss_type == BSS_TYPE_AP_BSS && 10755a99610c99625ae86d76014da25659dff72e8792Arik Nemtsov i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) { 10766c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov /* this calls wl12xx_free_link */ 1077c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_free_sta(wl, wlvif, i); 10786c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov } else { 10796c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov u8 hlid = i; 10806c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov wl12xx_free_link(wl, wlvif, &hlid); 10816c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov } 1082f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1083d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = 0; 1084d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller 10858591d42452f16b1888419da4456142864b08ef9eArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 10868591d42452f16b1888419da4456142864b08ef9eArik Nemtsov wlvif->tx_queue_count[i] = 0; 1087d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller} 1088d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller/* caller must hold wl->mutex and TX must be stopped */ 10896639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wl12xx_tx_reset(struct wl1271 *wl) 1090d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller{ 1091d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller int i; 1092d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 1093d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct ieee80211_tx_info *info; 1094a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 10956246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov /* only reset the queues if something bad happened */ 10964c145185175dcca660265d2fcdd4feffc0249f8eVictor Goldenshtein if (wl1271_tx_total_queue_count(wl) != 0) { 1097da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller for (i = 0; i < wl->num_links; i++) 10986246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 10996246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov 11006246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 11016246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl->tx_queue_count[i] = 0; 11026246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov } 1103f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov 11042fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 11052fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 11062fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 11077dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov * This call will always wake the TX queues. 11082fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 11096639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 11102fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 111172b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov for (i = 0; i < wl->num_tx_desc; i++) { 111250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 111350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 111450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 111550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 111650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 111750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 111850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1119990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 1120ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 1121ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * Remove private headers before passing the skb to 1122ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * mac80211 1123ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 1124ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 1125ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 11262c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 11272c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 1128ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->control.hw_key->cipher == 1129ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi WLAN_CIPHER_SUITE_TKIP) { 1130ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 11315ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, 1132ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb->data, hdrlen); 11335ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 1134ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 113550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1136ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 1137ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 113850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1139c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 1140ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 114150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 1142781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 1143781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1144781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 1145781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1146781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 1147781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 1148781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 1149958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov unsigned long timeout, start_time; 115018aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov int i; 1151958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov start_time = jiffies; 1152958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov timeout = start_time + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 1153781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 11542c38849f4a247673c8203a569444042e32d82410Arik Nemtsov /* only one flush should be in progress, for consistent queue state */ 11552c38849f4a247673c8203a569444042e32d82410Arik Nemtsov mutex_lock(&wl->flush_mutex); 11562c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 1157f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov mutex_lock(&wl->mutex); 1158f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov if (wl->tx_frames_cnt == 0 && wl1271_tx_total_queue_count(wl) == 0) { 1159f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov mutex_unlock(&wl->mutex); 1160f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov goto out; 1161f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov } 1162f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov 11632c38849f4a247673c8203a569444042e32d82410Arik Nemtsov wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); 11642c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 1165781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 1166958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov wl1271_debug(DEBUG_MAC80211, "flushing tx buffer: %d %d", 1167f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_frames_cnt, 1168f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl1271_tx_total_queue_count(wl)); 1169f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov 1170f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov /* force Tx and give the driver some time to flush data */ 1171f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov mutex_unlock(&wl->mutex); 1172f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov if (wl1271_tx_total_queue_count(wl)) 1173f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov wl1271_tx_work(&wl->tx_work); 1174f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov msleep(20); 1175f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov mutex_lock(&wl->mutex); 1176f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov 1177f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov if ((wl->tx_frames_cnt == 0) && 1178f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov (wl1271_tx_total_queue_count(wl) == 0)) { 1179958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov wl1271_debug(DEBUG_MAC80211, "tx flush took %d ms", 1180958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov jiffies_to_msecs(jiffies - start_time)); 1181f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov goto out_wake; 1182781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1183781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1184781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1185958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov wl1271_warning("Unable to flush all TX buffers, " 1186958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov "timed out (timeout %d ms", 1187958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov WL1271_TX_FLUSH_TIMEOUT / 1000); 118818aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov 118918aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov /* forcibly flush all Tx buffers on our queues */ 1190da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller for (i = 0; i < wl->num_links; i++) 119118aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 11922c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 1193f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsovout_wake: 11942c38849f4a247673c8203a569444042e32d82410Arik Nemtsov wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); 1195f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov mutex_unlock(&wl->mutex); 1196f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsovout: 11972c38849f4a247673c8203a569444042e32d82410Arik Nemtsov mutex_unlock(&wl->flush_mutex); 1198f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1199a1c597f2b22cdc228de3c58784b00e80b9b53e03Arik NemtsovEXPORT_SYMBOL_GPL(wl1271_tx_flush); 1200e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1201af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) 1202e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 1203af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller if (WARN_ON(!rate_set)) 1204af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return 0; 1205e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1206af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return BIT(__ffs(rate_set)); 1207e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 120878e28062fea51c62280cd17fe6143ed583f83ba0Eliad PellerEXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get); 12096639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12101c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, 12111c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov u8 queue, enum wlcore_queue_stop_reason reason) 12126639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12131c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); 12141c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov bool stopped = !!wl->queue_stop_reasons[hwq]; 12156639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12166639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov /* queue should not be stopped for this reason */ 12171c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq])); 12186639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12196639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov if (stopped) 12206639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov return; 12216639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12221c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov ieee80211_stop_queue(wl->hw, hwq); 12236639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12246639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12251c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, 12266639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 12276639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12286639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 12296639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12306639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 12311c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov wlcore_stop_queue_locked(wl, wlvif, queue, reason); 12326639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 12336639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12346639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12351c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue, 12366639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 12376639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12386639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 12391c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); 12406639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12416639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 12426639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12436639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov /* queue should not be clear for this reason */ 12441c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq])); 12456639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12461c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov if (wl->queue_stop_reasons[hwq]) 12476639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov goto out; 12486639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12491c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov ieee80211_wake_queue(wl->hw, hwq); 12506639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12516639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovout: 12526639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 12536639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12546639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12556639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_stop_queues(struct wl1271 *wl, 12566639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 12576639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12586639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov int i; 12591c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov unsigned long flags; 12606639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12611c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 12626639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12631c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov /* mark all possible queues as stopped */ 12641c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) 12651c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WARN_ON_ONCE(test_and_set_bit(reason, 12661c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov &wl->queue_stop_reasons[i])); 12676639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12681c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov /* use the global version to make sure all vifs in mac80211 we don't 12691c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov * know are stopped. 12701c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov */ 12711c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov ieee80211_stop_queues(wl->hw); 12721c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov 12731c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 12746639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12756639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12761c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_wake_queues(struct wl1271 *wl, 12771c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov enum wlcore_queue_stop_reason reason) 12786639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12796639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov int i; 12806639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 12816639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12826639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 12836639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12841c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov /* mark all possible queues as awake */ 12851c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++) 12861c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov WARN_ON_ONCE(!test_and_clear_bit(reason, 12871c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov &wl->queue_stop_reasons[i])); 12886639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12891c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov /* use the global version to make sure all vifs in mac80211 we don't 12901c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov * know are woken up. 12911c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov */ 12921c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov ieee80211_wake_queues(wl->hw); 12936639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12946639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 12956639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12966639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12971c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovbool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, 12981c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov struct wl12xx_vif *wlvif, u8 queue, 12991c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov enum wlcore_queue_stop_reason reason) 13006639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 1301d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov unsigned long flags; 1302d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov bool stopped; 1303d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov 1304d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 1305d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue, 1306d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov reason); 1307d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 1308d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov 1309d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov return stopped; 1310d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov} 1311d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov 1312d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsovbool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl, 1313d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov struct wl12xx_vif *wlvif, u8 queue, 1314d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov enum wlcore_queue_stop_reason reason) 1315d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov{ 13161c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); 1317d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov 13188910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov assert_spin_locked(&wl->wl_lock); 13191c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov return test_bit(reason, &wl->queue_stop_reasons[hwq]); 13206639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 13216639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 1322d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsovbool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1323d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov u8 queue) 13246639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 13251c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue); 1326d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov 13278910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov assert_spin_locked(&wl->wl_lock); 13281c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov return !!wl->queue_stop_reasons[hwq]; 13296639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 1330