tx.c revision c3e06fc03b64c626e150c33b897ddd728c30a316
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> 27f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 28c31be25a7144ebc9b7a22128909bac7654d4c46bLuciano Coelho#include "wlcore.h" 290f4e31222a2c0b93f25a87effd2033cb78c7a79cLuciano Coelho#include "debug.h" 3000d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h" 3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "ps.h" 3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "tx.h" 3356d4f8f685c073c7ed7203b78c57f5d893d65102Arik Nemtsov#include "event.h" 34b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov#include "hw_ops.h" 35f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3600782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho/* 3700782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * TODO: this is here just for now, it must be removed when the data 3800782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * operations are in place. 3900782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho */ 4000782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho#include "../wl12xx/reg.h" 4100782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho 42536129c8ad35de87ff2f864f205a54ac32bfebccEliad Pellerstatic int wl1271_set_default_wep_key(struct wl1271 *wl, 43536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct wl12xx_vif *wlvif, u8 id) 447f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov{ 457f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov int ret; 46536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); 477f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 487f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (is_ap) 49c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, 50a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller wlvif->ap.bcast_hlid); 517f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov else 52154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); 537f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 547f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (ret < 0) 557f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return ret; 567f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 577f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); 587f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return 0; 597f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov} 607f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 6125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 62f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 6325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv int id; 6425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6572b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc); 6672b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (id >= wl->num_tx_desc) 6725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return -EBUSY; 6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv __set_bit(id, wl->tx_frames_map); 7025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = skb; 7125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt++; 7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return id; 7325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv} 74f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 75872b345fbaef290f890d0bbd34b78ab50269980fArik Nemtsovvoid wl1271_free_tx_id(struct wl1271 *wl, int id) 7625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{ 7725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (__test_and_clear_bit(id, wl->tx_frames_map)) { 7872b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc)) 79ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 80ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv 8125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 8225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 8325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 84f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 85872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl1271_free_tx_id); 86f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 8799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 8899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 8999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 9099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 9199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 9299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 9399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 9499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 9599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 9699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 9799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 9899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 9999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov if (ieee80211_is_auth(hdr->frame_control)) 10099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 10199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 10299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 103c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerstatic void wl1271_tx_regulate_link(struct wl1271 *wl, 104c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller struct wl12xx_vif *wlvif, 105c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller u8 hlid) 106b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 107da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov bool fw_ps, single_sta; 1089b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov u8 tx_pkts; 109b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 110c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (WARN_ON(!test_bit(hlid, wlvif->links_map))) 111b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 112b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 113b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 1149b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov tx_pkts = wl->links[hlid].allocated_pkts; 115da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov single_sta = (wl->active_sta_count == 1); 116b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 117b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 118b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 119b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 120da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov * Make an exception if this is the only connected station. In this 121da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov * case FW-memory congestion is not a problem. 122b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 123da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) 1246e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller wl12xx_ps_link_start(wl, wlvif, hlid, true); 125b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 126b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 127f8e0af6b8732b47c2531a280753d29a4ca2d114bArik Nemtsovbool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) 128f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 129f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->dummy_packet == skb; 130f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 131872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl12xx_is_dummy_packet); 132f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 1332b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsovstatic u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1342b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov struct sk_buff *skb, struct ieee80211_sta *sta) 135a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 1362b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov if (sta) { 137a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 138a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1392b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov wl_sta = (struct wl1271_station *)sta->drv_priv; 140a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl_sta->hlid; 141a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 142a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_hdr *hdr; 143a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 14453d40d0b863e22b697f8d85e1f95cb6f9d2d95b1Eliad Peller if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags)) 145f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->system_hlid; 146f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 147a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov hdr = (struct ieee80211_hdr *)skb->data; 14845b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller if (is_multicast_ether_addr(ieee80211_get_DA(hdr))) 149a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller return wlvif->ap.bcast_hlid; 15045b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller else 15145b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller return wlvif->ap.global_hlid; 152a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 153a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 154a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 155d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pelleru8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, 1562b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov struct sk_buff *skb, struct ieee80211_sta *sta) 157f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 158df4c849f4608e8962f019fea6021ebd602a11641Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data; 159df4c849f4608e8962f019fea6021ebd602a11641Eliad Peller 1600f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!wlvif || wl12xx_is_dummy_packet(wl, skb)) 161f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->system_hlid; 162f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 163536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (wlvif->bss_type == BSS_TYPE_AP_BSS) 1642b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta); 165f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 166ba8447f64159927baf673d827e404605471d8f68Eliad Peller if ((test_bit(WLVIF_FLAG_STA_ASSOCIATED, &wlvif->flags) || 167eee514e3d6cecc7abdf1b27734169004fefb0941Eliad Peller test_bit(WLVIF_FLAG_IBSS_JOINED, &wlvif->flags)) && 168df4c849f4608e8962f019fea6021ebd602a11641Eliad Peller !ieee80211_is_auth(hdr->frame_control) && 169df4c849f4608e8962f019fea6021ebd602a11641Eliad Peller !ieee80211_is_assoc_req(hdr->frame_control)) 170154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller return wlvif->sta.hlid; 171f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller else 172afaf8bdb2b08bbf493b03757243821df72b26c53Eliad Peller return wlvif->dev_hlid; 173f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 174f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 175b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsovunsigned int wlcore_calc_packet_alignment(struct wl1271 *wl, 176b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov unsigned int packet_length) 1770da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{ 1789fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) || 1799fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN)) 180f83985bb5f8f0f25d44ab7b108a709a52aa1c5e0Arik Nemtsov return ALIGN(packet_length, WL1271_TX_ALIGN_TO); 1819fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis else 1829fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); 1830da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv} 184b3b4b4b812018a06221b6d7b88a5540fccae2940Arik NemtsovEXPORT_SYMBOL(wlcore_calc_packet_alignment); 1850da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv 186a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, 187536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, u32 buf_offset, 18832bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov u8 hlid, bool is_gem) 189f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 190f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 191f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 1925c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 193742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int id, ret = -EBUSY, ac; 19432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov u32 spare_blocks; 195f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 196a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) 1976c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 198a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 19932bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem); 20032bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov 201f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 20225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 203f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 204f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 205f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 206b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks); 20748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 208f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 209f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 210f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 211f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2124a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks, 2134a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov spare_blocks); 214ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 215f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 216f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 217f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 2187bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov wl->tx_allocated_blocks += total_blocks; 219f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 22055df5afb13718cda49128fa5985556df91d07765Arik Nemtsov /* If the FW was empty before, arm the Tx watchdog */ 22155df5afb13718cda49128fa5985556df91d07765Arik Nemtsov if (wl->tx_allocated_blocks == total_blocks) 22255df5afb13718cda49128fa5985556df91d07765Arik Nemtsov wl12xx_rearm_tx_watchdog_locked(wl); 22355df5afb13718cda49128fa5985556df91d07765Arik Nemtsov 224742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 225742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov wl->tx_allocated_pkts[ac]++; 226bf54e301671a6ece6c94550294dc7faf14158cd3Arik Nemtsov 22732bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb) && wlvif && 2280f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller wlvif->bss_type == BSS_TYPE_AP_BSS && 229c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller test_bit(hlid, wlvif->ap.sta_hlid_map)) 2309b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov wl->links[hlid].allocated_pkts++; 23109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 232f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 233f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 234f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 235f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 236f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 237781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 23825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 239781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 240f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 241f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 242f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 243f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 244a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, 245536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, 246536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct ieee80211_tx_info *control, u8 hlid) 247f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 248ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 249f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 2506f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov int ac, rate_idx; 251ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 252cf00f379d82d170712150588accd2ebe316c2226John W. Linville u16 tx_attr = 0; 253f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller __le16 frame_control; 254f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller struct ieee80211_hdr *hdr; 255f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller u8 *frame_start; 256a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller bool is_dummy; 257f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 258f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 259f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_start = (u8 *)(desc + 1); 260f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller hdr = (struct ieee80211_hdr *)(frame_start + extra); 261f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_control = hdr->frame_control; 262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2631e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 2641e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 265f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller int hdrlen = ieee80211_hdrlen(frame_control); 266f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller memmove(frame_start, hdr, hdrlen); 2672fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov skb_set_network_header(skb, skb_network_offset(skb) + extra); 2681e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 2691e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 270f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 271ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 272ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 273ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 274c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 275a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 2760f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) 277c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 278c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 279c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 280f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 281db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller /* queue */ 282c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 283db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller desc->tid = skb->priority; 284c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 285a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller if (is_dummy) { 286ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 287ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * FW expects the dummy packet to have an invalid session id - 288ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * any session id that is different than the one set in the join 289ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 29098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller tx_attr = (SESSION_COUNTER_INVALID << 291ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_OFST_SESSION_COUNTER) & 292ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_SESSION_COUNTER; 293ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 294ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; 2950f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller } else if (wlvif) { 296ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* configure the tx attributes */ 29798b8625301e55bd3e4340f704edc378e4707e577Eliad Peller tx_attr = wlvif->session_counter << 29898b8625301e55bd3e4340f704edc378e4707e577Eliad Peller TX_HW_ATTR_OFST_SESSION_COUNTER; 299ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 300ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 30179b122dc51797b650201f21360481a0450e9b7e4Eliad Peller desc->hlid = hlid; 3020f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif) 303a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller rate_idx = 0; 304a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { 3058f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira /* 3064340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller * if the packets are data packets 3078f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira * send them with AP rate policies (EAPOLs are an exception), 3088f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira * otherwise use default basic rates 3098f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira */ 310bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky if (skb->protocol == cpu_to_be16(ETH_P_PAE)) 3118f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira rate_idx = wlvif->sta.basic_rate_idx; 312bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky else if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) 313bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky rate_idx = wlvif->sta.p2p_rate_idx; 3144340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller else if (ieee80211_is_data(frame_control)) 315e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.ap_rate_idx; 316c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 317e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.basic_rate_idx; 318c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 319a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller if (hlid == wlvif->ap.global_hlid) 320e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.mgmt_rate_idx; 321bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky else if (hlid == wlvif->ap.bcast_hlid || 322c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov skb->protocol == cpu_to_be16(ETH_P_PAE) || 323c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov !ieee80211_is_data(frame_control)) 324c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov /* 325c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov * send non-data, bcast and EAPOLs using the 326c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov * min basic rate 327c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov */ 328e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.bcast_rate_idx; 329e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov else 330e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.ucast_rate_idx[ac]; 331c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 332c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 333c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 334d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 335f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller /* for WEP shared auth - no fw encryption is needed */ 336f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller if (ieee80211_is_auth(frame_control) && 337f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller ieee80211_has_protected(frame_control)) 338f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; 339f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller 340d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 3416f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov 3422fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov wlcore_hw_set_tx_desc_csum(wl, desc, skb); 3436f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov wlcore_hw_set_tx_desc_data_len(wl, desc, skb); 344f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 345f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 346f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 347a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, 348930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov struct sk_buff *skb, u32 buf_offset, u8 hlid) 349f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 350f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 351f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 352f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 353a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 354536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_dummy; 35532bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov bool is_gem = false; 356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3577a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (!skb) { 3587a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira wl1271_error("discarding null skb"); 359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 3607a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira } 361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 362930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov if (hlid == WL12XX_INVALID_LINK_ID) { 363930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_error("invalid hlid. dropping skb 0x%p", skb); 364930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov return -EINVAL; 365930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov } 366930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov 367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 369536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 370536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller 3712c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 3722c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 37397359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 3745ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller extra = WL1271_EXTRA_SPACE_TKIP; 375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 3777f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 3787f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 3797f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 3807f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 3817f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 3827f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 384f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller if (unlikely(is_wep && wlvif->default_key != idx)) { 385536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller ret = wl1271_set_default_wep_key(wl, wlvif, idx); 386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 388f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller wlvif->default_key = idx; 389f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 39032bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov 39132bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov is_gem = (cipher == WL1271_CIPHER_SUITE_GEM); 392f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 39309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 39432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid, 39532bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov is_gem); 396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 398f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 399a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); 400fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov 4010f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { 40299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, skb); 403c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_tx_regulate_link(wl, wlvif, hlid); 404b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 40599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 406a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 40748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * The length of each packet is stored in terms of 40848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * words. Thus, we must pad the skb data to make sure its 40948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * length is aligned. The number of padding bytes is computed 41048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * and set in wl1271_tx_fill_hdr. 41148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * In special cases, we want to align to a specific block size 41248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * (eg. for wl128x with SDIO we align to 256). 413a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 414b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov total_len = wlcore_calc_packet_alignment(wl, skb->len); 41548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 416a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 417a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 419990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv /* Revert side effects in the dummy packet skb, so it can be reused */ 420536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (is_dummy) 421990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 422990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 423a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 424f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 426af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, 427af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller enum ieee80211_band rate_band) 428830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 429830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 430830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 431830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 432830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 433af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller band = wl->hw->wiphy->bands[rate_band]; 434830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 435830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 436830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 437830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 438830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 439830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 440b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov /* MCS rates indication are on bits 16 - 31 */ 44118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 44218357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 443b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov for (bit = 0; bit < 16; bit++) { 44418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 44518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 44618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 44718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 44818357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 449830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 450830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 451830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 452a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 4532fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 454708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov int i; 4552fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 456708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 4576639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov if (wlcore_is_queue_stopped_by_reason(wl, i, 4586639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov WLCORE_QUEUE_STOP_REASON_WATERMARK) && 459f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { 460708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov /* firmware buffer has space, restart queues */ 4616639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wlcore_wake_queue(wl, i, 4626639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov WLCORE_QUEUE_STOP_REASON_WATERMARK); 463708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov } 4642fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 4652fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 4662fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 467742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsovstatic struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, 468742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queues) 469742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov{ 470742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int i, q = -1, ac; 471742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov u32 min_pkts = 0xffffffff; 472742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 473742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* 474742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * Find a non-empty ac where: 475742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 1. There are packets to transmit 476742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 2. The FW has the least allocated blocks 477742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 478742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * We prioritize the ACs according to VO>VI>BE>BK 479742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov */ 480742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 481742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(i); 482742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!skb_queue_empty(&queues[ac]) && 483742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov (wl->tx_allocated_pkts[ac] < min_pkts)) { 484742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov q = ac; 485742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov min_pkts = wl->tx_allocated_pkts[q]; 486742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 487742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 488742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 489742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (q == -1) 490742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return NULL; 491742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 492742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return &queues[q]; 493742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov} 494742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 495d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, 496d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct wl1271_link *lnk) 4976742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 498d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 4996742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 500742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queue; 5016742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 502d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller queue = wl1271_select_queue(wl, lnk->tx_queue); 503742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!queue) 504d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller return NULL; 505742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 506742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov skb = skb_dequeue(queue); 5076742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 508f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 5096742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 5106246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 511f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 5126742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5136742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 5146742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5156742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 5166742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5176742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 518d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, 519930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov struct wl12xx_vif *wlvif, 520930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov u8 *hlid) 521a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 522a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 523a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 524a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 525a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 5264438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; 527a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 528a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 529c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller for (i = 0; i < WL12XX_MAX_LINKS; i++) { 530c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller h = (start_hlid + i) % WL12XX_MAX_LINKS; 531a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 532742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* only consider connected stations */ 533c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (!test_bit(h, wlvif->links_map)) 534742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 535742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 536d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); 537d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 538742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 539742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 540d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = h; 541d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller break; 542a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 543a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 544d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 5454438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller wlvif->last_tx_hlid = 0; 546a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 547930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov *hlid = wlvif->last_tx_hlid; 548a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 549a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 550a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 551930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid) 552a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 553990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv unsigned long flags; 554e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller struct wl12xx_vif *wlvif = wl->last_wlvif; 555990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv struct sk_buff *skb = NULL; 556990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 55749c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* continue from last wlvif (round robin) */ 558e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (wlvif) { 559e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif_continue(wl, wlvif) { 560930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); 561e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (skb) { 562e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl->last_wlvif = wlvif; 563e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller break; 564e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 565e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 566e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 567e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller 56849c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* dequeue from the system HLID before the restarting wlvif list */ 569930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov if (!skb) { 57049c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); 571930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov *hlid = wl->system_hlid; 572930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov } 57349c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 57449c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* do a new pass over the wlvif list */ 575e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (!skb) { 576e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif(wl, wlvif) { 577930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov skb = wl12xx_vif_skb_dequeue(wl, wlvif, hlid); 578e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (skb) { 579e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl->last_wlvif = wlvif; 580e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller break; 581e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 58249c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 58349c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* 58449c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov * No need to continue after last_wlvif. The previous 58549c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov * pass should have found it. 58649c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov */ 58749c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov if (wlvif == wl->last_wlvif) 58849c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov break; 589e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 590a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller } 591a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 592990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!skb && 593990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 594f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q; 595f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov 596990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl->dummy_packet; 597930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov *hlid = wl->system_hlid; 598f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 599990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_lock_irqsave(&wl->wl_lock, flags); 6006246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 601f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 602990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 603990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } 604990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 605990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return skb; 606a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 607a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 608d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, 609930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov struct sk_buff *skb, u8 hlid) 6106742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 6116742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 6126742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 6136742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 614990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 615990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 616d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller } else { 617a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 618a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 619a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 6204438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % 621d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller WL12XX_MAX_LINKS; 622a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 623a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 6246742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 625f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]++; 6266742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 6276742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 6286742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 62977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb) 63077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{ 63177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 63277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 63377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller return ieee80211_is_data_present(hdr->frame_control); 63477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller} 63577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 6369eb599e9c62dcfd4efece1936c385381b366b684Eliad Pellervoid wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) 6379eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller{ 6389eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl12xx_vif *wlvif; 6399eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u32 timeout; 6409eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u8 hlid; 6419eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6429eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.interval) 6439eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 6449eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6459eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.always && 6469eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) 6479eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 6489eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6499eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller timeout = wl->conf.rx_streaming.duration; 6509eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_for_each_wlvif_sta(wl, wlvif) { 6519eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool found = false; 6529eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { 6539eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (test_bit(hlid, wlvif->links_map)) { 6549eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller found = true; 6559eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller break; 6569eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6579eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6589eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6599eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!found) 6609eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller continue; 6619eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6629eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller /* enable rx streaming */ 6630744bdb60b51dce54553d5af9a6133f1fe419032Eliad Peller if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) 6649eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller ieee80211_queue_work(wl->hw, 6659eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller &wlvif->rx_streaming_enable_work); 6669eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6679eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller mod_timer(&wlvif->rx_streaming_timer, 6689eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller jiffies + msecs_to_jiffies(timeout)); 6699eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6709eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller} 6719eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6727a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira/* 6737a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * Returns failure values only in case of failed bus ops within this function. 6747a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * wl1271_prepare_tx_frame retvals won't be returned in order to avoid 6757a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * triggering recovery by higher layers when not necessary. 6767a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery 6777a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame 6787a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING 6797a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * within prepare_tx_frame code but there's nothing we should do about those 6807a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * as well. 6817a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira */ 682eb96f841b9563ba34969be25615548635728faf5Ido Yarivint wlcore_tx_work_locked(struct wl1271 *wl) 683f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 684a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller struct wl12xx_vif *wlvif; 685f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 6869eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl1271_tx_hw_descr *desc; 6879fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis u32 buf_offset = 0, last_len = 0; 6886c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 6899eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; 690eb96f841b9563ba34969be25615548635728faf5Ido Yariv int ret = 0; 6917a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira int bus_ret = 0; 692930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov u8 hlid; 693f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6944cc533830b7e6b309e8b73196c410951fc2bed91Ido Yariv if (unlikely(wl->state != WLCORE_STATE_ON)) 6957a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira return 0; 696f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 697930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov while ((skb = wl1271_skb_dequeue(wl, &hlid))) { 6980f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 6999eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool has_data = false; 7009eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 701a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wlvif = NULL; 7020f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) 7030f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller wlvif = wl12xx_vif_to_data(info->control.vif); 704930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov else 705930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov hlid = wl->system_hlid; 706a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 7079eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller has_data = wlvif && wl1271_tx_is_data_present(skb); 708930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset, 709930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov hlid); 7106c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 711a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 7126c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 7136c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 7146c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 715930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 7169fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis 7179fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, 7189fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis last_len); 7197a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, 7207a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira wl->aggr_buf, buf_offset, true); 7217a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 722eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 723eb96f841b9563ba34969be25615548635728faf5Ido Yariv 7246c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 7256c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 7266c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 7276c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 7286c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 7296c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 730a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 731a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 732930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 733a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 734a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 735ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 736f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 7375de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller if (wl12xx_is_dummy_packet(wl, skb)) 7385de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller /* 7395de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * fw still expects dummy packet, 7405de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * so re-enqueue it 7415de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller */ 742930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov wl1271_skb_queue_head(wl, wlvif, skb, hlid); 7435de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller else 7445de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller ieee80211_free_txskb(wl->hw, skb); 745ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 746f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 7479fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis last_len = ret; 7489fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset += last_len; 749a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 7509eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (has_data) { 7519eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller desc = (struct wl1271_tx_hw_descr *) skb->data; 7529eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller __set_bit(desc->hlid, active_hlids); 7539eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 754f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 755f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 756ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 757a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 7589fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len); 7597a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, 7607a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira buf_offset, true); 7617a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 762eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 763eb96f841b9563ba34969be25615548635728faf5Ido Yariv 7646c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 7656c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 7666c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 767606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 768606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 769606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 770606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 771b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) { 7727a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS, 773b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv wl->tx_packets_count); 7747a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira if (bus_ret < 0) 775b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv goto out; 776b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv } 777606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 778a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 779a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 7809eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_rearm_rx_streaming(wl, active_hlids); 781eb96f841b9563ba34969be25615548635728faf5Ido Yariv 782eb96f841b9563ba34969be25615548635728faf5Ido Yarivout: 7837a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira return bus_ret; 784a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 785f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 786a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 787a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 788a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 789c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller int ret; 790a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 791a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 792c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller ret = wl1271_ps_elp_wakeup(wl); 793c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller if (ret < 0) 794c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller goto out; 795c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 796eb96f841b9563ba34969be25615548635728faf5Ido Yariv ret = wlcore_tx_work_locked(wl); 797eb96f841b9563ba34969be25615548635728faf5Ido Yariv if (ret < 0) { 798eb96f841b9563ba34969be25615548635728faf5Ido Yariv wl12xx_queue_recovery_work(wl); 799eb96f841b9563ba34969be25615548635728faf5Ido Yariv goto out; 800eb96f841b9563ba34969be25615548635728faf5Ido Yariv } 801c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 802c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller wl1271_ps_elp_sleep(wl); 803c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout: 804f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 805f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 806f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 807d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchsstatic u8 wl1271_tx_get_rate_flags(u8 rate_class_index) 808d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs{ 809defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs u8 flags = 0; 810defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs 81143a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov /* 81243a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * TODO: use wl12xx constants when this code is moved to wl12xx, as 81343a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * only it uses Tx-completion. 81443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov */ 81543a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov if (rate_class_index <= 8) 816defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_MCS; 81743a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov 81843a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov /* 81943a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * TODO: use wl12xx constants when this code is moved to wl12xx, as 82043a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov * only it uses Tx-completion. 82143a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov */ 82243a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov if (rate_class_index == 0) 823defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_SHORT_GI; 82443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov 825defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs return flags; 826d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs} 827d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs 828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 829f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 83248e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct ieee80211_vif *vif; 83348e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct wl12xx_vif *wlvif; 834f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 835f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 83631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 837d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs u8 rate_flags = 0; 83831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 839f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 840f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 84172b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 842f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 843f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 844f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 845f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 846f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 847f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 848f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 849990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 850ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl1271_free_tx_id(wl, id); 851ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi return; 852ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 853ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 85448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller /* info->control is valid as long as we don't update info->status */ 85548e93e402ad19f570bae323b07911bdf6562af8eEliad Peller vif = info->control.vif; 85648e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif = wl12xx_vif_to_data(vif); 85748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller 85831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 85931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 86031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 861f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 86243a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov rate = wlcore_rate_to_idx(wl, result->rate_class_index, 8631b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wlvif->band); 864d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); 86531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 86631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 86731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 86831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 869f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 870f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 87131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 87231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 873d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs info->status.rates[0].flags = rate_flags; 87431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 87531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 877f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 878b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 879b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update sequence number only when relevant, i.e. only in 880b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * sessions of TKIP, AES and GEM (not in open or WEP sessions) 881b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 882b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski if (info->control.hw_key && 883b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || 884b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || 885b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { 886b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 fw_lsb = result->tx_security_sequence_number_lsb; 88748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller u8 cur_lsb = wlvif->tx_security_last_seq_lsb; 888b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski 889b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 890b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update security sequence number, taking care of potential 891b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * wrap-around 892b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 89348e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; 89448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif->tx_security_last_seq_lsb = fw_lsb; 895b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski } 896ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 8971e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 8981e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 8991e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 9001e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 9012c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 9022c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 90397359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 9041e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 9055ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, 9065ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller hdrlen); 9075ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 9081e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 909f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 915f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 916a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 91792ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller queue_work(wl->freezable_wq, &wl->netstack_work); 91825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 919f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 922045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivint wlcore_tx_complete(struct wl1271 *wl) 923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 9242c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches struct wl1271_acx_mem_map *memmap = wl->target_mem_map; 925ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 927045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv int ret; 928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 930045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result), 931045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv wl->tx_res_if, sizeof(*wl->tx_res_if), false); 932045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv if (ret < 0) 933045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv goto out; 934045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv 935ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 936ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 937ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 938b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) + 939b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv offsetof(struct wl1271_tx_hw_res_if, 940b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv tx_result_host_counter), fw_counter); 941b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv if (ret < 0) 942b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv goto out; 943ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 944ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 94506f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 946f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 947f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 948ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 949f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 950f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 951f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 952f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 953f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 954f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 955f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 956f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 957f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 958f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 959f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 960f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 961f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 962045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv 963045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivout: 964045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv return ret; 965f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 966045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido YarivEXPORT_SYMBOL(wlcore_tx_complete); 967f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 968a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 969a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 970a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 971f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int i; 972a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 9731d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 974f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int total[NUM_TX_QUEUES]; 975a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 976a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 977f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i] = 0; 978a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 979a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 98079ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 98179ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb)) { 98279ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info = IEEE80211_SKB_CB(skb); 98379ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].idx = -1; 98479ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].count = 0; 98579ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov ieee80211_tx_status_ni(wl->hw, skb); 98679ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov } 98779ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 988f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i]++; 989a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 990a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 991a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 992a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 993f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 994f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] -= total[i]; 995a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 996a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 997a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 998a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 999a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 10007dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */ 1001d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellervoid wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) 1002f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 1003f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 1004f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1005f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 1006d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { 1007d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (wlvif->bss_type == BSS_TYPE_AP_BSS) 1008c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_free_sta(wl, wlvif, i); 1009d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller else 1010d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->sta.ba_rx_bitmap = 0; 1011f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov 1012d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl->links[i].allocated_pkts = 0; 1013d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl->links[i].prev_freed_pkts = 0; 1014f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 1015d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = 0; 1016d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller 1017d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller} 1018d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller/* caller must hold wl->mutex and TX must be stopped */ 10196639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wl12xx_tx_reset(struct wl1271 *wl) 1020d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller{ 1021d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller int i; 1022d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 1023d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct ieee80211_tx_info *info; 1024a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 10256246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov /* only reset the queues if something bad happened */ 10266246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { 10276246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov for (i = 0; i < WL12XX_MAX_LINKS; i++) 10286246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 10296246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov 10306246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 10316246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl->tx_queue_count[i] = 0; 10326246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov } 1033f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov 10342fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 10352fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 10362fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 10377dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov * This call will always wake the TX queues. 10382fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 10396639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 10402fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 104172b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov for (i = 0; i < wl->num_tx_desc; i++) { 104250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 104350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 104450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 104550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 104650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 104750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 104850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1049990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 1050ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 1051ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * Remove private headers before passing the skb to 1052ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * mac80211 1053ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 1054ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 1055ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 10562c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) && 10572c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov info->control.hw_key && 1058ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->control.hw_key->cipher == 1059ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi WLAN_CIPHER_SUITE_TKIP) { 1060ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 10615ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, 1062ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb->data, hdrlen); 10635ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 1064ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 106550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1066ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 1067ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 106850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1069c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 1070ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 107150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 1072781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 1073781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1074781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 1075781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1076781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 1077781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 1078781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 1079781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen unsigned long timeout; 108018aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov int i; 1081781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 1082781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 10832c38849f4a247673c8203a569444042e32d82410Arik Nemtsov /* only one flush should be in progress, for consistent queue state */ 10842c38849f4a247673c8203a569444042e32d82410Arik Nemtsov mutex_lock(&wl->flush_mutex); 10852c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 10862c38849f4a247673c8203a569444042e32d82410Arik Nemtsov wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); 10872c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 1088781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 1089781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_lock(&wl->mutex); 1090a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 1091f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_frames_cnt, 1092f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl1271_tx_total_queue_count(wl)); 1093f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov if ((wl->tx_frames_cnt == 0) && 1094f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov (wl1271_tx_total_queue_count(wl) == 0)) { 1095781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 10962c38849f4a247673c8203a569444042e32d82410Arik Nemtsov goto out; 1097781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1098781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 1099781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen msleep(1); 1100781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1101781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1102781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen wl1271_warning("Unable to flush all TX buffers, timed out."); 110318aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov 110418aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov /* forcibly flush all Tx buffers on our queues */ 110518aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov mutex_lock(&wl->mutex); 110618aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov for (i = 0; i < WL12XX_MAX_LINKS; i++) 110718aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 110818aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov mutex_unlock(&wl->mutex); 11092c38849f4a247673c8203a569444042e32d82410Arik Nemtsov 11102c38849f4a247673c8203a569444042e32d82410Arik Nemtsovout: 11112c38849f4a247673c8203a569444042e32d82410Arik Nemtsov wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH); 11122c38849f4a247673c8203a569444042e32d82410Arik Nemtsov mutex_unlock(&wl->flush_mutex); 1113f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1114a1c597f2b22cdc228de3c58784b00e80b9b53e03Arik NemtsovEXPORT_SYMBOL_GPL(wl1271_tx_flush); 1115e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1116af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) 1117e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 1118af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller if (WARN_ON(!rate_set)) 1119af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return 0; 1120e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1121af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return BIT(__ffs(rate_set)); 1122e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 11236639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11246639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_stop_queue_locked(struct wl1271 *wl, u8 queue, 11256639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 11266639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11276639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov bool stopped = !!wl->queue_stop_reasons[queue]; 11286639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11296639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov /* queue should not be stopped for this reason */ 11306639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov WARN_ON(test_and_set_bit(reason, &wl->queue_stop_reasons[queue])); 11316639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11326639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov if (stopped) 11336639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov return; 11346639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11356639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov ieee80211_stop_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); 11366639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 11376639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11386639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_stop_queue(struct wl1271 *wl, u8 queue, 11396639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 11406639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11416639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 11426639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11436639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 11446639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wlcore_stop_queue_locked(wl, queue, reason); 11456639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 11466639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 11476639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11486639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_wake_queue(struct wl1271 *wl, u8 queue, 11496639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 11506639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11516639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 11526639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11536639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 11546639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11556639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov /* queue should not be clear for this reason */ 11566639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov WARN_ON(!test_and_clear_bit(reason, &wl->queue_stop_reasons[queue])); 11576639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11586639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov if (wl->queue_stop_reasons[queue]) 11596639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov goto out; 11606639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11616639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov ieee80211_wake_queue(wl->hw, wl1271_tx_get_mac80211_queue(queue)); 11626639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11636639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovout: 11646639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 11656639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 11666639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11676639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_stop_queues(struct wl1271 *wl, 11686639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 11696639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11706639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov int i; 11716639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11726639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 11736639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wlcore_stop_queue(wl, i, reason); 11746639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 1175a1c597f2b22cdc228de3c58784b00e80b9b53e03Arik NemtsovEXPORT_SYMBOL_GPL(wlcore_stop_queues); 11766639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11776639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_wake_queues(struct wl1271 *wl, 11786639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 11796639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11806639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov int i; 11816639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11826639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 11836639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wlcore_wake_queue(wl, i, reason); 11846639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 1185a1c597f2b22cdc228de3c58784b00e80b9b53e03Arik NemtsovEXPORT_SYMBOL_GPL(wlcore_wake_queues); 11866639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11876639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_reset_stopped_queues(struct wl1271 *wl) 11886639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 11896639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov int i; 11906639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov unsigned long flags; 11916639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11926639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 11936639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11946639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 11956639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov if (!wl->queue_stop_reasons[i]) 11966639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov continue; 11976639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 11986639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wl->queue_stop_reasons[i] = 0; 11996639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov ieee80211_wake_queue(wl->hw, 12006639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov wl1271_tx_get_mac80211_queue(i)); 12016639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov } 12026639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12036639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 12046639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12056639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12066639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovbool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl, u8 queue, 12076639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov enum wlcore_queue_stop_reason reason) 12086639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12096639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov return test_bit(reason, &wl->queue_stop_reasons[queue]); 12106639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 12116639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov 12126639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovbool wlcore_is_queue_stopped(struct wl1271 *wl, u8 queue) 12136639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{ 12146639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov return !!wl->queue_stop_reasons[queue]; 12156639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov} 1216