tx.c revision 72b0624fa5b766133fd0be9099724324b1f0d70e
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" 34f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3500782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho/* 3600782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * TODO: this is here just for now, it must be removed when the data 3700782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * operations are in place. 3800782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho */ 3900782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho#include "../wl12xx/reg.h" 4000782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho 41536129c8ad35de87ff2f864f205a54ac32bfebccEliad Pellerstatic int wl1271_set_default_wep_key(struct wl1271 *wl, 42536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct wl12xx_vif *wlvif, u8 id) 437f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov{ 447f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov int ret; 45536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); 467f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 477f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (is_ap) 48c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, 49a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller wlvif->ap.bcast_hlid); 507f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov else 51154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid); 527f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 537f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (ret < 0) 547f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return ret; 557f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 567f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); 577f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return 0; 587f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov} 597f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 6025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 61f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 6225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv int id; 6325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6472b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc); 6572b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (id >= wl->num_tx_desc) 6625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return -EBUSY; 6725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv __set_bit(id, wl->tx_frames_map); 6925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = skb; 7025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt++; 7125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return id; 7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv} 73f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 7425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic void wl1271_free_tx_id(struct wl1271 *wl, int id) 7525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{ 7625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (__test_and_clear_bit(id, wl->tx_frames_map)) { 7772b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc)) 78ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 79ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv 8025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 8125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 8225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 83f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 84f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 8599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 8699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 8799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 8899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 8999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 9099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 9199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 9299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 9399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 9499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 9599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 9699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 9799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov if (ieee80211_is_auth(hdr->frame_control)) 9899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 9999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 10099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 101c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerstatic void wl1271_tx_regulate_link(struct wl1271 *wl, 102c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller struct wl12xx_vif *wlvif, 103c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller u8 hlid) 104b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 105da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov bool fw_ps, single_sta; 1069b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov u8 tx_pkts; 107b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 108c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (WARN_ON(!test_bit(hlid, wlvif->links_map))) 109b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 110b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 111b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 1129b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov tx_pkts = wl->links[hlid].allocated_pkts; 113da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov single_sta = (wl->active_sta_count == 1); 114b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 115b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 116b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 117b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 118da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov * Make an exception if this is the only connected station. In this 119da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov * case FW-memory congestion is not a problem. 120b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 121da03209eaca9302e110925f84a515e03062aaa9eArik Nemtsov if (!single_sta && fw_ps && tx_pkts >= WL1271_PS_STA_MAX_PACKETS) 1226e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller wl12xx_ps_link_start(wl, wlvif, hlid, true); 123b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 124b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 125f8e0af6b8732b47c2531a280753d29a4ca2d114bArik Nemtsovbool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) 126f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 127f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->dummy_packet == skb; 128f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 129f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 130a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Pelleru8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif, 131a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller struct sk_buff *skb) 132a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 133a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); 134a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 135a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (control->control.sta) { 136a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 137a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 138a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl_sta = (struct wl1271_station *) 139a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov control->control.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; 148a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (ieee80211_is_mgmt(hdr->frame_control)) 149a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller return wlvif->ap.global_hlid; 150a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov else 151a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller return wlvif->ap.bcast_hlid; 152a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 153a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 154a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 155d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pelleru8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif, 156d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb) 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) 164a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller return wl12xx_tx_get_hlid_ap(wl, wlvif, skb); 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 1750da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yarivstatic unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, 1760da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv unsigned int packet_length) 1770da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{ 1786f7dd16cb125468a5393861c22fbecfb52dd9653Luciano Coelho if (wl->quirks & WLCORE_QUIRK_NO_BLOCKSIZE_ALIGNMENT) 1790da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv return ALIGN(packet_length, WL1271_TX_ALIGN_TO); 180ce39defb5c6312a89a0c7be48797d6fb8fe9abadLuciano Coelho else 181ce39defb5c6312a89a0c7be48797d6fb8fe9abadLuciano Coelho return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); 1820da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv} 1830da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv 184a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif, 185536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, u32 buf_offset, 186536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller u8 hlid) 187f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 188f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 189f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 19048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi u32 len; 1915c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 192742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int id, ret = -EBUSY, ac; 193e9eb8cbe77139470651c858b8b7a3d20d332cf47Guy Eilam u32 spare_blocks = wl->tx_spare_blocks; 194a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller bool is_dummy = false; 195f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 196a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) 1976c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 198a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 199f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 20025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 201f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 202f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 203f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 204f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* approximate the number of blocks required for this packet 205f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho in the firmware */ 2060da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv len = wl12xx_calc_packet_alignment(wl, total_len); 20748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 208e9eb8cbe77139470651c858b8b7a3d20d332cf47Guy Eilam /* in case of a dummy packet, use default amount of spare mem blocks */ 209a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller if (unlikely(wl12xx_is_dummy_packet(wl, skb))) { 210a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller is_dummy = true; 211e9eb8cbe77139470651c858b8b7a3d20d332cf47Guy Eilam spare_blocks = TX_HW_BLOCK_SPARE_DEFAULT; 212a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller } 213e9eb8cbe77139470651c858b8b7a3d20d332cf47Guy Eilam 21448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + 215e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho spare_blocks; 21648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 217f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 219f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 220f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 221ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi /* HW descriptor fields change between wl127x and wl128x */ 222ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi if (wl->chip.id == CHIP_ID_1283_PG20) { 223ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks = total_blocks; 224ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } else { 225e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho desc->wl127x_mem.extra_blocks = spare_blocks; 226ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks = total_blocks; 227ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } 228ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 229f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 230f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 231f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 2327bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov wl->tx_allocated_blocks += total_blocks; 233f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 23455df5afb13718cda49128fa5985556df91d07765Arik Nemtsov /* If the FW was empty before, arm the Tx watchdog */ 23555df5afb13718cda49128fa5985556df91d07765Arik Nemtsov if (wl->tx_allocated_blocks == total_blocks) 23655df5afb13718cda49128fa5985556df91d07765Arik Nemtsov wl12xx_rearm_tx_watchdog_locked(wl); 23755df5afb13718cda49128fa5985556df91d07765Arik Nemtsov 238742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 239742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov wl->tx_allocated_pkts[ac]++; 240bf54e301671a6ece6c94550294dc7faf14158cd3Arik Nemtsov 2410f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!is_dummy && wlvif && 2420f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller wlvif->bss_type == BSS_TYPE_AP_BSS && 243c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller test_bit(hlid, wlvif->ap.sta_hlid_map)) 2449b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov wl->links[hlid].allocated_pkts++; 24509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 246f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 247f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 248f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 249f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 250f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 251781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 25225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 253781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 256f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 257f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 258a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif, 259536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb, u32 extra, 260536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct ieee80211_tx_info *control, u8 hlid) 261f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 262ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 263f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 26448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int aligned_len, ac, rate_idx; 265ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 266cf00f379d82d170712150588accd2ebe316c2226John W. Linville u16 tx_attr = 0; 267f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller __le16 frame_control; 268f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller struct ieee80211_hdr *hdr; 269f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller u8 *frame_start; 270a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller bool is_dummy; 271f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 272f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 273f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_start = (u8 *)(desc + 1); 274f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller hdr = (struct ieee80211_hdr *)(frame_start + extra); 275f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller frame_control = hdr->frame_control; 276f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2771e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 2781e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 279f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller int hdrlen = ieee80211_hdrlen(frame_control); 280f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller memmove(frame_start, hdr, hdrlen); 2811e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 2821e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 283f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 284ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 285ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 286ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 287c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 288a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 2890f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS) 290c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 291c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 292c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 293f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 294db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller /* queue */ 295c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 296db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller desc->tid = skb->priority; 297c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 298a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller if (is_dummy) { 299ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 300ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * FW expects the dummy packet to have an invalid session id - 301ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * any session id that is different than the one set in the join 302ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 30398b8625301e55bd3e4340f704edc378e4707e577Eliad Peller tx_attr = (SESSION_COUNTER_INVALID << 304ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_OFST_SESSION_COUNTER) & 305ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_SESSION_COUNTER; 306ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 307ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; 3080f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller } else if (wlvif) { 309ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* configure the tx attributes */ 31098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller tx_attr = wlvif->session_counter << 31198b8625301e55bd3e4340f704edc378e4707e577Eliad Peller TX_HW_ATTR_OFST_SESSION_COUNTER; 312ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 313ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 31479b122dc51797b650201f21360481a0450e9b7e4Eliad Peller desc->hlid = hlid; 3150f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (is_dummy || !wlvif) 316a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller rate_idx = 0; 317a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller else if (wlvif->bss_type != BSS_TYPE_AP_BSS) { 318c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov /* if the packets are destined for AP (have a STA entry) 319c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov send them with AP rate policies, otherwise use default 320c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov basic rates */ 3218a0f2ee37810aa4a4f46baf08b2ad587e138eb58Eliad Peller if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE) 3228a0f2ee37810aa4a4f46baf08b2ad587e138eb58Eliad Peller rate_idx = wlvif->sta.p2p_rate_idx; 3238a0f2ee37810aa4a4f46baf08b2ad587e138eb58Eliad Peller else if (control->control.sta) 324e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.ap_rate_idx; 325c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 326e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->sta.basic_rate_idx; 327c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 328a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller if (hlid == wlvif->ap.global_hlid) 329e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.mgmt_rate_idx; 330a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller else if (hlid == wlvif->ap.bcast_hlid) 331e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.bcast_rate_idx; 332e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov else 333e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller rate_idx = wlvif->ap.ucast_rate_idx[ac]; 334c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 335c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 336c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 337f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->reserved = 0; 338f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3390da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); 34048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3410da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv if (wl->chip.id == CHIP_ID_1283_PG20) { 34248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->wl128x_mem.extra_bytes = aligned_len - skb->len; 34348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 344ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 345ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " 346ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", 347ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 348ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 349ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 350ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks); 35148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } else { 35248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int pad; 35348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3540da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv /* Store the aligned length in terms of words */ 35548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 35648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 35748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi /* calculate number of padding bytes */ 35848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi pad = aligned_len - skb->len; 35948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; 360f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 361ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " 362ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", pad, 363ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 364ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 365ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 366ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks); 36748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } 368d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 369f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller /* for WEP shared auth - no fw encryption is needed */ 370f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller if (ieee80211_is_auth(frame_control) && 371f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller ieee80211_has_protected(frame_control)) 372f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller tx_attr |= TX_HW_ATTR_HOST_ENCRYPT; 373f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller 374d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 377f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 378a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif, 379a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller struct sk_buff *skb, u32 buf_offset) 380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 382f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 384a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 38509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid; 386536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller bool is_dummy; 387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!skb) 389f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 391f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 392f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 393536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller /* TODO: handle dummy packets on multi-vifs */ 394536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller is_dummy = wl12xx_is_dummy_packet(wl, skb); 395536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller 396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 39797359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 3985ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller extra = WL1271_EXTRA_SPACE_TKIP; 399f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 4017f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 4027f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 4037f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 4047f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 4057f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 4067f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 407f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 408f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller if (unlikely(is_wep && wlvif->default_key != idx)) { 409536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller ret = wl1271_set_default_wep_key(wl, wlvif, idx); 410f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 412f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller wlvif->default_key = idx; 413f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 414f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 415d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); 41679b122dc51797b650201f21360481a0450e9b7e4Eliad Peller if (hlid == WL12XX_INVALID_LINK_ID) { 417e0d62536d032db689adf9c8162a9d2caf4714f44Eliad Peller wl1271_error("invalid hlid. dropping skb 0x%p", skb); 41879b122dc51797b650201f21360481a0450e9b7e4Eliad Peller return -EINVAL; 41979b122dc51797b650201f21360481a0450e9b7e4Eliad Peller } 42009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 421a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid); 422f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 423f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 424f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 425a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid); 426fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov 4270f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) { 42899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, skb); 429c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_tx_regulate_link(wl, wlvif, hlid); 430b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 43199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 432a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 43348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * The length of each packet is stored in terms of 43448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * words. Thus, we must pad the skb data to make sure its 43548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * length is aligned. The number of padding bytes is computed 43648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * and set in wl1271_tx_fill_hdr. 43748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * In special cases, we want to align to a specific block size 43848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * (eg. for wl128x with SDIO we align to 256). 439a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 4400da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv total_len = wl12xx_calc_packet_alignment(wl, skb->len); 44148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 442a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 443a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 444f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 445990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv /* Revert side effects in the dummy packet skb, so it can be reused */ 446536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller if (is_dummy) 447990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 448990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 449a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 450f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 451f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 452af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set, 453af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller enum ieee80211_band rate_band) 454830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 455830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 456830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 457830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 458830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 459af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller band = wl->hw->wiphy->bands[rate_band]; 460830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 461830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 462830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 463830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 464830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 465830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 46618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi /* MCS rates indication are on bits 16 - 23 */ 46718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 46818357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 46918357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi for (bit = 0; bit < 8; bit++) { 47018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 47118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 47218357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 47318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 47418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 475830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 476830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 477830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 478a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 4792fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 4802fe33e8cff354a3f320549544bffebbbab680145Ido Yariv unsigned long flags; 481708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov int i; 4822fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 483708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 484708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov if (test_bit(i, &wl->stopped_queues_map) && 485f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { 486708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov /* firmware buffer has space, restart queues */ 487708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 488708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov ieee80211_wake_queue(wl->hw, 489708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl1271_tx_get_mac80211_queue(i)); 490708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov clear_bit(i, &wl->stopped_queues_map); 491708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 492708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov } 4932fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 4942fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 4952fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 496742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsovstatic struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, 497742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queues) 498742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov{ 499742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int i, q = -1, ac; 500742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov u32 min_pkts = 0xffffffff; 501742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 502742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* 503742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * Find a non-empty ac where: 504742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 1. There are packets to transmit 505742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 2. The FW has the least allocated blocks 506742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 507742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * We prioritize the ACs according to VO>VI>BE>BK 508742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov */ 509742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 510742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(i); 511742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!skb_queue_empty(&queues[ac]) && 512742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov (wl->tx_allocated_pkts[ac] < min_pkts)) { 513742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov q = ac; 514742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov min_pkts = wl->tx_allocated_pkts[q]; 515742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 516742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 517742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 518742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (q == -1) 519742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return NULL; 520742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 521742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return &queues[q]; 522742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov} 523742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 524d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic struct sk_buff *wl12xx_lnk_skb_dequeue(struct wl1271 *wl, 525d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct wl1271_link *lnk) 5266742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 527d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 5286742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 529742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queue; 5306742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 531d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller queue = wl1271_select_queue(wl, lnk->tx_queue); 532742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!queue) 533d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller return NULL; 534742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 535742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov skb = skb_dequeue(queue); 5366742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 537f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 5386742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 5396246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 540f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 5416742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5426742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 5436742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5446742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 5456742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5466742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 547d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic struct sk_buff *wl12xx_vif_skb_dequeue(struct wl1271 *wl, 548d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct wl12xx_vif *wlvif) 549a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 550a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 551a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 552a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 553a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 5544438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller start_hlid = (wlvif->last_tx_hlid + 1) % WL12XX_MAX_LINKS; 555a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 556a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 557c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller for (i = 0; i < WL12XX_MAX_LINKS; i++) { 558c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller h = (start_hlid + i) % WL12XX_MAX_LINKS; 559a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 560742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* only consider connected stations */ 561c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller if (!test_bit(h, wlvif->links_map)) 562742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 563742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 564d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[h]); 565d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 566742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 567742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 568d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = h; 569d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller break; 570a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 571a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 572d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (!skb) 5734438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller wlvif->last_tx_hlid = 0; 574a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 575a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 576a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 577a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 578a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 579a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 580990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv unsigned long flags; 581e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller struct wl12xx_vif *wlvif = wl->last_wlvif; 582990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv struct sk_buff *skb = NULL; 583990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 58449c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* continue from last wlvif (round robin) */ 585e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (wlvif) { 586e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif_continue(wl, wlvif) { 587e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller skb = wl12xx_vif_skb_dequeue(wl, wlvif); 588e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (skb) { 589e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl->last_wlvif = wlvif; 590e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller break; 591e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 592e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 593e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 594e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller 59549c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* dequeue from the system HLID before the restarting wlvif list */ 59649c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov if (!skb) 59749c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov skb = wl12xx_lnk_skb_dequeue(wl, &wl->links[wl->system_hlid]); 59849c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 59949c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* do a new pass over the wlvif list */ 600e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (!skb) { 601e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl12xx_for_each_wlvif(wl, wlvif) { 602e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller skb = wl12xx_vif_skb_dequeue(wl, wlvif); 603e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller if (skb) { 604e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller wl->last_wlvif = wlvif; 605e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller break; 606e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 60749c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov 60849c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov /* 60949c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov * No need to continue after last_wlvif. The previous 61049c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov * pass should have found it. 61149c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov */ 61249c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov if (wlvif == wl->last_wlvif) 61349c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov break; 614e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller } 615a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller } 616a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 617990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!skb && 618990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 619f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q; 620f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov 621990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl->dummy_packet; 622f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 623990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_lock_irqsave(&wl->wl_lock, flags); 6246246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov WARN_ON_ONCE(wl->tx_queue_count[q] <= 0); 625f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 626990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 627990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } 628990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 629990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return skb; 630a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 631a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 632d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif, 633536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller struct sk_buff *skb) 6346742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 6356742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 6366742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 6376742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 638990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 639990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 640d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller } else { 641d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller u8 hlid = wl12xx_tx_get_hlid(wl, wlvif, skb); 642a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 643a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 644a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 6454438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller wlvif->last_tx_hlid = (hlid + WL12XX_MAX_LINKS - 1) % 646d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller WL12XX_MAX_LINKS; 647a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 648a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 6496742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 650f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]++; 6516742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 6526742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 6536742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 65477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb) 65577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{ 65677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 65777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 65877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller return ieee80211_is_data_present(hdr->frame_control); 65977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller} 66077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 6619eb599e9c62dcfd4efece1936c385381b366b684Eliad Pellervoid wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids) 6629eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller{ 6639eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl12xx_vif *wlvif; 6649eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u32 timeout; 6659eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller u8 hlid; 6669eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6679eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.interval) 6689eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 6699eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6709eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!wl->conf.rx_streaming.always && 6719eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags)) 6729eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller return; 6739eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6749eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller timeout = wl->conf.rx_streaming.duration; 6759eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_for_each_wlvif_sta(wl, wlvif) { 6769eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool found = false; 6779eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller for_each_set_bit(hlid, active_hlids, WL12XX_MAX_LINKS) { 6789eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (test_bit(hlid, wlvif->links_map)) { 6799eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller found = true; 6809eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller break; 6819eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6829eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6839eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6849eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (!found) 6859eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller continue; 6869eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6879eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller /* enable rx streaming */ 6880744bdb60b51dce54553d5af9a6133f1fe419032Eliad Peller if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags)) 6899eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller ieee80211_queue_work(wl->hw, 6909eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller &wlvif->rx_streaming_enable_work); 6919eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 6929eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller mod_timer(&wlvif->rx_streaming_timer, 6939eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller jiffies + msecs_to_jiffies(timeout)); 6949eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 6959eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller} 6969eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 697a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellervoid wl1271_tx_work_locked(struct wl1271 *wl) 698f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 699a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller struct wl12xx_vif *wlvif; 700f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 7019eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller struct wl1271_tx_hw_descr *desc; 7026c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv u32 buf_offset = 0; 7036c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 7049eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller unsigned long active_hlids[BITS_TO_LONGS(WL12XX_MAX_LINKS)] = {0}; 705f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 706f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 707f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (unlikely(wl->state == WL1271_STATE_OFF)) 708c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller return; 709f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 710a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller while ((skb = wl1271_skb_dequeue(wl))) { 7110f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); 7129eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller bool has_data = false; 7139eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller 714a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wlvif = NULL; 7150f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller if (!wl12xx_is_dummy_packet(wl, skb) && info->control.vif) 7160f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller wlvif = wl12xx_vif_to_data(info->control.vif); 717a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller 7189eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller has_data = wlvif && wl1271_tx_is_data_present(skb); 719a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset); 7206c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 721a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 7226c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 7236c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 7246c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 725d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl1271_skb_queue_head(wl, wlvif, skb); 72600782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, 72700782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho buf_offset, true); 7286c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 7296c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 7306c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 7316c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 7326c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 7336c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 734a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 735a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 736d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl1271_skb_queue_head(wl, wlvif, skb); 737a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 738a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 739ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 740f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 7415de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller if (wl12xx_is_dummy_packet(wl, skb)) 7425de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller /* 7435de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * fw still expects dummy packet, 7445de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller * so re-enqueue it 7455de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller */ 7465de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller wl1271_skb_queue_head(wl, wlvif, skb); 7475de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller else 7485de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller ieee80211_free_txskb(wl->hw, skb); 749ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 750f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 751a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset += ret; 752a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 7539eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller if (has_data) { 7549eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller desc = (struct wl1271_tx_hw_descr *) skb->data; 7559eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller __set_bit(desc->hlid, active_hlids); 7569eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller } 757f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 758f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 759ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 760a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 76100782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf, 76200782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho buf_offset, true); 7636c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 7646c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 7656c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 766606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 767606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 768606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 769606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 7706f7dd16cb125468a5393861c22fbecfb52dd9653Luciano Coelho if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) 77100782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho wl1271_write32(wl, WL12XX_HOST_WR_ACCESS, 772606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl->tx_packets_count); 773606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 774a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 775a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 7769eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller wl12xx_rearm_rx_streaming(wl, active_hlids); 777a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 778f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 779a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 780a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 781a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 782c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller int ret; 783a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 784a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 785c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller ret = wl1271_ps_elp_wakeup(wl); 786c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller if (ret < 0) 787c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller goto out; 788c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 789a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller wl1271_tx_work_locked(wl); 790c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 791c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller wl1271_ps_elp_sleep(wl); 792c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout: 793f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 794f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 795f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 796d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchsstatic u8 wl1271_tx_get_rate_flags(u8 rate_class_index) 797d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs{ 798defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs u8 flags = 0; 799defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs 800d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs if (rate_class_index >= CONF_HW_RXTX_RATE_MCS_MIN && 801d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs rate_class_index <= CONF_HW_RXTX_RATE_MCS_MAX) 802defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_MCS; 803defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs if (rate_class_index == CONF_HW_RXTX_RATE_MCS7_SGI) 804defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs flags |= IEEE80211_TX_RC_SHORT_GI; 805defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs return flags; 806d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs} 807d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs 808f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 811f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 81248e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct ieee80211_vif *vif; 81348e93e402ad19f570bae323b07911bdf6562af8eEliad Peller struct wl12xx_vif *wlvif; 814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 815f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 81631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 817d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs u8 rate_flags = 0; 81831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 819f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 820f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 82172b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) { 822f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 823f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 824f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 825f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 826f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 827f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 829990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 830ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl1271_free_tx_id(wl, id); 831ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi return; 832ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 833ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 83448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller /* info->control is valid as long as we don't update info->status */ 83548e93e402ad19f570bae323b07911bdf6562af8eEliad Peller vif = info->control.vif; 83648e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif = wl12xx_vif_to_data(vif); 83748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller 83831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 83931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 84031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 841f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 8421b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller rate = wl1271_rate_to_idx(result->rate_class_index, 8431b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller wlvif->band); 844d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index); 84531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 84631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 84731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 84831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 849f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 850f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 85131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 85231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 853d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs info->status.rates[0].flags = rate_flags; 85431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 85531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 856f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 857f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 858b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 859b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update sequence number only when relevant, i.e. only in 860b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * sessions of TKIP, AES and GEM (not in open or WEP sessions) 861b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 862b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski if (info->control.hw_key && 863b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || 864b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || 865b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { 866b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 fw_lsb = result->tx_security_sequence_number_lsb; 86748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller u8 cur_lsb = wlvif->tx_security_last_seq_lsb; 868b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski 869b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 870b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update security sequence number, taking care of potential 871b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * wrap-around 872b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 87348e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif->tx_security_seq += (fw_lsb - cur_lsb) & 0xff; 87448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller wlvif->tx_security_last_seq_lsb = fw_lsb; 875b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski } 876ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 8771e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 8781e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 8791e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 8801e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 881f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 88297359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 8831e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 8845ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data, 8855ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller hdrlen); 8865ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 8871e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 889f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 890f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 891f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 892f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 893f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 894f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 895a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 89692ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller queue_work(wl->freezable_wq, &wl->netstack_work); 89725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 898f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 899f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 900f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 901ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenvoid wl1271_tx_complete(struct wl1271 *wl) 902f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 903f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_acx_mem_map *memmap = 904f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho (struct wl1271_acx_mem_map *)wl->target_mem_map; 905ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 906f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 907f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 908f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 9097b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_read(wl, le32_to_cpu(memmap->tx_result), 9107b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl->tx_res_if, sizeof(*wl->tx_res_if), false); 911ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 912ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 913ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 914ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + 915ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen offsetof(struct wl1271_tx_hw_res_if, 916ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen tx_result_host_counter), fw_counter); 917ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 918ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 91906f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 920f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 922ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 923f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 931f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 932f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 933f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 934f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 935f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 936f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 937f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 938a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 939a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 940a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 941f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int i; 942a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 9431d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 944f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int total[NUM_TX_QUEUES]; 945a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 946a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 947f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i] = 0; 948a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 949a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 95079ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 95179ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb)) { 95279ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info = IEEE80211_SKB_CB(skb); 95379ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].idx = -1; 95479ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].count = 0; 95579ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov ieee80211_tx_status_ni(wl->hw, skb); 95679ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov } 95779ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 958f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i]++; 959a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 960a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 961a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 962a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 963f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 964f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] -= total[i]; 965a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 966a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 967a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 968a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 969a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 9707dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */ 971d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellervoid wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif) 972f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 973f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 974f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 975f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 976d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller for_each_set_bit(i, wlvif->links_map, WL12XX_MAX_LINKS) { 977d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller if (wlvif->bss_type == BSS_TYPE_AP_BSS) 978c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller wl1271_free_sta(wl, wlvif, i); 979d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller else 980d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->sta.ba_rx_bitmap = 0; 981f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov 982d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl->links[i].allocated_pkts = 0; 983d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wl->links[i].prev_freed_pkts = 0; 984f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 985d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller wlvif->last_tx_hlid = 0; 986d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller 987d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller} 988d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller/* caller must hold wl->mutex and TX must be stopped */ 989d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellervoid wl12xx_tx_reset(struct wl1271 *wl, bool reset_tx_queues) 990d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller{ 991d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller int i; 992d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct sk_buff *skb; 993d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller struct ieee80211_tx_info *info; 994a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 9956246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov /* only reset the queues if something bad happened */ 9966246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov if (WARN_ON_ONCE(wl1271_tx_total_queue_count(wl) != 0)) { 9976246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov for (i = 0; i < WL12XX_MAX_LINKS; i++) 9986246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 9996246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov 10006246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 10016246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov wl->tx_queue_count[i] = 0; 10026246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov } 1003f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov 1004708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl->stopped_queues_map = 0; 1005f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 10062fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 10072fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 10082fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 10097dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov * This call will always wake the TX queues. 10102fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 10117dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov if (reset_tx_queues) 10127dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 10132fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 101472b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov for (i = 0; i < wl->num_tx_desc; i++) { 101550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 101650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 101750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 101850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 101950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 102050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 102150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1022990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 1023ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 1024ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * Remove private headers before passing the skb to 1025ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * mac80211 1026ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 1027ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 1028ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 1029ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi if (info->control.hw_key && 1030ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->control.hw_key->cipher == 1031ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi WLAN_CIPHER_SUITE_TKIP) { 1032ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 10335ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, 1034ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb->data, hdrlen); 10355ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller skb_pull(skb, WL1271_EXTRA_SPACE_TKIP); 1036ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 103750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1038ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 1039ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 104050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 1041c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 1042ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 104350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 1044781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 1045781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1046781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 1047781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1048781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 1049781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 1050781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 1051781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen unsigned long timeout; 105218aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov int i; 1053781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 1054781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1055781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 1056781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_lock(&wl->mutex); 1057a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 1058f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_frames_cnt, 1059f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl1271_tx_total_queue_count(wl)); 1060f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov if ((wl->tx_frames_cnt == 0) && 1061f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov (wl1271_tx_total_queue_count(wl) == 0)) { 1062781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 1063781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen return; 1064781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1065781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 1066781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen msleep(1); 1067781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 1068781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 1069781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen wl1271_warning("Unable to flush all TX buffers, timed out."); 107018aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov 107118aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov /* forcibly flush all Tx buffers on our queues */ 107218aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov mutex_lock(&wl->mutex); 107318aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov for (i = 0; i < WL12XX_MAX_LINKS; i++) 107418aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 107518aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov mutex_unlock(&wl->mutex); 1076f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 1077e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1078af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set) 1079e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 1080af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller if (WARN_ON(!rate_set)) 1081af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return 0; 1082e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 1083af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller return BIT(__ffs(rate_set)); 1084e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 1085