tx.c revision 742246f8bc16c3a1a556c68ca2fabca162d14c24
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) 40c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, 41e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov wl->ap_bcast_hlid); 427f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov else 43c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller ret = wl12xx_cmd_set_default_wep_key(wl, id, wl->sta_hlid); 447f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 457f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (ret < 0) 467f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return ret; 477f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 487f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id); 497f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov return 0; 507f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov} 517f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 5225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb) 53f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 5425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv int id; 5525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 5625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = find_first_zero_bit(wl->tx_frames_map, ACX_TX_DESCRIPTORS); 5725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (id >= ACX_TX_DESCRIPTORS) 5825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return -EBUSY; 5925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv 6025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv __set_bit(id, wl->tx_frames_map); 6125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = skb; 6225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt++; 6325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv return id; 6425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv} 65f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6625eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic void wl1271_free_tx_id(struct wl1271 *wl, int id) 6725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{ 6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv if (__test_and_clear_bit(id, wl->tx_frames_map)) { 69ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv if (unlikely(wl->tx_frames_cnt == ACX_TX_DESCRIPTORS)) 70ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 71ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv 7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames[id] = NULL; 7325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl->tx_frames_cnt--; 7425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv } 75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 76f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 77c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohenstatic int wl1271_tx_update_filters(struct wl1271 *wl, 78c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen struct sk_buff *skb) 79c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen{ 80c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen struct ieee80211_hdr *hdr; 81251c177f886027fbce494202e44935762f103137Eliad Peller int ret; 82c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 83c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen hdr = (struct ieee80211_hdr *)(skb->data + 84c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen sizeof(struct wl1271_tx_hw_descr)); 85c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 86c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen /* 87c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * stop bssid-based filtering before transmitting authentication 88c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * requests. this way the hw will never drop authentication 89c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * responses coming from BSSIDs it isn't familiar with (e.g. on 90c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen * roaming) 91c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen */ 92c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen if (!ieee80211_is_auth(hdr->frame_control)) 93c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen return 0; 94c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 95251c177f886027fbce494202e44935762f103137Eliad Peller if (wl->dev_hlid != WL12XX_INVALID_LINK_ID) 96251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 97251c177f886027fbce494202e44935762f103137Eliad Peller 98251c177f886027fbce494202e44935762f103137Eliad Peller wl1271_debug(DEBUG_CMD, "starting device role for roaming"); 99251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl12xx_cmd_role_start_dev(wl); 100251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 101251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 102251c177f886027fbce494202e44935762f103137Eliad Peller 103251c177f886027fbce494202e44935762f103137Eliad Peller ret = wl12xx_roc(wl, wl->dev_role_id); 104251c177f886027fbce494202e44935762f103137Eliad Peller if (ret < 0) 105251c177f886027fbce494202e44935762f103137Eliad Peller goto out; 106251c177f886027fbce494202e44935762f103137Eliad Pellerout: 10708c1d1c7042330e2280a7718be4ad88c2e8f8268Eliad Peller return 0; 108c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen} 109c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen 11099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl, 11199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct sk_buff *skb) 11299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{ 11399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov struct ieee80211_hdr *hdr; 11499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 11599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov /* 11699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * add the station to the known list before transmitting the 11799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * authentication response. this way it won't get de-authed by FW 11899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov * when transmitting too soon. 11999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov */ 12099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov hdr = (struct ieee80211_hdr *)(skb->data + 12199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov sizeof(struct wl1271_tx_hw_descr)); 12299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov if (ieee80211_is_auth(hdr->frame_control)) 12399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_acx_set_inconnection_sta(wl, hdr->addr1); 12499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov} 12599a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 126dbe25cb5eb04b0ffdad582a93f9fe9edd0ed791bEliad Peller#if 0 127b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsovstatic void wl1271_tx_regulate_link(struct wl1271 *wl, u8 hlid) 128b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{ 129b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov bool fw_ps; 130b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov u8 tx_blks; 131b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 132b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* only regulate station links */ 133b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (hlid < WL1271_AP_STA_HLID_START) 134b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov return; 135b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 136b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov fw_ps = test_bit(hlid, (unsigned long *)&wl->ap_fw_ps_map); 137b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov tx_blks = wl->links[hlid].allocated_blks; 138b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 139b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov /* 140b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * if in FW PS and there is enough data in FW we can put the link 141b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov * into high-level PS and clean out its TX queues. 142b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov */ 143b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (fw_ps && tx_blks >= WL1271_PS_STA_MAX_BLOCKS) 144b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_ps_link_start(wl, hlid, true); 145b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov} 146dbe25cb5eb04b0ffdad582a93f9fe9edd0ed791bEliad Peller#endif 147b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov 148f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Pellerstatic bool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb) 149f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 150f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->dummy_packet == skb; 151f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 152f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 153f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Pelleru8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct sk_buff *skb) 154a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 155a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_tx_info *control = IEEE80211_SKB_CB(skb); 156a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 157a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (control->control.sta) { 158a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct wl1271_station *wl_sta; 159a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 160a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl_sta = (struct wl1271_station *) 161a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov control->control.sta->drv_priv; 162a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return wl_sta->hlid; 163a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 164a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct ieee80211_hdr *hdr; 165a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 166f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller if (!test_bit(WL1271_FLAG_AP_STARTED, &wl->flags)) 167f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->system_hlid; 168f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 169a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov hdr = (struct ieee80211_hdr *)skb->data; 170a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (ieee80211_is_mgmt(hdr->frame_control)) 171e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov return wl->ap_global_hlid; 172a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov else 173e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov return wl->ap_bcast_hlid; 174a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 175a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 176a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 177f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Pellerstatic u8 wl1271_tx_get_hlid(struct wl1271 *wl, struct sk_buff *skb) 178f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{ 179f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller if (wl12xx_is_dummy_packet(wl, skb)) 180f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->system_hlid; 181f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 182f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller if (wl->bss_type == BSS_TYPE_AP_BSS) 183f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl12xx_tx_get_hlid_ap(wl, skb); 184f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 185227e81e18422851901b9de11c5955d292c4a47fcEliad Peller if (test_bit(WL1271_FLAG_STA_ASSOCIATED, &wl->flags) || 186227e81e18422851901b9de11c5955d292c4a47fcEliad Peller test_bit(WL1271_FLAG_IBSS_JOINED, &wl->flags)) 187f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->sta_hlid; 188f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller else 189f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller return wl->dev_hlid; 190f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller} 191f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller 1920da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yarivstatic unsigned int wl12xx_calc_packet_alignment(struct wl1271 *wl, 1930da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv unsigned int packet_length) 1940da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{ 1950da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv if (wl->quirks & WL12XX_QUIRK_BLOCKSIZE_ALIGNMENT) 1960da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE); 1970da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv else 1980da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv return ALIGN(packet_length, WL1271_TX_ALIGN_TO); 1990da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv} 2000da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv 201a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_tx_allocate(struct wl1271 *wl, struct sk_buff *skb, u32 extra, 20209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 buf_offset, u8 hlid) 203f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 204f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 205f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra; 20648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi u32 len; 2075c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen u32 total_blocks; 208742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int id, ret = -EBUSY, ac; 209e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho 2102920743a14764eda099700e1eca9a282393cee16Arik Nemtsov /* we use 1 spare block */ 2112920743a14764eda099700e1eca9a282393cee16Arik Nemtsov u32 spare_blocks = 1; 212f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 213a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset + total_len > WL1271_AGGR_BUFFER_SIZE) 2146c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv return -EAGAIN; 215a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv 216f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* allocate free identifier for the packet */ 21725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv id = wl1271_alloc_tx_id(wl, skb); 218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (id < 0) 219f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return id; 220f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 221f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* approximate the number of blocks required for this packet 222f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho in the firmware */ 2230da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv len = wl12xx_calc_packet_alignment(wl, total_len); 22448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 22548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi total_blocks = (len + TX_HW_BLOCK_SIZE - 1) / TX_HW_BLOCK_SIZE + 226e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho spare_blocks; 22748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 228f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (total_blocks <= wl->tx_blocks_available) { 229f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *)skb_push( 230f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb, total_len - skb->len); 231f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 232ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi /* HW descriptor fields change between wl127x and wl128x */ 233ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi if (wl->chip.id == CHIP_ID_1283_PG20) { 234ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks = total_blocks; 235ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } else { 236e7ddf549f3f2da156f5c12921e6699024e80a3f4Luciano Coelho desc->wl127x_mem.extra_blocks = spare_blocks; 237ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks = total_blocks; 238ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi } 239ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 240f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->id = id; 241f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 242f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_blocks_available -= total_blocks; 2437bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov wl->tx_allocated_blocks += total_blocks; 244f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 245742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 246742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov wl->tx_allocated_pkts[ac]++; 247bf54e301671a6ece6c94550294dc7faf14158cd3Arik Nemtsov 24809039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 24909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[hlid].allocated_blks += total_blocks; 25009039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 251f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho ret = 0; 252f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 253f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, 254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho "tx_allocate: size: %d, blocks: %d, id: %d", 255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho total_len, total_blocks, id); 256781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } else { 25725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, id); 258781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 259f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 260f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 261f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 263a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct sk_buff *skb, 26409039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u32 extra, struct ieee80211_tx_info *control, 26509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid) 266f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 267ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen struct timespec ts; 268f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_descr *desc; 26948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int aligned_len, ac, rate_idx; 270ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen s64 hosttime; 271d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho u16 tx_attr; 272f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 273f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc = (struct wl1271_tx_hw_descr *) skb->data; 274f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 2751e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* relocate space for security header */ 2761e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen if (extra) { 2771e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen void *framestart = skb->data + sizeof(*desc); 2781e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen u16 fc = *(u16 *)(framestart + extra); 279d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho int hdrlen = ieee80211_hdrlen(cpu_to_le16(fc)); 2801e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(framestart, framestart + extra, hdrlen); 2811e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 2821e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 283f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* configure packet life time */ 284ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen getnstimeofday(&ts); 285ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen hosttime = (timespec_to_ns(&ts) >> 10); 286ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen desc->start_time = cpu_to_le32(hosttime - wl->time_offset); 287c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 288c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (wl->bss_type != BSS_TYPE_AP_BSS) 289c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU); 290c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 291c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU); 292f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 293db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller /* queue */ 294c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 295db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller desc->tid = skb->priority; 296c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 297990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 298ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 299ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * FW expects the dummy packet to have an invalid session id - 300ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * any session id that is different than the one set in the join 301ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 302ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr = ((~wl->session_counter) << 303ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_OFST_SESSION_COUNTER) & 304ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi TX_HW_ATTR_SESSION_COUNTER; 305ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 306ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ; 307ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } else { 308ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* configure the tx attributes */ 309ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi tx_attr = 310ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl->session_counter << TX_HW_ATTR_OFST_SESSION_COUNTER; 311ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 312ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 31379b122dc51797b650201f21360481a0450e9b7e4Eliad Peller desc->hlid = hlid; 314c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 31579b122dc51797b650201f21360481a0450e9b7e4Eliad Peller if (wl->bss_type != BSS_TYPE_AP_BSS) { 316c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov /* if the packets are destined for AP (have a STA entry) 317c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov send them with AP rate policies, otherwise use default 318c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov basic rates */ 319c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov if (control->control.sta) 320c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_AP_FULL_RATE; 321c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov else 322c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ACX_TX_BASIC_RATE; 323c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } else { 324e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov if (hlid == wl->ap_global_hlid) 32509039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_MGMT_RATE; 326e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov else if (hlid == wl->ap_bcast_hlid) 32709039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov rate_idx = ACX_TX_AP_MODE_BCST_RATE; 328e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov else 329c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov rate_idx = ac; 330c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov } 331c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov 332c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY; 333f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho desc->reserved = 0; 334f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3350da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv aligned_len = wl12xx_calc_packet_alignment(wl, skb->len); 33648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3370da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv if (wl->chip.id == CHIP_ID_1283_PG20) { 33848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->wl128x_mem.extra_bytes = aligned_len - skb->len; 33948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 340ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi 341ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: hlid: %d " 342ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", 343ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 344ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 345ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 346ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl128x_mem.total_mem_blocks); 34748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } else { 34848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi int pad; 34948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 3500da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv /* Store the aligned length in terms of words */ 35148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi desc->length = cpu_to_le16(aligned_len >> 2); 35248a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 35348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi /* calculate number of padding bytes */ 35448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi pad = aligned_len - skb->len; 35548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi tx_attr |= pad << TX_HW_ATTR_OFST_LAST_WORD_PAD; 356f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 357ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi wl1271_debug(DEBUG_TX, "tx_fill_hdr: pad: %d hlid: %d " 358ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi "tx_attr: 0x%x len: %d life: %d mem: %d", pad, 359ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->hlid, tx_attr, 360ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->length), 361ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi le16_to_cpu(desc->life_time), 362ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi desc->wl127x_mem.total_mem_blocks); 36348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi } 364d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho 365d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho desc->tx_attr = cpu_to_le16(tx_attr); 366f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 367f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 368f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */ 369a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yarivstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct sk_buff *skb, 370a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 buf_offset) 371f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 372f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 extra = 0; 374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret = 0; 375a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv u32 total_len; 37609039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov u8 hlid; 377f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (!skb) 379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return -EINVAL; 380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 382f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 383f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 38497359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) 385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho extra = WL1271_TKIP_IV_SPACE; 386f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 387f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key) { 3887f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov bool is_wep; 3897f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u8 idx = info->control.hw_key->hw_key_idx; 3907f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov u32 cipher = info->control.hw_key->cipher; 3917f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov 3927f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) || 3937f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov (cipher == WLAN_CIPHER_SUITE_WEP104); 394f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 3957f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov if (unlikely(is_wep && wl->default_key != idx)) { 3967f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov ret = wl1271_set_default_wep_key(wl, idx); 397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 398f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 399ee444cf0501183df1640cd35bebd4250989bfe99Juuso Oikarinen wl->default_key = idx; 400f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 401f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 402f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 403f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller hlid = wl1271_tx_get_hlid(wl, skb); 40479b122dc51797b650201f21360481a0450e9b7e4Eliad Peller if (hlid == WL12XX_INVALID_LINK_ID) { 40579b122dc51797b650201f21360481a0450e9b7e4Eliad Peller wl1271_error("invalid hlid. dropping skb 0x%p", skb); 40679b122dc51797b650201f21360481a0450e9b7e4Eliad Peller return -EINVAL; 40779b122dc51797b650201f21360481a0450e9b7e4Eliad Peller } 40809039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov 40909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov ret = wl1271_tx_allocate(wl, skb, extra, buf_offset, hlid); 410f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (ret < 0) 411f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return ret; 412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 413fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov wl1271_tx_fill_hdr(wl, skb, extra, info, hlid); 414fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov 415b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 41699a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov wl1271_tx_ap_update_inconnection_sta(wl, skb); 417dbe25cb5eb04b0ffdad582a93f9fe9edd0ed791bEliad Peller#if 0 418b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov wl1271_tx_regulate_link(wl, hlid); 419dbe25cb5eb04b0ffdad582a93f9fe9edd0ed791bEliad Peller#endif 420c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen } else { 421c5745187a4812f2991a58e469a866582a7326d91Ohad Ben-Cohen wl1271_tx_update_filters(wl, skb); 422b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov } 42399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov 424a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 42548a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * The length of each packet is stored in terms of 42648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * words. Thus, we must pad the skb data to make sure its 42748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * length is aligned. The number of padding bytes is computed 42848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * and set in wl1271_tx_fill_hdr. 42948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * In special cases, we want to align to a specific block size 43048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi * (eg. for wl128x with SDIO we align to 256). 431a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 4320da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv total_len = wl12xx_calc_packet_alignment(wl, skb->len); 43348a61477bdc04896bd96d259388a0c42a7019943Shahar Levi 434a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len); 435a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len); 436f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 437990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv /* Revert side effects in the dummy packet skb, so it can be reused */ 438990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) 439990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 440990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 441a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv return total_len; 442f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 443f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 444ebba60c66b3aa321a84c9a90a343c91fde972066Juuso Oikarinenu32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set) 445830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{ 446830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen struct ieee80211_supported_band *band; 447830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen u32 enabled_rates = 0; 448830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen int bit; 449830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 450830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen band = wl->hw->wiphy->bands[wl->band]; 451830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen for (bit = 0; bit < band->n_bitrates; bit++) { 452830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen if (rate_set & 0x1) 453830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen enabled_rates |= band->bitrates[bit].hw_value; 454830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen rate_set >>= 1; 455830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen } 456830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 45700d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#ifdef CONFIG_WL12XX_HT 45818357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi /* MCS rates indication are on bits 16 - 23 */ 45918357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates; 46018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 46118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi for (bit = 0; bit < 8; bit++) { 46218357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi if (rate_set & 0x1) 46318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit); 46418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi rate_set >>= 1; 46518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi } 46618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi#endif 46718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi 468830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen return enabled_rates; 469830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen} 470830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen 471a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl) 4722fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{ 4732fe33e8cff354a3f320549544bffebbbab680145Ido Yariv unsigned long flags; 474708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov int i; 4752fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 476708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 477708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov if (test_bit(i, &wl->stopped_queues_map) && 478f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] <= WL1271_TX_QUEUE_LOW_WATERMARK) { 479708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov /* firmware buffer has space, restart queues */ 480708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 481708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov ieee80211_wake_queue(wl->hw, 482708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl1271_tx_get_mac80211_queue(i)); 483708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov clear_bit(i, &wl->stopped_queues_map); 484708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 485708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov } 4862fe33e8cff354a3f320549544bffebbbab680145Ido Yariv } 4872fe33e8cff354a3f320549544bffebbbab680145Ido Yariv} 4882fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 489742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsovstatic struct sk_buff_head *wl1271_select_queue(struct wl1271 *wl, 490742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queues) 491742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov{ 492742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov int i, q = -1, ac; 493742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov u32 min_pkts = 0xffffffff; 494742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 495742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* 496742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * Find a non-empty ac where: 497742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 1. There are packets to transmit 498742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 2. The FW has the least allocated blocks 499742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * 500742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov * We prioritize the ACs according to VO>VI>BE>BK 501742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov */ 502742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 503742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov ac = wl1271_tx_get_queue(i); 504742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!skb_queue_empty(&queues[ac]) && 505742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov (wl->tx_allocated_pkts[ac] < min_pkts)) { 506742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov q = ac; 507742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov min_pkts = wl->tx_allocated_pkts[q]; 508742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 509742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov } 510742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 511742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (q == -1) 512742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return NULL; 513742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 514742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov return &queues[q]; 515742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov} 516742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 517a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_sta_skb_dequeue(struct wl1271 *wl) 5186742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 5196742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen struct sk_buff *skb = NULL; 5206742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 521742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queue; 5226742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 523742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov queue = wl1271_select_queue(wl, wl->tx_queue); 524742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!queue) 5257bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov goto out; 526742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 527742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov skb = skb_dequeue(queue); 5286742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5296742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenout: 5306742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen if (skb) { 531f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 5326742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 533f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 5346742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 5356742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 5366742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 5376742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen return skb; 5386742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 5396742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 540a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_ap_skb_dequeue(struct wl1271 *wl) 541a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 542a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb = NULL; 543a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 544a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov int i, h, start_hlid; 545742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov struct sk_buff_head *queue; 546a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 547a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* start from the link after the last one */ 548a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov start_hlid = (wl->last_tx_hlid + 1) % AP_MAX_LINKS; 549a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 550a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* dequeue according to AC, round robin on each link */ 551a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 552a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov h = (start_hlid + i) % AP_MAX_LINKS; 553a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 554742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov /* only consider connected stations */ 555742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (h >= WL1271_AP_STA_HLID_START && 556742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov !test_bit(h - WL1271_AP_STA_HLID_START, wl->ap_hlid_map)) 557742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 558742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 559742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov queue = wl1271_select_queue(wl, wl->links[h].tx_queue); 560742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov if (!queue) 561742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov continue; 562742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov 563742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov skb = skb_dequeue(queue); 5647bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov if (skb) 565742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov break; 566a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 567a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 568a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (skb) { 569f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 570a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = h; 571a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 572f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 573a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 574a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 575a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 576a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 577a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 578a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov return skb; 579a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 580a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 581a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl) 582a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 583990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv unsigned long flags; 584990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv struct sk_buff *skb = NULL; 585990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 586a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) 587990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl1271_ap_skb_dequeue(wl); 588990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv else 589990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl1271_sta_skb_dequeue(wl); 590a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 591990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!skb && 592990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) { 593f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int q; 594f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov 595990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv skb = wl->dummy_packet; 596f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 597990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_lock_irqsave(&wl->wl_lock, flags); 598f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]--; 599990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv spin_unlock_irqrestore(&wl->wl_lock, flags); 600990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } 601990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv 602990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv return skb; 603a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 604a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 6056742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinenstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct sk_buff *skb) 6066742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{ 6076742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen unsigned long flags; 6086742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb)); 6096742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 610990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 611990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags); 612990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv } else if (wl->bss_type == BSS_TYPE_AP_BSS) { 613f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller u8 hlid = wl1271_tx_get_hlid(wl, skb); 614a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->links[hlid].tx_queue[q], skb); 615a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 616a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov /* make sure we dequeue the same packet next time */ 617a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = (hlid + AP_MAX_LINKS - 1) % AP_MAX_LINKS; 618a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 619a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb_queue_head(&wl->tx_queue[q], skb); 620a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 621a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 6226742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_lock_irqsave(&wl->wl_lock, flags); 623f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[q]++; 6246742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen spin_unlock_irqrestore(&wl->wl_lock, flags); 6256742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen} 6266742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen 62777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb) 62877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{ 62977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data); 63077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 63177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller return ieee80211_is_data_present(hdr->frame_control); 63277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller} 63377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 634a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work_locked(struct wl1271 *wl) 635f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 636f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 6376c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv u32 buf_offset = 0; 6386c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv bool sent_packets = false; 63977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller bool had_data = false; 64077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller bool is_ap = (wl->bss_type == BSS_TYPE_AP_BSS); 641f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int ret; 642f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 643f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (unlikely(wl->state == WL1271_STATE_OFF)) 644c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller return; 645f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 6466742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen while ((skb = wl1271_skb_dequeue(wl))) { 64777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (wl1271_tx_is_data_present(skb)) 64877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller had_data = true; 64977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 650a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv ret = wl1271_prepare_tx_frame(wl, skb, buf_offset); 6516c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (ret == -EAGAIN) { 652a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv /* 6536c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Aggregation buffer is full. 6546c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Flush buffer and try again. 6556c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv */ 6566742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 6576c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 6586742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen buf_offset, true); 6596c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 6606c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv buf_offset = 0; 6616c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv continue; 6626c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } else if (ret == -EBUSY) { 6636c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv /* 6646c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv * Firmware buffer is full. 665a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv * Queue back last skb, and stop aggregating. 666a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv */ 6676742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen wl1271_skb_queue_head(wl, skb); 668a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv /* No work left, avoid scheduling redundant tx work */ 669a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags); 670ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 671f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } else if (ret < 0) { 672f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho dev_kfree_skb(skb); 673ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen goto out_ack; 674f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 675a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset += ret; 676a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl->tx_packets_count++; 677f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 678f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 679ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack: 680a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv if (buf_offset) { 681a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv wl1271_write(wl, WL1271_SLV_MEM_DATA, wl->aggr_buf, 682a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv buf_offset, true); 6836c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv sent_packets = true; 6846c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv } 6856c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv if (sent_packets) { 686606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv /* 687606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * Interrupt the firmware with the new packets. This is only 688606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv * required for older hardware revisions 689606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv */ 690606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv if (wl->quirks & WL12XX_QUIRK_END_OF_TRANSACTION) 691606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl1271_write32(wl, WL1271_HOST_WR_ACCESS, 692606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv wl->tx_packets_count); 693606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv 694a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 695a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv } 69677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (!is_ap && wl->conf.rx_streaming.interval && had_data && 69777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller (wl->conf.rx_streaming.always || 69877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))) { 69977ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller u32 timeout = wl->conf.rx_streaming.duration; 70077ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 70177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller /* enable rx streaming */ 70277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller if (!test_bit(WL1271_FLAG_RX_STREAMING_STARTED, &wl->flags)) 70377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller ieee80211_queue_work(wl->hw, 70477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller &wl->rx_streaming_enable_work); 70577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller 70677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller mod_timer(&wl->rx_streaming_timer, 70777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller jiffies + msecs_to_jiffies(timeout)); 70877ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller } 709a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv} 710f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 711a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work) 712a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{ 713a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv struct wl1271 *wl = container_of(work, struct wl1271, tx_work); 714c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller int ret; 715a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv 716a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv mutex_lock(&wl->mutex); 717c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller ret = wl1271_ps_elp_wakeup(wl); 718c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller if (ret < 0) 719c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller goto out; 720c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 721a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv wl1271_tx_work_locked(wl); 722c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller 723c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller wl1271_ps_elp_sleep(wl); 724c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout: 725f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho mutex_unlock(&wl->mutex); 726f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 727f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 728f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl, 729f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result) 730f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 731f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct ieee80211_tx_info *info; 732f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 733f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int id = result->id; 73431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen int rate = -1; 73531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen u8 retries = 0; 736f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 737f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* check for id legality */ 738ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(id >= ACX_TX_DESCRIPTORS || wl->tx_frames[id] == NULL)) { 739f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result illegal id: %d", id); 740f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho return; 741f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 742f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 743f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho skb = wl->tx_frames[id]; 744f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info = IEEE80211_SKB_CB(skb); 745f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 746990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (wl12xx_is_dummy_packet(wl, skb)) { 747ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi wl1271_free_tx_id(wl, id); 748ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi return; 749ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 750ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 75131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen /* update the TX status info */ 75231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (result->status == TX_SUCCESS) { 75331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen if (!(info->flags & IEEE80211_TX_CTL_NO_ACK)) 754f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho info->flags |= IEEE80211_TX_STAT_ACK; 7556a2de93b2553c2e9a72997370534993c85c1eee6Teemu Paasikivi rate = wl1271_rate_to_idx(result->rate_class_index, wl->band); 75631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 75731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen } else if (result->status == TX_RETRY_EXCEEDED) { 75831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen wl->stats.excessive_retries++; 75931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen retries = result->ack_failures; 760f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 761f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 76231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].idx = rate; 76331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].count = retries; 76431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.rates[0].flags = 0; 76531627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen info->status.ack_signal = -1; 76631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen 767f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->stats.retry_count += result->ack_failures; 768f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 769b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 770b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update sequence number only when relevant, i.e. only in 771b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * sessions of TKIP, AES and GEM (not in open or WEP sessions) 772b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 773b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski if (info->control.hw_key && 774b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski (info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP || 775b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WLAN_CIPHER_SUITE_CCMP || 776b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski info->control.hw_key->cipher == WL1271_CIPHER_SUITE_GEM)) { 777b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 fw_lsb = result->tx_security_sequence_number_lsb; 778b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski u8 cur_lsb = wl->tx_security_last_seq_lsb; 779b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski 780b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski /* 781b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * update security sequence number, taking care of potential 782b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski * wrap-around 783b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski */ 784b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski wl->tx_security_seq += (fw_lsb - cur_lsb + 256) % 256; 785b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski wl->tx_security_last_seq_lsb = fw_lsb; 786b992c68228a3ccdf73ea4f57519e1663839a9cbeOz Krakowski } 787ac4e4ce54eb9cb4963a1d3d91fc65536d882ffb2Juuso Oikarinen 7881e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove private header from packet */ 7891e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 7901e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen 7911e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen /* remove TKIP header space if present */ 792f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho if (info->control.hw_key && 79397359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) { 7941e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 7951e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen memmove(skb->data + WL1271_TKIP_IV_SPACE, skb->data, hdrlen); 7961e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen skb_pull(skb, WL1271_TKIP_IV_SPACE); 7971e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen } 798f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 799f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x" 800f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho " status 0x%x", 801f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->id, skb, result->ack_failures, 802f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result->rate_class_index, result->status); 803f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 804f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* return the packet to the stack */ 805a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv skb_queue_tail(&wl->deferred_tx_queue, skb); 80692ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller queue_work(wl->freezable_wq, &wl->netstack_work); 80725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv wl1271_free_tx_id(wl, result->id); 808f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 809f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 810f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */ 811ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenvoid wl1271_tx_complete(struct wl1271 *wl) 812f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 813f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_acx_mem_map *memmap = 814f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho (struct wl1271_acx_mem_map *)wl->target_mem_map; 815ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen u32 count, fw_counter; 816f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u32 i; 817f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* read the tx results from the chipset */ 8197b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl1271_read(wl, le32_to_cpu(memmap->tx_result), 8207b048c52d7283ebf07c826a45c631a6ba225c057Teemu Paasikivi wl->tx_res_if, sizeof(*wl->tx_res_if), false); 821ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter); 822ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 823ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen /* write host counter to chipset (to ack) */ 824ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen wl1271_write32(wl, le32_to_cpu(memmap->tx_result) + 825ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen offsetof(struct wl1271_tx_hw_res_if, 826ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen tx_result_host_counter), fw_counter); 827ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen 828ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen count = fw_counter - wl->tx_results_count; 82906f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count); 830f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 831f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* verify that the result buffer is not getting overrun */ 832ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen if (unlikely(count > TX_HW_RESULT_QUEUE_LEN)) 833f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_warning("TX result overflow from chipset: %d", count); 834f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 835f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the results */ 836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho for (i = 0; i < count; i++) { 837f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct wl1271_tx_hw_res_descr *result; 838f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK; 839f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 840f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* process the packet */ 841f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho result = &(wl->tx_res_if->tx_results_queue[offset]); 842f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl1271_tx_complete_packet(wl, result); 843f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 844f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho wl->tx_results_count++; 845f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 846f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 847f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 848a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid) 849a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{ 850a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov struct sk_buff *skb; 851f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int i; 852a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov unsigned long flags; 8531d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 854f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov int total[NUM_TX_QUEUES]; 855a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 856a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 857f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i] = 0; 858a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->links[hlid].tx_queue[i]))) { 859a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb); 86079ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 86179ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov if (!wl12xx_is_dummy_packet(wl, skb)) { 86279ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info = IEEE80211_SKB_CB(skb); 86379ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].idx = -1; 86479ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov info->status.rates[0].count = 0; 86579ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov ieee80211_tx_status_ni(wl->hw, skb); 86679ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov } 86779ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov 868f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov total[i]++; 869a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 870a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 871a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 872a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_lock_irqsave(&wl->wl_lock, flags); 873f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) 874f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] -= total[i]; 875a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov spin_unlock_irqrestore(&wl->wl_lock, flags); 876a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 877a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 878a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov} 879a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 8807dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */ 8817dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsovvoid wl1271_tx_reset(struct wl1271 *wl, bool reset_tx_queues) 882f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{ 883f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho int i; 884f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho struct sk_buff *skb; 8851d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov struct ieee80211_tx_info *info; 886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho /* TX failure */ 888a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov if (wl->bss_type == BSS_TYPE_AP_BSS) { 88909039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov for (i = 0; i < AP_MAX_LINKS; i++) { 890a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_tx_reset_link_queues(wl, i); 89109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].allocated_blks = 0; 89209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov wl->links[i].prev_freed_blks = 0; 89309039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov } 894a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 895a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl->last_tx_hlid = 0; 896a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } else { 897a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov for (i = 0; i < NUM_TX_QUEUES; i++) { 898a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov while ((skb = skb_dequeue(&wl->tx_queue[i]))) { 899a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "freeing skb 0x%p", 900a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov skb); 901ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi 902990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 903ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 904ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 905ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 906c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 907ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 908a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov } 909f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_queue_count[i] = 0; 9106742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen } 911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho } 912a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov 913708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov wl->stopped_queues_map = 0; 914f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho 9152fe33e8cff354a3f320549544bffebbbab680145Ido Yariv /* 9162fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * Make sure the driver is at a consistent state, in case this 9172fe33e8cff354a3f320549544bffebbbab680145Ido Yariv * function is called from a context other than interface removal. 9187dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov * This call will always wake the TX queues. 9192fe33e8cff354a3f320549544bffebbbab680145Ido Yariv */ 9207dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov if (reset_tx_queues) 9217dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov wl1271_handle_tx_low_watermark(wl); 9222fe33e8cff354a3f320549544bffebbbab680145Ido Yariv 92350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv for (i = 0; i < ACX_TX_DESCRIPTORS; i++) { 92450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv if (wl->tx_frames[i] == NULL) 92550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv continue; 92650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 92750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv skb = wl->tx_frames[i]; 92850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_free_tx_id(wl, i); 92950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb); 93050e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 931990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv if (!wl12xx_is_dummy_packet(wl, skb)) { 932ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi /* 933ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * Remove private headers before passing the skb to 934ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi * mac80211 935ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi */ 936ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info = IEEE80211_SKB_CB(skb); 937ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, sizeof(struct wl1271_tx_hw_descr)); 938ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi if (info->control.hw_key && 939ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->control.hw_key->cipher == 940ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi WLAN_CIPHER_SUITE_TKIP) { 941ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi int hdrlen = ieee80211_get_hdrlen_from_skb(skb); 942ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi memmove(skb->data + WL1271_TKIP_IV_SPACE, 943ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb->data, hdrlen); 944ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi skb_pull(skb, WL1271_TKIP_IV_SPACE); 945ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 94650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 947ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].idx = -1; 948ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi info->status.rates[0].count = 0; 94950e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv 950c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller ieee80211_tx_status_ni(wl->hw, skb); 951ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi } 95250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv } 953781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen} 954781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 955781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000 956781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 957781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */ 958781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl) 959781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{ 960781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen unsigned long timeout; 961781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen timeout = jiffies + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT); 962781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 963781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen while (!time_after(jiffies, timeout)) { 964781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_lock(&wl->mutex); 965a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov wl1271_debug(DEBUG_TX, "flushing tx buffer: %d %d", 966f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl->tx_frames_cnt, 967f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov wl1271_tx_total_queue_count(wl)); 968f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov if ((wl->tx_frames_cnt == 0) && 969f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov (wl1271_tx_total_queue_count(wl) == 0)) { 970781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 971781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen return; 972781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 973781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen mutex_unlock(&wl->mutex); 974781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen msleep(1); 975781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen } 976781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen 977781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen wl1271_warning("Unable to flush all TX buffers, timed out."); 978f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho} 979e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 980e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsovu32 wl1271_tx_min_rate_get(struct wl1271 *wl) 981e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{ 982e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov int i; 983e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov u32 rate = 0; 984e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 985e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if (!wl->basic_rate_set) { 986e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov WARN_ON(1); 987e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov wl->basic_rate_set = wl->conf.tx.basic_rate; 988e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 989e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 990e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov for (i = 0; !rate; i++) { 991e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov if ((wl->basic_rate_set >> i) & 0x1) 992e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov rate = 1 << i; 993e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov } 994e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov 995e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov return rate; 996e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov} 997