tx.c revision f1a46384ad568f72c11edbe2a3ec284bf32f2dbd
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 2800d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "wl12xx.h" 2900d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h" 3000d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "reg.h" 3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "ps.h" 3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "tx.h" 33f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 347f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsovstatic int wl1271_set_default_wep_key(struct wl1271 *wl, u8 id) 357f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov{ 367f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov int ret; 377f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); 387f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 397f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (is_ap) 407f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov ret = wl1271_cmd_set_ap_default_wep_key(wl, id); 417f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov else 427f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov ret = wl1271_cmd_set_sta_default_wep_key(wl, id); 437f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 447f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (ret < 0) 457f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return ret; 467f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 477f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); 487f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return 0; 497f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov} 507f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 5125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 52f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 5325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv int id; 5425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 5525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); 5625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (id >= ACX_TX_DESCRIPTORS) 5725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return -EBUSY; 5825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 5925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv __set_bit(id, wl->tx_frames_map); 6025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = skb; 6125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt++; 6225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return id; 6325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv} 64f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic void wl1271_free_tx_id(struct wl1271 *wl, int id) 6625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{ 6725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (__test_and_clear_bit(id, wl->tx_frames_map)) { 68ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) 69ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 70ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv 7125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 7325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 74f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 76c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohenstatic int wl1271_tx_update_filters(struct wl1271 *wl, 77c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen struct sk_buff *skb) 78c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen{ 79c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen struct ieee80211_hdr *hdr; 80c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 81c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen hdr = (struct ieee80211_hdr *)(skb->data + 82c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen sizeof(struct wl1271_tx_hw_descr)); 83c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 84c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen /* 85c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * stop bssid-based filtering before transmitting authentication 86c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * requests. this way the hw will never drop authentication 87c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * responses coming from BSSIDs it isn't familiar with (e.g. on 88c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * roaming) 89c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen */ 90c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen if (!ieee80211_is_auth(hdr->frame_control)) 91c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen return 0; 92c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 93c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen wl1271_configure_filters(wl, FIF_OTHER_BSS); 94c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 95c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen return wl1271_acx_rx_config(wl, wl->rx_config, wl->rx_filter); 96c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen} 97c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 9899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 9999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 10099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 10199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 10299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 10399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 10499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 10599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 10699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 10799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 10899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 10999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 11099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov if (ieee80211_is_auth(hdr->frame_control)) 11199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 11299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 11399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 114b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsovstatic void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) 115b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 116b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov bool fw_ps; 117b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov u8 tx_blks; 118b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 119b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* only regulate station links */ 120b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (hlid < WL1271_AP_STA_HLID_START) 121b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 122b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 123b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 124b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov tx_blks = wl->links[hlid].allocated_blks; 125b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 126b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 127b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 128b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 129b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 130b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) 131b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_ps_link_start(wl, hlid, true); 132b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 133b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 134a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovu8 wl1271_tx_get_hlid(struct sk_buff *skb) 135a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 136a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); 137a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 138a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (control->control.sta) { 139a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 140a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 141a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl_sta = (struct wl1271_station *) 142a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov control->control.sta->drv_priv; 143a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl_sta->hlid; 144a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 145a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_hdr *hdr; 146a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 147a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov hdr = (struct ieee80211_hdr *)skb->data; 148a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (ieee80211_is_mgmt(hdr->frame_control)) 149a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return WL1271_AP_GLOBAL_HLID; 150a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov else 151a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return WL1271_AP_BROADCAST_HLID; 152a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 153a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 154a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 1550da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yarivstatic unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, 1560da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv unsigned int packet_length) 1570da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{ 1580da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) 1590da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); 1600da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv else 1610da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv return ALIGN(packet_length, WL1271_TX_ALIGN_TO); 1620da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv} 1630da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv 164a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, 16509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 buf_offset, u8 hlid) 166f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 167f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 168f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 16948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi u32 len; 1705c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 1719e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov int id, ret = -EBUSY, ac; 172e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho u32 spare_blocks; 173e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho 174e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho if (unlikely(wl->quirks & WL12XX_QUIRK_USE_2_SPARE_BLOCKS)) 175e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho spare_blocks = 2; 176e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho else 177e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho spare_blocks = 1; 178f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 179a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) 1806c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 181a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 182f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 18325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 184f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 185f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 186f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 187f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* approximate the number of blocks required for this packet 188f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho in the firmware */ 1890da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv len = wl12xx_calc_packet_alignment(wl, total_len); 19048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 19148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + 192e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho spare_blocks; 19348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 194f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 195f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 196f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 197f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 198ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi /* HW descriptor fields change between wl127x and wl128x */ 199ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi if (wl->chip.id == CHIP_ID_1283_PG20) { 200ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks = total_blocks; 201ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } else { 202e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho desc->wl127x_mem.extra_blocks = spare_blocks; 203ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks = total_blocks; 204ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } 205ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 206f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 207f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 208f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 2099e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 2109e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 2119e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov wl->tx_allocated_blocks[ac] += total_blocks; 212f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 21309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 21409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[hlid].allocated_blks += total_blocks; 21509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 216f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 217f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 219f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 220f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 221781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 22225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 223781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 224f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 225f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 226f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 227f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 228990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yarivstatic bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) 229990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv{ 230990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return wl->dummy_packet == skb; 231990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv} 232990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 233a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, 23409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 extra, struct ieee80211_tx_info *control, 23509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid) 236f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 237ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 238f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 23948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int aligned_len, ac, rate_idx; 240ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 241d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho u16 tx_attr; 242f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 243f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 244f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2451e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 2461e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 2471e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen void *framestart = skb->data + sizeof(*desc); 2481e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen u16 fc = *(u16 *)(framestart + extra); 249d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); 2501e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(framestart, framestart + extra, hdrlen); 2511e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 2521e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 253f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 254ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 255ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 256ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 257c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 258c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (wl->bss_type != BSS_TYPE_AP_BSS) 259c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 260c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 261c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 263db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller /* queue */ 264c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 265db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller desc->tid = skb->priority; 266c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 267990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 268ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 269ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * FW expects the dummy packet to have an invalid session id - 270ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * any session id that is different than the one set in the join 271ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 272ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr = ((~wl->session_counter) << 273ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_OFST_SESSION_COUNTER) & 274ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_SESSION_COUNTER; 275ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 276ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; 277ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } else { 278ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* configure the tx attributes */ 279ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr = 280ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; 281ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 282ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 283c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (wl->bss_type != BSS_TYPE_AP_BSS) { 28409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov desc->aid = hlid; 285c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 286c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov /* if the packets are destined for AP (have a STA entry) 287c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov send them with AP rate policies, otherwise use default 288c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov basic rates */ 289c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (control->control.sta) 290c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_AP_FULL_RATE; 291c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 292c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_BASIC_RATE; 293c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 29409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov desc->hlid = hlid; 29509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov switch (hlid) { 29609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov case WL1271_AP_GLOBAL_HLID: 29709039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_MGMT_RATE; 29809039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 29909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov case WL1271_AP_BROADCAST_HLID: 30009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_BCST_RATE; 30109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 30209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov default: 303c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ac; 30409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 305c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 306c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 307c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 308c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 309f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->reserved = 0; 310f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3110da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); 31248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3130da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv if (wl->chip.id == CHIP_ID_1283_PG20) { 31448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->wl128x_mem.extra_bytes = aligned_len - skb->len; 31548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 316ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 317ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " 318ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", 319ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 320ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 321ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 322ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks); 32348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } else { 32448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int pad; 32548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3260da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv /* Store the aligned length in terms of words */ 32748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 32848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 32948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi /* calculate number of padding bytes */ 33048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi pad = aligned_len - skb->len; 33148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; 332f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 333ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " 334ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", pad, 335ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 336ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 337ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 338ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks); 33948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } 340d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 341d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 342f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 343f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 344f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 345a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, 346a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 buf_offset) 347f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 348f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 349f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 350f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 351a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 35209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid; 353f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 354f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!skb) 355f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 357f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 358f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 359f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 36097359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 361f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho extra = WL1271_TKIP_IV_SPACE; 362f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 363f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 3647f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 3657f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 3667f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 3677f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 3687f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 3697f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 370f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3717f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (unlikely(is_wep && wl->default_key != idx)) { 3727f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov ret = wl1271_set_default_wep_key(wl, idx); 373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 375ee444cf0501183df1640cd35bebd4250989bfe99Juuso Oikarinen wl->default_key = idx; 376f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 377f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 37909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 38009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov hlid = wl1271_tx_get_hlid(skb); 38109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov else 38209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov hlid = TX_HW_DEFAULT_AID; 38309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 38409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); 385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 388fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); 389fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov 390b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 39199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, skb); 392b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_tx_regulate_link(wl, hlid); 393c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen } else { 394c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen wl1271_tx_update_filters(wl, skb); 395b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 39699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 397a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 39848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * The length of each packet is stored in terms of 39948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * words. Thus, we must pad the skb data to make sure its 40048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * length is aligned. The number of padding bytes is computed 40148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * and set in wl1271_tx_fill_hdr. 40248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * In special cases, we want to align to a specific block size 40348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * (eg. for wl128x with SDIO we align to 256). 404a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 4050da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv total_len = wl12xx_calc_packet_alignment(wl, skb->len); 40648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 407a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 408a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 409f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 410990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv /* Revert side effects in the dummy packet skb, so it can be reused */ 411990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) 412990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 413990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 414a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 417ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinenu32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) 418830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 419830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 420830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 421830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 422830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 423830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen band = wl->hw->wiphy->bands[wl->band]; 424830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 425830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 426830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 427830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 428830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 429830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 43000d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#ifdef CONFIG_WL12XX_HT 43118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi /* MCS rates indication are on bits 16 - 23 */ 43218357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 43318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 43418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi for (bit = 0; bit < 8; bit++) { 43518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 43618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 43718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 43818357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 43918357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi#endif 44018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 441830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 442830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 443830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 444a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 4452fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 4462fe33e8cff354a3f320549544bffebbbab680145Ido Yariv unsigned long flags; 447708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov int i; 4482fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 449708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 450708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov if (test_bit(i, &wl->stopped_queues_map) && 451f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { 452708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov /* firmware buffer has space, restart queues */ 453708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 454708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov ieee80211_wake_queue(wl->hw, 455708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl1271_tx_get_mac80211_queue(i)); 456708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov clear_bit(i, &wl->stopped_queues_map); 457708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 458708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov } 4592fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 4602fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 4612fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 4629e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsovstatic struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, 4639e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov struct sk_buff_head *queues) 4649e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov{ 4659e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov int i, q = -1; 4669e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov u32 min_blks = 0xffffffff; 4679e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 4689e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov /* 4699e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov * Find a non-empty ac where: 4709e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov * 1. There are packets to transmit 4719e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov * 2. The FW has the least allocated blocks 4729e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov */ 4739e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 4749e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov if (!skb_queue_empty(&queues[i]) && 4759e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov (wl->tx_allocated_blocks[i] < min_blks)) { 4769e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov q = i; 4779e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov min_blks = wl->tx_allocated_blocks[q]; 4789e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov } 4799e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 4809e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov if (q == -1) 4819e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov return NULL; 4829e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 4839e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov return &queues[q]; 4849e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov} 4859e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 486a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) 4876742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 4886742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen struct sk_buff *skb = NULL; 4896742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 4909e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov struct sk_buff_head *queue; 4916742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 4929e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov queue = wl1271_select_queue(wl, wl->tx_queue); 4939e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov if (!queue) 4946742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen goto out; 4959e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 4969e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov skb = skb_dequeue(queue); 4976742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 4986742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenout: 4996742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 500f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 5016742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 502f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 5036742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5046742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 5056742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5066742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 5076742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5086742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 509a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) 510a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 511a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 512a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 513a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 5149e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov struct sk_buff_head *queue; 515a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 516a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 517a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; 518a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 519a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 520a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 521a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov h = (start_hlid + i) % AP_MAX_LINKS; 522a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 5239e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov /* only consider connected stations */ 5249e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov if (h >= WL1271_AP_STA_HLID_START && 5259e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) 5269e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov continue; 5279e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 5289e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov queue = wl1271_select_queue(wl, wl->links[h].tx_queue); 5299e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov if (!queue) 5309e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov continue; 5319e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov 5329e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov skb = skb_dequeue(queue); 533a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) 5349e374a37b6fa2310b71d3c5657cd0c1e693120c6Arik Nemtsov break; 535a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 536a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 537a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) { 538f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 539a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = h; 540a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 541f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 542a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 543a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 544a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 545a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 546a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 547a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 548a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 549a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 550a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 551a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 552990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv unsigned long flags; 553990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv struct sk_buff *skb = NULL; 554990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 555a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 556990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl1271_ap_skb_dequeue(wl); 557990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv else 558990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl1271_sta_skb_dequeue(wl); 559a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 560990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!skb && 561990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 562f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q; 563f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov 564990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl->dummy_packet; 565f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 566990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_lock_irqsave(&wl->wl_lock, flags); 567f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 568990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 569990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } 570990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 571990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return skb; 572a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 573a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 5746742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) 5756742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 5766742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 5776742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 5786742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 579990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 580990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 581990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } else if (wl->bss_type == BSS_TYPE_AP_BSS) { 582a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov u8 hlid = wl1271_tx_get_hlid(skb); 583a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 584a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 585a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 586a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS; 587a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 588a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->tx_queue[q], skb); 589a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 590a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 5916742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 592f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]++; 5936742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5946742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5956742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 59677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb) 59777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{ 59877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 59977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 60077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller return ieee80211_is_data_present(hdr->frame_control); 60177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller} 60277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 603a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work_locked(struct wl1271 *wl) 604f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 605f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 6066c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv u32 buf_offset = 0; 6076c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 60877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller bool had_data = false; 60977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); 610f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 611f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 612f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (unlikely(wl->state == WL1271_STATE_OFF)) 613c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller return; 614f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6156742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen while ((skb = wl1271_skb_dequeue(wl))) { 61677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (wl1271_tx_is_data_present(skb)) 61777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller had_data = true; 61877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 619a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); 6206c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 621a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 6226c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 6236c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 6246c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 6256742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 6266c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 6276742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen buf_offset, true); 6286c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 6296c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 6306c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 6316c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 6326c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 6336c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 634a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 635a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 6366742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 637a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 638a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 639ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 640f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 641f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho dev_kfree_skb(skb); 642ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 643f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 644a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset += ret; 645a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 646f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 647f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 648ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 649a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 650a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 651a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset, true); 6526c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 6536c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 6546c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 655606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 656606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 657606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 658606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 659606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) 660606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl1271_write32(wl, WL1271_HOST_WR_ACCESS, 661606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl->tx_packets_count); 662606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 663a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 664a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 66577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (!is_ap && wl->conf.rx_streaming.interval && had_data && 66677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller (wl->conf.rx_streaming.always || 66777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { 66877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller u32 timeout = wl->conf.rx_streaming.duration; 66977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 67077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller /* enable rx streaming */ 67177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) 67277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller ieee80211_queue_work(wl->hw, 67377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller &wl->rx_streaming_enable_work); 67477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 67577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller mod_timer(&wl->rx_streaming_timer, 67677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller jiffies + msecs_to_jiffies(timeout)); 67777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller } 678a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 679f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 680a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 681a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 682a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 683c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller int ret; 684a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 685a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 686c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller ret = wl1271_ps_elp_wakeup(wl); 687c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller if (ret < 0) 688c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller goto out; 689c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 690a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv wl1271_tx_work_locked(wl); 691c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 692c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller wl1271_ps_elp_sleep(wl); 693c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout: 694f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 695f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 696f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 697f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 698f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 699f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 700f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 701f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 702f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 70331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 70431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 705f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 706f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 707ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { 708f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 709f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 710f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 711f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 712f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 713f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 714f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 715990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 716ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl1271_free_tx_id(wl, id); 717ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi return; 718ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 719ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 72031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 72131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 72231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 723f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 7246a2de93b2553c2e9a72997370534993c85c1eee6Teemu Paasikivi rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); 72531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 72631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 72731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 72831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 729f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 730f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 73131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 73231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 73331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].flags = 0; 73431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 73531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 736f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 737f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 738b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 739b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update sequence number only when relevant, i.e. only in 740b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * sessions of TKIP, AES and GEM (not in open or WEP sessions) 741b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 742b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski if (info->control.hw_key && 743b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || 744b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || 745b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { 746b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 fw_lsb = result->tx_security_sequence_number_lsb; 747b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 cur_lsb = wl->tx_security_last_seq_lsb; 748b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski 749b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 750b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update security sequence number, taking care of potential 751b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * wrap-around 752b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 753b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256; 754b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski wl->tx_security_last_seq_lsb = fw_lsb; 755b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski } 756ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 7571e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 7581e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 7591e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 7601e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 761f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 76297359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 7631e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 7641e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); 7651e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, WL1271_TKIP_IV_SPACE); 7661e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 767f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 768f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 769f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 770f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 771f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 772f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 773f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 774a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 77592ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller queue_work(wl->freezable_wq, &wl->netstack_work); 77625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 777f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 778f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 779f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 780ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenvoid wl1271_tx_complete(struct wl1271 *wl) 781f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 782f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_acx_mem_map *memmap = 783f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho (struct wl1271_acx_mem_map *)wl->target_mem_map; 784ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 785f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 786f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 787f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 7887b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_read(wl, le32_to_cpu(memmap->tx_result), 7897b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl->tx_res_if, sizeof(*wl->tx_res_if), false); 790ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 791ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 792ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 793ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + 794ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen offsetof(struct wl1271_tx_hw_res_if, 795ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen tx_result_host_counter), fw_counter); 796ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 797ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 79806f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 799f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 800f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 801ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 802f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 803f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 804f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 805f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 806f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 807f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 808f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 811f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 812f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 813f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 815f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 816f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 817a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 818a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 819a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 820f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int i; 821a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 8221d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 823f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int total[NUM_TX_QUEUES]; 824a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 825a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 826f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i] = 0; 827a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 828a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 8291d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info = IEEE80211_SKB_CB(skb); 8301d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].idx = -1; 8311d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].count = 0; 832c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 833f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i]++; 834a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 835a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 836a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 837a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 838f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 839f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] -= total[i]; 840a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 841a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 842a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 843a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 844a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 8457dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */ 8467dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsovvoid wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) 847f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 848f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 849f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 8501d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 851f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 852f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 853a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 85409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 855a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 85609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].allocated_blks = 0; 85709039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].prev_freed_blks = 0; 85809039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov } 859a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 860a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 861a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 862a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 863a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->tx_queue[i]))) { 864a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "freeing skb 0x%p", 865a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb); 866ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 867990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 868ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 869ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 870ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 871c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 872ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 873a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 874f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] = 0; 8756742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 876f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 877a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 878708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl->stopped_queues_map = 0; 879f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 8802fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 8812fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 8822fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 8837dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov * This call will always wake the TX queues. 8842fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 8857dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov if (reset_tx_queues) 8867dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 8872fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 88850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { 88950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 89050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 89150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 89250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 89350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 89450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 89550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 896990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 897ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 898ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * Remove private headers before passing the skb to 899ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * mac80211 900ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 901ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 902ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 903ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi if (info->control.hw_key && 904ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->control.hw_key->cipher == 905ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi WLAN_CIPHER_SUITE_TKIP) { 906ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 907ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi memmove(skb->data + WL1271_TKIP_IV_SPACE, 908ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb->data, hdrlen); 909ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, WL1271_TKIP_IV_SPACE); 910ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 91150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 912ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 913ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 91450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 915c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 916ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 91750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 918781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 919781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 920781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 921781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 922781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 923781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 924781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 925781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen unsigned long timeout; 926781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 927781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 928781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 929781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_lock(&wl->mutex); 930a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 931f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_frames_cnt, 932f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl1271_tx_total_queue_count(wl)); 933f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov if ((wl->tx_frames_cnt == 0) && 934f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov (wl1271_tx_total_queue_count(wl) == 0)) { 935781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 936781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen return; 937781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 938781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 939781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen msleep(1); 940781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 941781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 942781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen wl1271_warning("Unable to flush all TX buffers, timed out."); 943f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 944e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 945e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsovu32 wl1271_tx_min_rate_get(struct wl1271 *wl) 946e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 947e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov int i; 948e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov u32 rate = 0; 949e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 950e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if (!wl->basic_rate_set) { 951e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov WARN_ON(1); 952e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov wl->basic_rate_set = wl->conf.tx.basic_rate; 953e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 954e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 955e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov for (i = 0; !rate; i++) { 956e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if ((wl->basic_rate_set >> i) & 0x1) 957e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov rate = 1 << i; 958e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 959e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 960e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov return rate; 961e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 962