tx.c revision a620865edf62ea2d024bbfe62162244473badfcb
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)) { 6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 6925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 7025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 71f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 72f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 7399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 7499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 7599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 7699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 7799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 7899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 7999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 8099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 8199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 8299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 8399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 8499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 8599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov if (ieee80211_is_auth(hdr->frame_control)) 8699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 8799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 8899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 89b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsovstatic void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) 90b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 91b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov bool fw_ps; 92b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov u8 tx_blks; 93b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 94b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* only regulate station links */ 95b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (hlid < WL1271_AP_STA_HLID_START) 96b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 97b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 98b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 99b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov tx_blks = wl->links[hlid].allocated_blks; 100b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 101b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 102b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 103b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 104b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 105b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) 106b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_ps_link_start(wl, hlid, true); 107b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 108b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 109a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovu8 wl1271_tx_get_hlid(struct sk_buff *skb) 110a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 111a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); 112a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 113a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (control->control.sta) { 114a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 115a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 116a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl_sta = (struct wl1271_station *) 117a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov control->control.sta->drv_priv; 118a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl_sta->hlid; 119a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 120a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_hdr *hdr; 121a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 122a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov hdr = (struct ieee80211_hdr *)skb->data; 123a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (ieee80211_is_mgmt(hdr->frame_control)) 124a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return WL1271_AP_GLOBAL_HLID; 125a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov else 126a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return WL1271_AP_BROADCAST_HLID; 127a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 128a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 129a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 130a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, 13109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 buf_offset, u8 hlid) 132f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 133f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 134f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 1355c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 136f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id, ret = -EBUSY; 137f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 138a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) 1396c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 140a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 141f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 14225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 143f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 144f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 145f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 146f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* approximate the number of blocks required for this packet 147f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho in the firmware */ 1485c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen total_blocks = total_len + TX_HW_BLOCK_SIZE - 1; 1495c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen total_blocks = total_blocks / TX_HW_BLOCK_SIZE + TX_HW_BLOCK_SPARE; 150f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 151f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 152f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 153f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 154f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->extra_mem_blocks = TX_HW_BLOCK_SPARE; 155f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->total_mem_blocks = total_blocks; 156f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 157f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 158f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 159f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 16009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 16109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[hlid].allocated_blks += total_blocks; 16209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 163f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 164f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 165f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 166f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 167f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 168781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 16925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 170781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 171f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 172f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 173f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 174f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 175a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, 17609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 extra, struct ieee80211_tx_info *control, 17709039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid) 178f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 179ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 180f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 181c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov int pad, ac, rate_idx; 182ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 183d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho u16 tx_attr; 184f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 185f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 186f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 1871e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 1881e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 1891e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen void *framestart = skb->data + sizeof(*desc); 1901e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen u16 fc = *(u16 *)(framestart + extra); 191d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); 1921e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(framestart, framestart + extra, hdrlen); 1931e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 1941e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 195f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 196ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 197ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 198ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 199c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 200c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (wl->bss_type != BSS_TYPE_AP_BSS) 201c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 202c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 203c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 204f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 205f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure the tx attributes */ 206d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho tx_attr = wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; 207c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo 208ed484a16b495ee7e13cb28fd6ff6053d10657633Juuso Oikarinen /* queue (we use same identifiers for tid's and ac's */ 209c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 210ed484a16b495ee7e13cb28fd6ff6053d10657633Juuso Oikarinen desc->tid = ac; 211c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 212c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (wl->bss_type != BSS_TYPE_AP_BSS) { 21309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov desc->aid = hlid; 214c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 215c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov /* if the packets are destined for AP (have a STA entry) 216c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov send them with AP rate policies, otherwise use default 217c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov basic rates */ 218c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (control->control.sta) 219c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_AP_FULL_RATE; 220c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 221c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_BASIC_RATE; 222c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 22309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov desc->hlid = hlid; 22409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov switch (hlid) { 22509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov case WL1271_AP_GLOBAL_HLID: 22609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_MGMT_RATE; 22709039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 22809039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov case WL1271_AP_BROADCAST_HLID: 22909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_BCST_RATE; 23009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 23109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov default: 232c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ac; 23309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov break; 234c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 235c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 236c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 237c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 238f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->reserved = 0; 239f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 240f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* align the length (and store in terms of words) */ 24102ad2d9080266e6d999c00b78610ef6a45be45eaEliad Peller pad = ALIGN(skb->len, WL1271_TX_ALIGN_TO); 242d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->length = cpu_to_le16(pad >> 2); 243f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 244f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* calculate number of padding bytes */ 245f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho pad = pad - skb->len; 246d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; 247d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 248d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 249f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 250c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " 2511d4801f2689dc2618fdb5e83d4cb7743747491edEliad Peller "tx_attr: 0x%x len: %d life: %d mem: %d", pad, desc->hlid, 2521d4801f2689dc2618fdb5e83d4cb7743747491edEliad Peller le16_to_cpu(desc->tx_attr), le16_to_cpu(desc->length), 2531d4801f2689dc2618fdb5e83d4cb7743747491edEliad Peller le16_to_cpu(desc->life_time), desc->total_mem_blocks); 254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 256f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 257a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, 258a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 buf_offset) 259f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 260f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 261f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 263a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 26409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid; 265f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 266f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!skb) 267f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 268f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 270f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 271f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 27297359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 273f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho extra = WL1271_TKIP_IV_SPACE; 274f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 275f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 2767f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 2777f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 2787f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 2797f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 2807f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 2817f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 282f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2837f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (unlikely(is_wep && wl->default_key != idx)) { 2847f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov ret = wl1271_set_default_wep_key(wl, idx); 285f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 286f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 287ee444cf0501183df1640cd35bebd4250989bfe99Juuso Oikarinen wl->default_key = idx; 288f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 289f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 290f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 29109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 29209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov hlid = wl1271_tx_get_hlid(skb); 29309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov else 29409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov hlid = TX_HW_DEFAULT_AID; 29509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 29609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); 297f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 298f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 299f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 300b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 30199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, skb); 302b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_tx_regulate_link(wl, hlid); 303b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 30499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 30509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); 306f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 307a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 308a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * The length of each packet is stored in terms of words. Thus, we must 309a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * pad the skb data to make sure its length is aligned. 310a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * The number of padding bytes is computed and set in wl1271_tx_fill_hdr 311a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 31202ad2d9080266e6d999c00b78610ef6a45be45eaEliad Peller total_len = ALIGN(skb->len, WL1271_TX_ALIGN_TO); 313a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 314a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 315f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 316a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 317f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 318f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 319ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinenu32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) 320830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 321830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 322830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 323830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 324830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 325830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen band = wl->hw->wiphy->bands[wl->band]; 326830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 327830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 328830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 329830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 330830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 331830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 33200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#ifdef CONFIG_WL12XX_HT 33318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi /* MCS rates indication are on bits 16 - 23 */ 33418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 33518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 33618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi for (bit = 0; bit < 8; bit++) { 33718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 33818357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 33918357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 34018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 34118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi#endif 34218357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 343830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 344830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 345830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 346a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 3472fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 3482fe33e8cff354a3f320549544bffebbbab680145Ido Yariv unsigned long flags; 3492fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 3502fe33e8cff354a3f320549544bffebbbab680145Ido Yariv if (test_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags) && 3516742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl->tx_queue_count <= WL1271_TX_QUEUE_LOW_WATERMARK) { 3522fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* firmware buffer has space, restart queues */ 3532fe33e8cff354a3f320549544bffebbbab680145Ido Yariv spin_lock_irqsave(&wl->wl_lock, flags); 3542fe33e8cff354a3f320549544bffebbbab680145Ido Yariv ieee80211_wake_queues(wl->hw); 3552fe33e8cff354a3f320549544bffebbbab680145Ido Yariv clear_bit(WL1271_FLAG_TX_QUEUE_STOPPED, &wl->flags); 3562fe33e8cff354a3f320549544bffebbbab680145Ido Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 3572fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 3582fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 3592fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 360a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) 3616742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 3626742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen struct sk_buff *skb = NULL; 3636742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 3646742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 3656742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VO]); 3666742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) 3676742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen goto out; 3686742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_VI]); 3696742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) 3706742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen goto out; 3716742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BE]); 3726742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) 3736742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen goto out; 3746742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen skb = skb_dequeue(&wl->tx_queue[CONF_TX_AC_BK]); 3756742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 3766742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenout: 3776742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 3786742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 3796742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl->tx_queue_count--; 3806742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 3816742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 3826742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 3836742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 3846742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 3856742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 386a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) 387a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 388a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 389a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 390a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 391a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 392a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 393a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; 394a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 395a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 396a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 397a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov h = (start_hlid + i) % AP_MAX_LINKS; 398a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 399a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VO]); 400a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) 401a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov goto out; 402a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_VI]); 403a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) 404a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov goto out; 405a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BE]); 406a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) 407a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov goto out; 408a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb = skb_dequeue(&wl->links[h].tx_queue[CONF_TX_AC_BK]); 409a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) 410a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov goto out; 411a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 412a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 413a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovout: 414a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) { 415a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = h; 416a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 417a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->tx_queue_count--; 418a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 419a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 420a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 421a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 422a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 423a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 424a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 425a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 426a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 427a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 428a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 429a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl1271_ap_skb_dequeue(wl); 430a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 431a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl1271_sta_skb_dequeue(wl); 432a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 433a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 4346742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) 4356742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 4366742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 4376742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 4386742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 439a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 440a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov u8 hlid = wl1271_tx_get_hlid(skb); 441a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 442a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 443a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 444a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS; 445a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 446a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->tx_queue[q], skb); 447a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 448a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 4496742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 4506742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl->tx_queue_count++; 4516742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 4526742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 4536742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 454a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work_locked(struct wl1271 *wl) 455f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 456f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 457f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho bool woken_up = false; 4586c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv u32 buf_offset = 0; 4596c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 460f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 461f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 462f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (unlikely(wl->state == WL1271_STATE_OFF)) 463f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho goto out; 464f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 4656742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen while ((skb = wl1271_skb_dequeue(wl))) { 466f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!woken_up) { 467a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv ret = wl1271_ps_elp_wakeup(wl); 468f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 469ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 470f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho woken_up = true; 471f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 472f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 473a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); 4746c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 475a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 4766c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 4776c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 4786c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 4796742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 4806c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 4816742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen buf_offset, true); 4826c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 4836c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 4846c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 4856c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 4866c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 4876c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 488a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 489a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 4906742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 491a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 492a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 493ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 494f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 495f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho dev_kfree_skb(skb); 496ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 497f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 498a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset += ret; 499a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 500f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 501f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 502ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 503a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 504a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 505a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset, true); 5066c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 5076c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 5086c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 509606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 510606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 511606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 512606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 513606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) 514606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl1271_write32(wl, WL1271_HOST_WR_ACCESS, 515606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl->tx_packets_count); 516606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 517a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 518a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 519ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 520f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhoout: 521f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (woken_up) 522f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_ps_elp_sleep(wl); 523a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 524f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 525a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 526a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 527a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 528a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 529a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 530a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv wl1271_tx_work_locked(wl); 531f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 532f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 533f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 534f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 535f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 536f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 537f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 538f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 539f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 54031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 54131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 542f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 543f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 544ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { 545f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 546f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 547f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 548f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 549f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 550f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 551f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 55231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 55331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 55431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 555f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 5566a2de93b2553c2e9a72997370534993c85c1eee6Teemu Paasikivi rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); 55731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 55831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 55931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 56031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 561f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 562f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 56331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 56431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 56531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].flags = 0; 56631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 56731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 568f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 569f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 570ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen /* update security sequence number */ 57104e36fc5f1ff4e349ea21de8d15e4e1844d04197Juuso Oikarinen wl->tx_security_seq += (result->lsb_security_sequence_number - 57204e36fc5f1ff4e349ea21de8d15e4e1844d04197Juuso Oikarinen wl->tx_security_last_seq); 573ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen wl->tx_security_last_seq = result->lsb_security_sequence_number; 574ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 5751e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 5761e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 5771e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 5781e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 579f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 58097359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 5811e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 5821e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); 5831e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, WL1271_TKIP_IV_SPACE); 5841e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 585f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 586f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 587f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 588f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 589f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 590f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 591f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 592a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 593a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv ieee80211_queue_work(wl->hw, &wl->netstack_work); 59425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 595f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 596f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 597f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 598ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenvoid wl1271_tx_complete(struct wl1271 *wl) 599f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 600f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_acx_mem_map *memmap = 601f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho (struct wl1271_acx_mem_map *)wl->target_mem_map; 602ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 603f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 604f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 605f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 6067b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_read(wl, le32_to_cpu(memmap->tx_result), 6077b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl->tx_res_if, sizeof(*wl->tx_res_if), false); 608ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 609ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 610ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 611ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + 612ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen offsetof(struct wl1271_tx_hw_res_if, 613ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen tx_result_host_counter), fw_counter); 614ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 615ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 61606f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 617f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 618f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 619ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 620f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 621f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 622f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 623f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 624f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 625f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 626f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 627f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 628f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 629f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 630f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 631f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 632f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 633f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 634f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 635a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 636a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 637a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 638a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, total = 0; 639a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 6401d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 641a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 642a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 643a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 644a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 6451d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info = IEEE80211_SKB_CB(skb); 6461d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].idx = -1; 6471d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].count = 0; 648a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov ieee80211_tx_status(wl->hw, skb); 649a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov total++; 650a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 651a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 652a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 653a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 654a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->tx_queue_count -= total; 655a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 656a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 657a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 658a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 659a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 660f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 661781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_reset(struct wl1271 *wl) 662f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 663f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 664f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 6651d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 666f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 667f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 668a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 66909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 670a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 67109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].allocated_blks = 0; 67209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].prev_freed_blks = 0; 67309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov } 674a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 675a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 676a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 677a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 678a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->tx_queue[i]))) { 679a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "freeing skb 0x%p", 680a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb); 6811d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info = IEEE80211_SKB_CB(skb); 6821d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].idx = -1; 6831d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov info->status.rates[0].count = 0; 684a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov ieee80211_tx_status(wl->hw, skb); 685a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 6866742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 687f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 688a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 6896742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl->tx_queue_count = 0; 690f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6912fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 6922fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 6932fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 6942fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 695a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 6962fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 69750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { 69850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 69950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 70050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 70150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 70250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 70350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 70450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 70550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv /* Remove private headers before passing the skb to mac80211 */ 70650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv info = IEEE80211_SKB_CB(skb); 70750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 70850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (info->control.hw_key && 70950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 71050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 71150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, 71250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv hdrlen); 71350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb_pull(skb, WL1271_TKIP_IV_SPACE); 714f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 71550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 71650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv info->status.rates[0].idx = -1; 71750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv info->status.rates[0].count = 0; 71850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 71950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv ieee80211_tx_status(wl->hw, skb); 72050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 721781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 722781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 723781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 724781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 725781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 726781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 727781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 728781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen unsigned long timeout; 729781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 730781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 731781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 732781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_lock(&wl->mutex); 733a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 734a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->tx_frames_cnt, wl->tx_queue_count); 7356742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if ((wl->tx_frames_cnt == 0) && (wl->tx_queue_count == 0)) { 736781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 737781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen return; 738781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 739781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 740781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen msleep(1); 741781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 742781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 743781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen wl1271_warning("Unable to flush all TX buffers, timed out."); 744f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 745e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 746e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsovu32 wl1271_tx_min_rate_get(struct wl1271 *wl) 747e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 748e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov int i; 749e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov u32 rate = 0; 750e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 751e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if (!wl->basic_rate_set) { 752e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov WARN_ON(1); 753e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov wl->basic_rate_set = wl->conf.tx.basic_rate; 754e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 755e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 756e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov for (i = 0; !rate; i++) { 757e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if ((wl->basic_rate_set >> i) & 0x1) 758e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov rate = 1 << i; 759e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 760e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 761e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov return rate; 762e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 763