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>
278910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov#include <linux/spinlock.h>
28f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
29c31be25a7144ebc9b7a22128909bac7654d4c46bLuciano Coelho#include "wlcore.h"
300f4e31222a2c0b93f25a87effd2033cb78c7a79cLuciano Coelho#include "debug.h"
3100d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "io.h"
3200d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "ps.h"
3300d201001bd4e8a46e3d03c970abcb72256c368bShahar Levi#include "tx.h"
3456d4f8f685c073c7ed7203b78c57f5d893d65102Arik Nemtsov#include "event.h"
35b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov#include "hw_ops.h"
36f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
3700782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho/*
3800782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * TODO: this is here just for now, it must be removed when the data
3900782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho * operations are in place.
4000782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho */
4100782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho#include "../wl12xx/reg.h"
4200782136b4d6e2316e0a2a55f3b1fba160e9576eLuciano Coelho
43536129c8ad35de87ff2f864f205a54ac32bfebccEliad Pellerstatic int wl1271_set_default_wep_key(struct wl1271 *wl,
44536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller				      struct wl12xx_vif *wlvif, u8 id)
457f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov{
467f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	int ret;
47536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS);
487f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov
497f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	if (is_ap)
50c690ec816f9fa2ab2b6200c5b79b6933acca49a4Eliad Peller		ret = wl12xx_cmd_set_default_wep_key(wl, id,
51a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller						     wlvif->ap.bcast_hlid);
527f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	else
53154da67c7da14ffd8da292394f8cbc81cc5ea4e3Eliad Peller		ret = wl12xx_cmd_set_default_wep_key(wl, id, wlvif->sta.hlid);
547f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov
557f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	if (ret < 0)
567f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov		return ret;
577f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov
587f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	wl1271_debug(DEBUG_CRYPT, "default wep key idx: %d", (int)id);
597f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov	return 0;
607f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov}
617f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov
6225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yarivstatic int wl1271_alloc_tx_id(struct wl1271 *wl, struct sk_buff *skb)
63f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
6425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	int id;
6525eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv
6672b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov	id = find_first_zero_bit(wl->tx_frames_map, wl->num_tx_desc);
6772b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov	if (id >= wl->num_tx_desc)
6825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv		return -EBUSY;
6925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv
7025eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	__set_bit(id, wl->tx_frames_map);
7125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	wl->tx_frames[id] = skb;
7225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	wl->tx_frames_cnt++;
7325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	return id;
7425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv}
75f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
76872b345fbaef290f890d0bbd34b78ab50269980fArik Nemtsovvoid wl1271_free_tx_id(struct wl1271 *wl, int id)
7725eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv{
7825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	if (__test_and_clear_bit(id, wl->tx_frames_map)) {
7972b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov		if (unlikely(wl->tx_frames_cnt == wl->num_tx_desc))
80ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv			clear_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
81ef2e3004855e90d2919105e4a91d7df6ab9845a9Ido Yariv
8225eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv		wl->tx_frames[id] = NULL;
8325eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv		wl->tx_frames_cnt--;
8425eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	}
85f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
86872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl1271_free_tx_id);
87f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
8899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsovstatic void wl1271_tx_ap_update_inconnection_sta(struct wl1271 *wl,
89187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov						 struct wl12xx_vif *wlvif,
9099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov						 struct sk_buff *skb)
9199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov{
9299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	struct ieee80211_hdr *hdr;
9399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov
94187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	hdr = (struct ieee80211_hdr *)(skb->data +
95187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov				       sizeof(struct wl1271_tx_hw_descr));
96187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	if (!ieee80211_is_auth(hdr->frame_control))
97187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov		return;
98187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov
9999a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	/*
10099a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	 * add the station to the known list before transmitting the
10199a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	 * authentication response. this way it won't get de-authed by FW
10299a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	 * when transmitting too soon.
10399a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov	 */
104028e7243ac411c3aba7a754bcc775c2fbb0b3e5cEliad Peller	wl1271_acx_set_inconnection_sta(wl, wlvif, hdr->addr1);
105187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov
106187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	/*
107187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	 * ROC for 1 second on the AP channel for completing the connection.
108187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	 * Note the ROC will be continued by the update_sta_state callbacks
109187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	 * once the station reaches the associated state.
110187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	 */
111187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	wlcore_update_inconn_sta(wl, wlvif, NULL, true);
112187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	wlvif->pending_auth_reply_time = jiffies;
113187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	cancel_delayed_work(&wlvif->pending_auth_complete_work);
114187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov	ieee80211_queue_delayed_work(wl->hw,
115187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov				&wlvif->pending_auth_complete_work,
116187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov				msecs_to_jiffies(WLCORE_PEND_AUTH_ROC_TIMEOUT));
11799a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov}
11899a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov
119c7ffb902cca655e4d6bdda4156407008573bb214Eliad Pellerstatic void wl1271_tx_regulate_link(struct wl1271 *wl,
120c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller				    struct wl12xx_vif *wlvif,
121c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller				    u8 hlid)
122b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov{
12337c68ea6997aac2faf21b83c28eda3b1659c4d45Arik Nemtsov	bool fw_ps;
1249b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov	u8 tx_pkts;
125b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov
126c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller	if (WARN_ON(!test_bit(hlid, wlvif->links_map)))
127b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov		return;
128b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov
1295e74b3aa6ffd80128e3df605bf27d8a6a3c04997Eliad Peller	fw_ps = test_bit(hlid, &wl->ap_fw_ps_map);
1309b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov	tx_pkts = wl->links[hlid].allocated_pkts;
131b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov
132b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov	/*
133b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov	 * if in FW PS and there is enough data in FW we can put the link
134b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov	 * into high-level PS and clean out its TX queues.
1359a1009684df5295883ba2eb85066a23ed3c3f6a6Arik Nemtsov	 * Make an exception if this is the only connected link. In this
1369a1009684df5295883ba2eb85066a23ed3c3f6a6Arik Nemtsov	 * case FW-memory congestion is less of a problem.
13741ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller	 * Note that a single connected STA means 2*ap_count + 1 active links,
13841ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller	 * since we must account for the global and broadcast AP links
13941ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller	 * for each AP. The "fw_ps" check assures us the other link is a STA
14041ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller	 * connected to the AP. Otherwise the FW would not set the PSM bit.
141b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov	 */
14241ed1a787c4940d58d5870c633ab6291dd4679ddEliad Peller	if (wl->active_link_count > (wl->ap_count*2 + 1) && fw_ps &&
14337c68ea6997aac2faf21b83c28eda3b1659c4d45Arik Nemtsov	    tx_pkts >= WL1271_PS_STA_MAX_PACKETS)
1446e8cd3310491b10db20d0f7eaf5713b05fa7b753Eliad Peller		wl12xx_ps_link_start(wl, wlvif, hlid, true);
145b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov}
146b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov
147f8e0af6b8732b47c2531a280753d29a4ca2d114bArik Nemtsovbool wl12xx_is_dummy_packet(struct wl1271 *wl, struct sk_buff *skb)
148f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{
149f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller	return wl->dummy_packet == skb;
150f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller}
151872b345fbaef290f890d0bbd34b78ab50269980fArik NemtsovEXPORT_SYMBOL(wl12xx_is_dummy_packet);
152f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller
1532b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsovstatic u8 wl12xx_tx_get_hlid_ap(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1542b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov				struct sk_buff *skb, struct ieee80211_sta *sta)
155a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{
1562b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov	if (sta) {
157a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		struct wl1271_station *wl_sta;
158a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
1592b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov		wl_sta = (struct wl1271_station *)sta->drv_priv;
160a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		return wl_sta->hlid;
161a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	} else {
162a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		struct ieee80211_hdr *hdr;
163a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
16453d40d0b863e22b697f8d85e1f95cb6f9d2d95b1Eliad Peller		if (!test_bit(WLVIF_FLAG_AP_STARTED, &wlvif->flags))
165f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller			return wl->system_hlid;
166f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller
167a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		hdr = (struct ieee80211_hdr *)skb->data;
16845b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller		if (is_multicast_ether_addr(ieee80211_get_DA(hdr)))
169a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller			return wlvif->ap.bcast_hlid;
17045b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller		else
17145b60f7ddd05e38a6835fb93e8dbcc6ef9bf12faEliad Peller			return wlvif->ap.global_hlid;
172a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	}
173a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov}
174a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
175d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pelleru8 wl12xx_tx_get_hlid(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1762b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov		      struct sk_buff *skb, struct ieee80211_sta *sta)
177f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller{
178dabf37dba405565ab46f4d1821c781730285b9edEliad Peller	struct ieee80211_tx_info *control;
179dabf37dba405565ab46f4d1821c781730285b9edEliad Peller
180536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	if (wlvif->bss_type == BSS_TYPE_AP_BSS)
1812b2b64380785bdcaaa9a123e7e5829acc749c4caArik Nemtsov		return wl12xx_tx_get_hlid_ap(wl, wlvif, skb, sta);
182f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller
183dabf37dba405565ab46f4d1821c781730285b9edEliad Peller	control = IEEE80211_SKB_CB(skb);
184dabf37dba405565ab46f4d1821c781730285b9edEliad Peller	if (control->flags & IEEE80211_TX_CTL_TX_OFFCHAN) {
185dabf37dba405565ab46f4d1821c781730285b9edEliad Peller		wl1271_debug(DEBUG_TX, "tx offchannel");
186dabf37dba405565ab46f4d1821c781730285b9edEliad Peller		return wlvif->dev_hlid;
187dabf37dba405565ab46f4d1821c781730285b9edEliad Peller	}
188dabf37dba405565ab46f4d1821c781730285b9edEliad Peller
1893230f35e09f386ee604f55450dcd26098a3c4bc3Eliad Peller	return wlvif->sta.hlid;
190f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller}
191f4df1bd525e027aa1975e00f87a420aec7bef4e0Eliad Peller
192b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsovunsigned int wlcore_calc_packet_alignment(struct wl1271 *wl,
193b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov					  unsigned int packet_length)
1940da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv{
1959fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis	if ((wl->quirks & WLCORE_QUIRK_TX_PAD_LAST_FRAME) ||
1969fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis	    !(wl->quirks & WLCORE_QUIRK_TX_BLOCKSIZE_ALIGN))
197f83985bb5f8f0f25d44ab7b108a709a52aa1c5e0Arik Nemtsov		return ALIGN(packet_length, WL1271_TX_ALIGN_TO);
1989fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis	else
1999fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis		return ALIGN(packet_length, WL12XX_BUS_BLOCK_SIZE);
2000da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv}
201b3b4b4b812018a06221b6d7b88a5540fccae2940Arik NemtsovEXPORT_SYMBOL(wlcore_calc_packet_alignment);
2020da13da767cd568c1fe2a7b5b936e86e521b5ae7Ido Yariv
203a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_tx_allocate(struct wl1271 *wl, struct wl12xx_vif *wlvif,
204536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller			      struct sk_buff *skb, u32 extra, u32 buf_offset,
20532bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov			      u8 hlid, bool is_gem)
206f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
207f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_tx_hw_descr *desc;
208f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 total_len = skb->len + sizeof(struct wl1271_tx_hw_descr) + extra;
2095c9417f1656b0f415f4be5a7cd7195ecadd7dd1aJuuso Oikarinen	u32 total_blocks;
210742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	int id, ret = -EBUSY, ac;
21132bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov	u32 spare_blocks;
212f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
21326a309c7586140afd40628a7031993afbaae0f07Igal Chernobelsky	if (buf_offset + total_len > wl->aggr_buf_size)
2146c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv		return -EAGAIN;
215a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv
21632bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov	spare_blocks = wlcore_hw_get_spare_blocks(wl, is_gem);
21732bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov
218f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* allocate free identifier for the packet */
21925eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	id = wl1271_alloc_tx_id(wl, skb);
220f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (id < 0)
221f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return id;
222f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
223b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov	total_blocks = wlcore_hw_calc_tx_blocks(wl, total_len, spare_blocks);
22448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi
225f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (total_blocks <= wl->tx_blocks_available) {
226f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		desc = (struct wl1271_tx_hw_descr *)skb_push(
227f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			skb, total_len - skb->len);
228f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
2294a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov		wlcore_hw_set_tx_desc_blocks(wl, desc, total_blocks,
2304a3b97eea216135cd37e6d3a4a6c551c201a6615Arik Nemtsov					     spare_blocks);
231ae77eccf04f8c36769bdba334e1bbcc7bb9d3644Shahar Levi
232f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		desc->id = id;
233f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
234f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl->tx_blocks_available -= total_blocks;
2357bb5d6ce9e6ebb3bb71915cb0224523d3c284b4fArik Nemtsov		wl->tx_allocated_blocks += total_blocks;
236f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
2379be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		/*
2389be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		 * If the FW was empty before, arm the Tx watchdog. Also do
2399be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		 * this on the first Tx after resume, as we always cancel the
2409be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		 * watchdog on suspend.
2419be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		 */
2429be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		if (wl->tx_allocated_blocks == total_blocks ||
2439be86cf067f43c3a43a538189d773afc812e4017Arik Nemtsov		    test_and_clear_bit(WL1271_FLAG_REINIT_TX_WDOG, &wl->flags))
24455df5afb13718cda49128fa5985556df91d07765Arik Nemtsov			wl12xx_rearm_tx_watchdog_locked(wl);
24555df5afb13718cda49128fa5985556df91d07765Arik Nemtsov
246742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov		ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
247742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov		wl->tx_allocated_pkts[ac]++;
248bf54e301671a6ece6c94550294dc7faf14158cd3Arik Nemtsov
2499ebcb232158c737db21e22b7bfdc4fc6d661ea8cArik Nemtsov		if (test_bit(hlid, wl->links_map))
2509b17f1b371c5aa5179b3e5392bc22132a3371da4Arik Nemtsov			wl->links[hlid].allocated_pkts++;
25109039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov
252f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		ret = 0;
253f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
254f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_debug(DEBUG_TX,
255f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			     "tx_allocate: size: %d, blocks: %d, id: %d",
256f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			     total_len, total_blocks, id);
257781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen	} else {
25825eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv		wl1271_free_tx_id(wl, id);
259781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen	}
260f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
261f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	return ret;
262f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
263f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
264a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic void wl1271_tx_fill_hdr(struct wl1271 *wl, struct wl12xx_vif *wlvif,
265536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller			       struct sk_buff *skb, u32 extra,
266536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller			       struct ieee80211_tx_info *control, u8 hlid)
267f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
268ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen	struct timespec ts;
269f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct wl1271_tx_hw_descr *desc;
2706f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov	int ac, rate_idx;
271ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen	s64 hosttime;
272cf00f379d82d170712150588accd2ebe316c2226John W. Linville	u16 tx_attr = 0;
273f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	__le16 frame_control;
274f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	struct ieee80211_hdr *hdr;
275f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	u8 *frame_start;
276a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	bool is_dummy;
277f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
278f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	desc = (struct wl1271_tx_hw_descr *) skb->data;
279f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	frame_start = (u8 *)(desc + 1);
280f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	hdr = (struct ieee80211_hdr *)(frame_start + extra);
281f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	frame_control = hdr->frame_control;
282f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
2831e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	/* relocate space for security header */
2841e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	if (extra) {
285f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller		int hdrlen = ieee80211_hdrlen(frame_control);
286f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller		memmove(frame_start, hdr, hdrlen);
2872fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov		skb_set_network_header(skb, skb_network_offset(skb) + extra);
2881e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	}
2891e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen
290f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* configure packet life time */
291ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen	getnstimeofday(&ts);
292ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen	hosttime = (timespec_to_ns(&ts) >> 10);
293ac5e1e39c1eeaaff7e6f03bf7cf7a444b42fbc23Juuso Oikarinen	desc->start_time = cpu_to_le32(hosttime - wl->time_offset);
294c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov
295a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	is_dummy = wl12xx_is_dummy_packet(wl, skb);
2960f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller	if (is_dummy || !wlvif || wlvif->bss_type != BSS_TYPE_AP_BSS)
297c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov		desc->life_time = cpu_to_le16(TX_HW_MGMT_PKT_LIFETIME_TU);
298c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov	else
299c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov		desc->life_time = cpu_to_le16(TX_HW_AP_MODE_PKT_LIFETIME_TU);
300f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
301db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller	/* queue */
302c6999d831ab9ae5e368b20f3bc11b0ca9c17a7ecKalle Valo	ac = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
303db674d249c1fa20fd6731048f41646b3a2e8bdf5Eliad Peller	desc->tid = skb->priority;
304c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov
305a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	if (is_dummy) {
306ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		/*
307ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		 * FW expects the dummy packet to have an invalid session id -
308ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		 * any session id that is different than the one set in the join
309ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		 */
31098b8625301e55bd3e4340f704edc378e4707e577Eliad Peller		tx_attr = (SESSION_COUNTER_INVALID <<
311ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			   TX_HW_ATTR_OFST_SESSION_COUNTER) &
312ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			   TX_HW_ATTR_SESSION_COUNTER;
313ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi
314ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		tx_attr |= TX_HW_ATTR_TX_DUMMY_REQ;
3150f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller	} else if (wlvif) {
3163ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov		u8 session_id = wl->session_ids[hlid];
3173ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov
3183ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov		if ((wl->quirks & WLCORE_QUIRK_AP_ZERO_SESSION_ID) &&
3193ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov		    (wlvif->bss_type == BSS_TYPE_AP_BSS))
3203ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov			session_id = 0;
3213ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov
322ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		/* configure the tx attributes */
3233ea186d137f79da5e6af283e5803715da1eb6259Arik Nemtsov		tx_attr = session_id << TX_HW_ATTR_OFST_SESSION_COUNTER;
324ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi	}
325ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi
32679b122dc51797b650201f21360481a0450e9b7e4Eliad Peller	desc->hlid = hlid;
3270f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller	if (is_dummy || !wlvif)
328a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller		rate_idx = 0;
329a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	else if (wlvif->bss_type != BSS_TYPE_AP_BSS) {
3308f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira		/*
3314340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller		 * if the packets are data packets
3328f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira		 * send them with AP rate policies (EAPOLs are an exception),
3338f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira		 * otherwise use default basic rates
3348f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira		 */
335bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky		if (skb->protocol == cpu_to_be16(ETH_P_PAE))
3368f1a8684a56b3640510c0610b5635f5a4fe366fdEyal Shapira			rate_idx = wlvif->sta.basic_rate_idx;
337bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky		else if (control->flags & IEEE80211_TX_CTL_NO_CCK_RATE)
338bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky			rate_idx = wlvif->sta.p2p_rate_idx;
3394340d1cf5f1a967074f5dabec09a06fc0ae52ac7Eliad Peller		else if (ieee80211_is_data(frame_control))
340e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller			rate_idx = wlvif->sta.ap_rate_idx;
341c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov		else
342e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller			rate_idx = wlvif->sta.basic_rate_idx;
343c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov	} else {
344a8ab39a4b588e8523be2fa75671bdc9612d3467aEliad Peller		if (hlid == wlvif->ap.global_hlid)
345e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller			rate_idx = wlvif->ap.mgmt_rate_idx;
346bed483f7b4c71d557777ee30d8dc46cbd5967fa6Igal Chernobelsky		else if (hlid == wlvif->ap.bcast_hlid ||
347c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			 skb->protocol == cpu_to_be16(ETH_P_PAE) ||
348c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			 !ieee80211_is_data(frame_control))
349c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			/*
350c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			 * send non-data, bcast and EAPOLs using the
351c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			 * min basic rate
352c3e06fc03b64c626e150c33b897ddd728c30a316Arik Nemtsov			 */
353e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller			rate_idx = wlvif->ap.bcast_rate_idx;
354e51ae9be2e313b63a43f1f93578d9a71d38a77eaArik Nemtsov		else
355e5a359f873f50cc123d5ca97637caa30fa095bb9Eliad Peller			rate_idx = wlvif->ap.ucast_rate_idx[ac];
356c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov	}
357c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov
358c6c8a65de6d3aa8daa93beeac390f49a21d0be36Arik Nemtsov	tx_attr |= rate_idx << TX_HW_ATTR_OFST_RATE_POLICY;
359d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho
360f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	/* for WEP shared auth - no fw encryption is needed */
361f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	if (ieee80211_is_auth(frame_control) &&
362f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller	    ieee80211_has_protected(frame_control))
363f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller		tx_attr |= TX_HW_ATTR_HOST_ENCRYPT;
364f4f57943f265d80fe5f0fedf6964f8056e753cf3Eliad Peller
3652a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky	/* send EAPOL frames as voice */
3662a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky	if (control->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)
3672a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky		tx_attr |= TX_HW_ATTR_EAPOL_FRAME;
3682a5ad92e271e518281504eeeab1dd311351ff7b7Igal Chernobelsky
369d0f63b202146f3281800ee44823740c8bbf38f11Luciano Coelho	desc->tx_attr = cpu_to_le16(tx_attr);
3706f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov
3712fc28de5989e1c40fee4e92e2a8f3bdd47b1b34aArik Nemtsov	wlcore_hw_set_tx_desc_csum(wl, desc, skb);
3726f266e912c0733e77f63e9ad245db3c966b75942Arik Nemtsov	wlcore_hw_set_tx_desc_data_len(wl, desc, skb);
373f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
374f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
375f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* caller must hold wl->mutex */
376a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Pellerstatic int wl1271_prepare_tx_frame(struct wl1271 *wl, struct wl12xx_vif *wlvif,
377930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov				   struct sk_buff *skb, u32 buf_offset, u8 hlid)
378f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
379f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct ieee80211_tx_info *info;
380f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 extra = 0;
381f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int ret = 0;
382a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	u32 total_len;
383536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	bool is_dummy;
38432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov	bool is_gem = false;
385f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
3867a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira	if (!skb) {
3877a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira		wl1271_error("discarding null skb");
388f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return -EINVAL;
3897a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira	}
390f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
391930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	if (hlid == WL12XX_INVALID_LINK_ID) {
392930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov		wl1271_error("invalid hlid. dropping skb 0x%p", skb);
393930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov		return -EINVAL;
394930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	}
395930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov
396f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	info = IEEE80211_SKB_CB(skb);
397f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
398536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	is_dummy = wl12xx_is_dummy_packet(wl, skb);
399536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller
4002c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
4012c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov	    info->control.hw_key &&
40297359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP)
4035ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller		extra = WL1271_EXTRA_SPACE_TKIP;
404f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
405f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (info->control.hw_key) {
4067f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov		bool is_wep;
4077f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov		u8 idx = info->control.hw_key->hw_key_idx;
4087f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov		u32 cipher = info->control.hw_key->cipher;
4097f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov
4107f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov		is_wep = (cipher == WLAN_CIPHER_SUITE_WEP40) ||
4117f179b468963564aa3faa5729fb3153c08b3d7c1Arik Nemtsov			 (cipher == WLAN_CIPHER_SUITE_WEP104);
412f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
413bf9d5d28aabc6e420a0b6fb3a24b93046878e864Victor Goldenshtein		if (WARN_ON(is_wep && wlvif && wlvif->default_key != idx)) {
414536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller			ret = wl1271_set_default_wep_key(wl, wlvif, idx);
415f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			if (ret < 0)
416f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho				return ret;
417f75c753f3c77b758fa5ace90c15b2ea3b7a3d46dEliad Peller			wlvif->default_key = idx;
418f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		}
41932bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov
42032bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov		is_gem = (cipher == WL1271_CIPHER_SUITE_GEM);
421f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
42209039f42a24084c10e7761ab28ef22932c62a46fArik Nemtsov
42332bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov	ret = wl1271_tx_allocate(wl, wlvif, skb, extra, buf_offset, hlid,
42432bb2c03f990d015c0fec67e9134ea8625aaf784Arik Nemtsov				 is_gem);
425f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	if (ret < 0)
426f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return ret;
427f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
428a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	wl1271_tx_fill_hdr(wl, wlvif, skb, extra, info, hlid);
429fae2fd767e9d380ed0d05e4a5d6b1673e2c2d3dfArik Nemtsov
4300f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller	if (!is_dummy && wlvif && wlvif->bss_type == BSS_TYPE_AP_BSS) {
431187e52cc3c9f5ee64136f8b5c4edcb4cf94693e7Arik Nemtsov		wl1271_tx_ap_update_inconnection_sta(wl, wlvif, skb);
432c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller		wl1271_tx_regulate_link(wl, wlvif, hlid);
433b622d992c21a85ce590afe2c18977ed28b457e0eArik Nemtsov	}
43499a2775d02a7accf4cc661a65c76fd7b379d1c7aArik Nemtsov
435a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	/*
43648a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * The length of each packet is stored in terms of
43748a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * words. Thus, we must pad the skb data to make sure its
43848a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * length is aligned.  The number of padding bytes is computed
43948a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * and set in wl1271_tx_fill_hdr.
44048a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * In special cases, we want to align to a specific block size
44148a61477bdc04896bd96d259388a0c42a7019943Shahar Levi	 * (eg. for wl128x with SDIO we align to 256).
442a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	 */
443b3b4b4b812018a06221b6d7b88a5540fccae2940Arik Nemtsov	total_len = wlcore_calc_packet_alignment(wl, skb->len);
44448a61477bdc04896bd96d259388a0c42a7019943Shahar Levi
445a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	memcpy(wl->aggr_buf + buf_offset, skb->data, skb->len);
446a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	memset(wl->aggr_buf + buf_offset + skb->len, 0, total_len - skb->len);
447f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
448990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	/* Revert side effects in the dummy packet skb, so it can be reused */
449536129c8ad35de87ff2f864f205a54ac32bfebccEliad Peller	if (is_dummy)
450990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
451990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv
452a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	return total_len;
453f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
454f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
455af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_enabled_rates_get(struct wl1271 *wl, u32 rate_set,
456af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller				enum ieee80211_band rate_band)
457830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen{
458830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	struct ieee80211_supported_band *band;
459830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	u32 enabled_rates = 0;
460830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	int bit;
461830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen
462af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller	band = wl->hw->wiphy->bands[rate_band];
463830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	for (bit = 0; bit < band->n_bitrates; bit++) {
464830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen		if (rate_set & 0x1)
465830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen			enabled_rates |= band->bitrates[bit].hw_value;
466830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen		rate_set >>= 1;
467830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	}
468830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen
469b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov	/* MCS rates indication are on bits 16 - 31 */
47018357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi	rate_set >>= HW_HT_RATES_OFFSET - band->n_bitrates;
47118357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi
472b3a47ee0ec07b16f68c38052e8cd1b5cb417bdcaArik Nemtsov	for (bit = 0; bit < 16; bit++) {
47318357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi		if (rate_set & 0x1)
47418357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi			enabled_rates |= (CONF_HW_BIT_RATE_MCS_0 << bit);
47518357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi		rate_set >>= 1;
47618357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi	}
47718357850b694ba3fa29363c7d86ccd8783f4a065Shahar Levi
478830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen	return enabled_rates;
479830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen}
480830fb67b8e37fb03cf703b4e1217fe30ce32d579Juuso Oikarinen
481a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_handle_tx_low_watermark(struct wl1271 *wl)
4822fe33e8cff354a3f320549544bffebbbab680145Ido Yariv{
483708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov	int i;
4841c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	struct wl12xx_vif *wlvif;
4852fe33e8cff354a3f320549544bffebbbab680145Ido Yariv
4861c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	wl12xx_for_each_wlvif(wl, wlvif) {
4871c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov		for (i = 0; i < NUM_TX_QUEUES; i++) {
4881c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov			if (wlcore_is_queue_stopped_by_reason(wl, wlvif, i,
4891c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov					WLCORE_QUEUE_STOP_REASON_WATERMARK) &&
4901c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov			    wlvif->tx_queue_count[i] <=
4911c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov					WL1271_TX_QUEUE_LOW_WATERMARK)
4921c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov				/* firmware buffer has space, restart queues */
4931c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov				wlcore_wake_queue(wl, wlvif, i,
4941c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov					WLCORE_QUEUE_STOP_REASON_WATERMARK);
495708bb3cf58a9bc90f3171ba64f30601f690e5aaaArik Nemtsov		}
4962fe33e8cff354a3f320549544bffebbbab680145Ido Yariv	}
4972fe33e8cff354a3f320549544bffebbbab680145Ido Yariv}
4982fe33e8cff354a3f320549544bffebbbab680145Ido Yariv
4990e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic int wlcore_select_ac(struct wl1271 *wl)
500742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov{
501742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	int i, q = -1, ac;
502742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	u32 min_pkts = 0xffffffff;
503742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov
504742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	/*
505742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 * Find a non-empty ac where:
506742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 * 1. There are packets to transmit
507742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 * 2. The FW has the least allocated blocks
508742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 *
509742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 * We prioritize the ACs according to VO>VI>BE>BK
510742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	 */
511742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	for (i = 0; i < NUM_TX_QUEUES; i++) {
512742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov		ac = wl1271_tx_get_queue(i);
5130e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		if (wl->tx_queue_count[ac] &&
5140e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		    wl->tx_allocated_pkts[ac] < min_pkts) {
515742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov			q = ac;
516742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov			min_pkts = wl->tx_allocated_pkts[q];
517742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov		}
518742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov	}
519742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov
5200e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	return q;
521742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov}
522742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov
5230e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_lnk_dequeue(struct wl1271 *wl,
5240e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov					  struct wl1271_link *lnk, u8 q)
5256742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{
526d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	struct sk_buff *skb;
5276742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	unsigned long flags;
5286742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen
5290e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	skb = skb_dequeue(&lnk->tx_queue[q]);
5306742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	if (skb) {
5316742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen		spin_lock_irqsave(&wl->wl_lock, flags);
5326246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov		WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
533f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		wl->tx_queue_count[q]--;
5348591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		if (lnk->wlvif) {
5358591d42452f16b1888419da4456142864b08ef9eArik Nemtsov			WARN_ON_ONCE(lnk->wlvif->tx_queue_count[q] <= 0);
5368591d42452f16b1888419da4456142864b08ef9eArik Nemtsov			lnk->wlvif->tx_queue_count[q]--;
5378591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		}
5386742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen		spin_unlock_irqrestore(&wl->wl_lock, flags);
5396742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	}
5406742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen
5416742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	return skb;
5426742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen}
5436742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen
5440e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_lnk_dequeue_high_prio(struct wl1271 *wl,
5450e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						    u8 hlid, u8 ac,
5460e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						    u8 *low_prio_hlid)
5470e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov{
5480e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	struct wl1271_link *lnk = &wl->links[hlid];
5490e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
550f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov	if (!wlcore_hw_lnk_high_prio(wl, hlid, lnk)) {
5510e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		if (*low_prio_hlid == WL12XX_INVALID_LINK_ID &&
552f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov		    !skb_queue_empty(&lnk->tx_queue[ac]) &&
553f1626fd8983a5bc68ce2879865cce297eb96c0b4Arik Nemtsov		    wlcore_hw_lnk_low_prio(wl, hlid, lnk))
5540e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			/* we found the first non-empty low priority queue */
5550e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			*low_prio_hlid = hlid;
5560e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
5570e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		return NULL;
5580e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	}
5590e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
5600e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	return wlcore_lnk_dequeue(wl, lnk, ac);
5610e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov}
5620e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
5630e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovstatic struct sk_buff *wlcore_vif_dequeue_high_prio(struct wl1271 *wl,
5640e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						    struct wl12xx_vif *wlvif,
5650e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						    u8 ac, u8 *hlid,
5660e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						    u8 *low_prio_hlid)
567a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{
568a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	struct sk_buff *skb = NULL;
569a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	int i, h, start_hlid;
570a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
571a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	/* start from the link after the last one */
572da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller	start_hlid = (wlvif->last_tx_hlid + 1) % wl->num_links;
573a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
574a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	/* dequeue according to AC, round robin on each link */
575da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller	for (i = 0; i < wl->num_links; i++) {
576da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller		h = (start_hlid + i) % wl->num_links;
577a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
578742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov		/* only consider connected stations */
579c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller		if (!test_bit(h, wlvif->links_map))
580742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov			continue;
581742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov
5820e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		skb = wlcore_lnk_dequeue_high_prio(wl, h, ac,
5830e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						   low_prio_hlid);
584d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller		if (!skb)
585742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov			continue;
586742246f8bc16c3a1a556c68ca2fabca162d14c24Arik Nemtsov
587d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller		wlvif->last_tx_hlid = h;
588d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller		break;
589a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	}
590a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
591d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	if (!skb)
5924438aca9e16901d8d32a025ca27ad8284a117e09Eliad Peller		wlvif->last_tx_hlid = 0;
593a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
594930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	*hlid = wlvif->last_tx_hlid;
595a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	return skb;
596a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov}
597a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
598930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsovstatic struct sk_buff *wl1271_skb_dequeue(struct wl1271 *wl, u8 *hlid)
599a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{
600990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	unsigned long flags;
601e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller	struct wl12xx_vif *wlvif = wl->last_wlvif;
602990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	struct sk_buff *skb = NULL;
6030e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	int ac;
6040e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	u8 low_prio_hlid = WL12XX_INVALID_LINK_ID;
6050e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6060e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	ac = wlcore_select_ac(wl);
6070e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	if (ac < 0)
6080e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		goto out;
609990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv
61049c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov	/* continue from last wlvif (round robin) */
611e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller	if (wlvif) {
612e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller		wl12xx_for_each_wlvif_continue(wl, wlvif) {
6130e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			if (!wlvif->tx_queue_count[ac])
6140e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov				continue;
6150e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6160e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
6170e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov							   &low_prio_hlid);
6180e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			if (!skb)
6190e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov				continue;
6200e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6210e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			wl->last_wlvif = wlvif;
6220e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			break;
623e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller		}
624e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller	}
625e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller
62649c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov	/* dequeue from the system HLID before the restarting wlvif list */
627930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	if (!skb) {
6280e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		skb = wlcore_lnk_dequeue_high_prio(wl, wl->system_hlid,
6290e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov						   ac, &low_prio_hlid);
6300e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		if (skb) {
6310e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			*hlid = wl->system_hlid;
6320e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			wl->last_wlvif = NULL;
6330e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		}
634930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	}
63549c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov
6360e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	/* Do a new pass over the wlvif list. But no need to continue
6370e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	 * after last_wlvif. The previous pass should have found it. */
638e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller	if (!skb) {
639e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller		wl12xx_for_each_wlvif(wl, wlvif) {
6400e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			if (!wlvif->tx_queue_count[ac])
6410e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov				goto next;
6420e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6430e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			skb = wlcore_vif_dequeue_high_prio(wl, wlvif, ac, hlid,
6440e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov							   &low_prio_hlid);
645e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller			if (skb) {
646e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller				wl->last_wlvif = wlvif;
647e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller				break;
648e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller			}
64949c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov
6500e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsovnext:
65149c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov			if (wlvif == wl->last_wlvif)
65249c9cd26445aa8bc8348c384c943b758c57c47a9Arik Nemtsov				break;
653e4120df982c2051f3cfc02f6278798c5166a72f8Eliad Peller		}
654a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	}
655a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller
6560e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	/* no high priority skbs found - but maybe a low priority one? */
6570e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	if (!skb && low_prio_hlid != WL12XX_INVALID_LINK_ID) {
6580e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		struct wl1271_link *lnk = &wl->links[low_prio_hlid];
6590e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		skb = wlcore_lnk_dequeue(wl, lnk, ac);
6600e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6610e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		WARN_ON(!skb); /* we checked this before */
6620e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		*hlid = low_prio_hlid;
6630e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6640e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		/* ensure proper round robin in the vif/link levels */
6650e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		wl->last_wlvif = lnk->wlvif;
6660e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov		if (lnk->wlvif)
6670e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov			lnk->wlvif->last_tx_hlid = low_prio_hlid;
6680e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
6690e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov	}
6700e81047996fdde7fc9e8a1c01d532df1f53586faArik Nemtsov
671abca1237820a7d9a087b2744a2abd1026364d7b7Arik Nemtsovout:
672990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	if (!skb &&
673990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	    test_and_clear_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags)) {
674f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		int q;
675f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov
676990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		skb = wl->dummy_packet;
677930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov		*hlid = wl->system_hlid;
678f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
679990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		spin_lock_irqsave(&wl->wl_lock, flags);
6806246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov		WARN_ON_ONCE(wl->tx_queue_count[q] <= 0);
681f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		wl->tx_queue_count[q]--;
682990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		spin_unlock_irqrestore(&wl->wl_lock, flags);
683990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	}
684990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv
685990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	return skb;
686a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov}
687a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
688d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellerstatic void wl1271_skb_queue_head(struct wl1271 *wl, struct wl12xx_vif *wlvif,
689930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov				  struct sk_buff *skb, u8 hlid)
6906742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen{
6916742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	unsigned long flags;
6926742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	int q = wl1271_tx_get_queue(skb_get_queue_mapping(skb));
6936742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen
694990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	if (wl12xx_is_dummy_packet(wl, skb)) {
695990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		set_bit(WL1271_FLAG_DUMMY_PACKET_PENDING, &wl->flags);
696d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	} else {
697a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		skb_queue_head(&wl->links[hlid].tx_queue[q], skb);
698a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
699a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		/* make sure we dequeue the same packet next time */
700da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller		wlvif->last_tx_hlid = (hlid + wl->num_links - 1) %
701da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller				      wl->num_links;
702a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	}
703a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
7046742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	spin_lock_irqsave(&wl->wl_lock, flags);
705f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov	wl->tx_queue_count[q]++;
7068591d42452f16b1888419da4456142864b08ef9eArik Nemtsov	if (wlvif)
7078591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		wlvif->tx_queue_count[q]++;
7086742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen	spin_unlock_irqrestore(&wl->wl_lock, flags);
7096742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen}
7106742f554db14da94172da9eb1875a1aa944a827fJuuso Oikarinen
71177ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Pellerstatic bool wl1271_tx_is_data_present(struct sk_buff *skb)
71277ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller{
71377ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
71477ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller
71577ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller	return ieee80211_is_data_present(hdr->frame_control);
71677ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller}
71777ddaa108f727b5ef3be004b952d2c3d3ffc48e5Eliad Peller
7189eb599e9c62dcfd4efece1936c385381b366b684Eliad Pellervoid wl12xx_rearm_rx_streaming(struct wl1271 *wl, unsigned long *active_hlids)
7199eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller{
7209eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	struct wl12xx_vif *wlvif;
7219eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	u32 timeout;
7229eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	u8 hlid;
7239eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7249eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	if (!wl->conf.rx_streaming.interval)
7259eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		return;
7269eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7279eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	if (!wl->conf.rx_streaming.always &&
7289eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	    !test_bit(WL1271_FLAG_SOFT_GEMINI, &wl->flags))
7299eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		return;
7309eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7319eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	timeout = wl->conf.rx_streaming.duration;
7329eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	wl12xx_for_each_wlvif_sta(wl, wlvif) {
7339eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		bool found = false;
734da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller		for_each_set_bit(hlid, active_hlids, wl->num_links) {
7359eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			if (test_bit(hlid, wlvif->links_map)) {
7369eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller				found  = true;
7379eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller				break;
7389eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			}
7399eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		}
7409eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7419eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		if (!found)
7429eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			continue;
7439eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7449eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		/* enable rx streaming */
7450744bdb60b51dce54553d5af9a6133f1fe419032Eliad Peller		if (!test_bit(WLVIF_FLAG_RX_STREAMING_STARTED, &wlvif->flags))
7469eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			ieee80211_queue_work(wl->hw,
7479eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller					     &wlvif->rx_streaming_enable_work);
7489eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7499eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		mod_timer(&wlvif->rx_streaming_timer,
7509eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			  jiffies + msecs_to_jiffies(timeout));
7519eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	}
7529eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller}
7539eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
7547a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira/*
7557a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * Returns failure values only in case of failed bus ops within this function.
7567a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * wl1271_prepare_tx_frame retvals won't be returned in order to avoid
7577a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * triggering recovery by higher layers when not necessary.
7587a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * In case a FW command fails within wl1271_prepare_tx_frame fails a recovery
7597a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * will be queued in wl1271_cmd_send. -EAGAIN/-EBUSY from prepare_tx_frame
7607a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * can occur and are legitimate so don't propagate. -EINVAL will emit a WARNING
7617a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * within prepare_tx_frame code but there's nothing we should do about those
7627a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira * as well.
7637a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira */
764eb96f841b9563ba34969be25615548635728faf5Ido Yarivint wlcore_tx_work_locked(struct wl1271 *wl)
765f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
766a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller	struct wl12xx_vif *wlvif;
767f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct sk_buff *skb;
7689eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	struct wl1271_tx_hw_descr *desc;
7699fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis	u32 buf_offset = 0, last_len = 0;
7706c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv	bool sent_packets = false;
771da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller	unsigned long active_hlids[BITS_TO_LONGS(WLCORE_MAX_LINKS)] = {0};
772eb96f841b9563ba34969be25615548635728faf5Ido Yariv	int ret = 0;
7737a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira	int bus_ret = 0;
774930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	u8 hlid;
775f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
7764cc533830b7e6b309e8b73196c410951fc2bed91Ido Yariv	if (unlikely(wl->state != WLCORE_STATE_ON))
7777a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira		return 0;
778f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
779930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov	while ((skb = wl1271_skb_dequeue(wl, &hlid))) {
7800f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller		struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
7819eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		bool has_data = false;
7829eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller
783a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller		wlvif = NULL;
784f4d02007cdd56c59bdb9362c699875cb2d02c0feArik Nemtsov		if (!wl12xx_is_dummy_packet(wl, skb))
7850f1680147ce2509383e053fa843020e0e9f3c6ceEliad Peller			wlvif = wl12xx_vif_to_data(info->control.vif);
786930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov		else
787930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov			hlid = wl->system_hlid;
788a32d0cdfcb7e5d41f210e13cbc78dc86a5a85a08Eliad Peller
7899eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		has_data = wlvif && wl1271_tx_is_data_present(skb);
790930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov		ret = wl1271_prepare_tx_frame(wl, wlvif, skb, buf_offset,
791930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov					      hlid);
7926c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv		if (ret == -EAGAIN) {
793a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv			/*
7946c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			 * Aggregation buffer is full.
7956c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			 * Flush buffer and try again.
7966c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			 */
797930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov			wl1271_skb_queue_head(wl, wlvif, skb, hlid);
7989fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis
7999fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis			buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset,
8009fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis							    last_len);
8017a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira			bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA,
8027a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira					     wl->aggr_buf, buf_offset, true);
8037a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira			if (bus_ret < 0)
804eb96f841b9563ba34969be25615548635728faf5Ido Yariv				goto out;
805eb96f841b9563ba34969be25615548635728faf5Ido Yariv
8066c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			sent_packets = true;
8076c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			buf_offset = 0;
8086c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			continue;
8096c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv		} else if (ret == -EBUSY) {
8106c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			/*
8116c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv			 * Firmware buffer is full.
812a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv			 * Queue back last skb, and stop aggregating.
813a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv			 */
814930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov			wl1271_skb_queue_head(wl, wlvif, skb, hlid);
815a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv			/* No work left, avoid scheduling redundant tx work */
816a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv			set_bit(WL1271_FLAG_FW_TX_BUSY, &wl->flags);
817ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen			goto out_ack;
818f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		} else if (ret < 0) {
8195de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller			if (wl12xx_is_dummy_packet(wl, skb))
8205de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller				/*
8215de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller				 * fw still expects dummy packet,
8225de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller				 * so re-enqueue it
8235de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller				 */
824930e1915e73dd12c5e3a0e6a5a4349bdb9ab0ab7Arik Nemtsov				wl1271_skb_queue_head(wl, wlvif, skb, hlid);
8255de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller			else
8265de8eef4fdd2044f6981ebf62330720bcdba8ee3Eliad Peller				ieee80211_free_txskb(wl->hw, skb);
827ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen			goto out_ack;
828f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		}
8299fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis		last_len = ret;
8309fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis		buf_offset += last_len;
831a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv		wl->tx_packets_count++;
8329eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		if (has_data) {
8339eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			desc = (struct wl1271_tx_hw_descr *) skb->data;
8349eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller			__set_bit(desc->hlid, active_hlids);
8359eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller		}
836f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
837f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
838ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinenout_ack:
839a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	if (buf_offset) {
8409fccc82e19db0d63741cd6c3d2a8829fc8854406Ido Reis		buf_offset = wlcore_hw_pre_pkt_send(wl, buf_offset, last_len);
8417a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira		bus_ret = wlcore_write_data(wl, REG_SLV_MEM_DATA, wl->aggr_buf,
8427a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira					     buf_offset, true);
8437a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira		if (bus_ret < 0)
844eb96f841b9563ba34969be25615548635728faf5Ido Yariv			goto out;
845eb96f841b9563ba34969be25615548635728faf5Ido Yariv
8466c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv		sent_packets = true;
8476c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv	}
8486c6e669ed6282788d6045397ce0f201edc400d9dIdo Yariv	if (sent_packets) {
849606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv		/*
850606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv		 * Interrupt the firmware with the new packets. This is only
851606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv		 * required for older hardware revisions
852606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv		 */
853b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv		if (wl->quirks & WLCORE_QUIRK_END_OF_TRANSACTION) {
8547a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira			bus_ret = wlcore_write32(wl, WL12XX_HOST_WR_ACCESS,
855b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv					     wl->tx_packets_count);
8567a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira			if (bus_ret < 0)
857b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv				goto out;
858b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv		}
859606ea9fa0b2c01ffafb6beae92ea8e2b1473520bIdo Yariv
860a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		wl1271_handle_tx_low_watermark(wl);
861a19606b4333ff34e9b2863f37c20fe86b42be14cIdo Yariv	}
8629eb599e9c62dcfd4efece1936c385381b366b684Eliad Peller	wl12xx_rearm_rx_streaming(wl, active_hlids);
863eb96f841b9563ba34969be25615548635728faf5Ido Yariv
864eb96f841b9563ba34969be25615548635728faf5Ido Yarivout:
8657a50bdfb81a6bff96100cd2a2c95f8b3cf05bc0cEyal Shapira	return bus_ret;
866a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv}
867f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
868a522550a283de31c7cfc30c7a129ce584e38c582Ido Yarivvoid wl1271_tx_work(struct work_struct *work)
869a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv{
870a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv	struct wl1271 *wl = container_of(work, struct wl1271, tx_work);
871c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller	int ret;
872a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv
873a522550a283de31c7cfc30c7a129ce584e38c582Ido Yariv	mutex_lock(&wl->mutex);
874c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller	ret = wl1271_ps_elp_wakeup(wl);
875c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller	if (ret < 0)
876c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller		goto out;
877c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller
878eb96f841b9563ba34969be25615548635728faf5Ido Yariv	ret = wlcore_tx_work_locked(wl);
879eb96f841b9563ba34969be25615548635728faf5Ido Yariv	if (ret < 0) {
880eb96f841b9563ba34969be25615548635728faf5Ido Yariv		wl12xx_queue_recovery_work(wl);
881eb96f841b9563ba34969be25615548635728faf5Ido Yariv		goto out;
882eb96f841b9563ba34969be25615548635728faf5Ido Yariv	}
883c1b193eb6557279d037ab18c00ab628c6c78847fEliad Peller
884c75bbcdb200e2815c855e42a4685d170858af306Eliad Peller	wl1271_ps_elp_sleep(wl);
885c1b193eb6557279d037ab18c00ab628c6c78847fEliad Pellerout:
886f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	mutex_unlock(&wl->mutex);
887f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
888f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
889d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchsstatic u8 wl1271_tx_get_rate_flags(u8 rate_class_index)
890d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs{
891defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs	u8 flags = 0;
892defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs
89343a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	/*
89443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 * TODO: use wl12xx constants when this code is moved to wl12xx, as
89543a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 * only it uses Tx-completion.
89643a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 */
89743a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	if (rate_class_index <= 8)
898defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs		flags |= IEEE80211_TX_RC_MCS;
89943a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov
90043a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	/*
90143a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 * TODO: use wl12xx constants when this code is moved to wl12xx, as
90243a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 * only it uses Tx-completion.
90343a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	 */
90443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov	if (rate_class_index == 0)
905defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs		flags |= IEEE80211_TX_RC_SHORT_GI;
90643a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov
907defe02c720d54fc9bda3e5e625be70adac347a61Pontus Fuchs	return flags;
908d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs}
909d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs
910f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelhostatic void wl1271_tx_complete_packet(struct wl1271 *wl,
911f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho				      struct wl1271_tx_hw_res_descr *result)
912f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
913f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct ieee80211_tx_info *info;
91448e93e402ad19f570bae323b07911bdf6562af8eEliad Peller	struct ieee80211_vif *vif;
91548e93e402ad19f570bae323b07911bdf6562af8eEliad Peller	struct wl12xx_vif *wlvif;
916f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	struct sk_buff *skb;
917f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int id = result->id;
91831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	int rate = -1;
919d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs	u8 rate_flags = 0;
92031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	u8 retries = 0;
921f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
922f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* check for id legality */
92372b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov	if (unlikely(id >= wl->num_tx_desc || wl->tx_frames[id] == NULL)) {
924f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TX result illegal id: %d", id);
925f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		return;
926f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
927f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
928f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	skb = wl->tx_frames[id];
929f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	info = IEEE80211_SKB_CB(skb);
930f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
931990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv	if (wl12xx_is_dummy_packet(wl, skb)) {
932ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		wl1271_free_tx_id(wl, id);
933ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		return;
934ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi	}
935ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi
93648e93e402ad19f570bae323b07911bdf6562af8eEliad Peller	/* info->control is valid as long as we don't update info->status */
93748e93e402ad19f570bae323b07911bdf6562af8eEliad Peller	vif = info->control.vif;
93848e93e402ad19f570bae323b07911bdf6562af8eEliad Peller	wlvif = wl12xx_vif_to_data(vif);
93948e93e402ad19f570bae323b07911bdf6562af8eEliad Peller
94031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	/* update the TX status info */
94131627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	if (result->status == TX_SUCCESS) {
94231627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen		if (!(info->flags & IEEE80211_TX_CTL_NO_ACK))
943f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho			info->flags |= IEEE80211_TX_STAT_ACK;
94443a8bc5a53c78b69b99824c9f38c333cea024c8aArik Nemtsov		rate = wlcore_rate_to_idx(wl, result->rate_class_index,
9451b92f15ee0e0f06222d4fd36dc36960d217243b3Eliad Peller					  wlvif->band);
946d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs		rate_flags = wl1271_tx_get_rate_flags(result->rate_class_index);
94731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen		retries = result->ack_failures;
94831627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	} else if (result->status == TX_RETRY_EXCEEDED) {
94931627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen		wl->stats.excessive_retries++;
95031627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen		retries = result->ack_failures;
951f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
952f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
95331627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	info->status.rates[0].idx = rate;
95431627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	info->status.rates[0].count = retries;
955d2e2d769e3d328ba7cbf08e8ed85e3f817915843Pontus Fuchs	info->status.rates[0].flags = rate_flags;
95631627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen	info->status.ack_signal = -1;
95731627dc59b4a87c4198b4245a7de1b8ccf4424faJuuso Oikarinen
958f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl->stats.retry_count += result->ack_failures;
959f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
9601e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	/* remove private header from packet */
9611e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
9621e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen
9631e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	/* remove TKIP header space if present */
9642c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov	if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
9652c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov	    info->control.hw_key &&
96697359d1235eaf634fe706c9faa6e40181cc95fb8Johannes Berg	    info->control.hw_key->cipher == WLAN_CIPHER_SUITE_TKIP) {
9671e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen		int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
9685ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller		memmove(skb->data + WL1271_EXTRA_SPACE_TKIP, skb->data,
9695ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller			hdrlen);
9705ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller		skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
9711e2b79761d551c545225e1fa6e7d144f7e804898Juuso Oikarinen	}
972f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
973f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	wl1271_debug(DEBUG_TX, "tx status id %u skb 0x%p failures %u rate 0x%x"
974f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		     " status 0x%x",
975f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		     result->id, skb, result->ack_failures,
976f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		     result->rate_class_index, result->status);
977f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
978f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* return the packet to the stack */
979a620865edf62ea2d024bbfe62162244473badfcbIdo Yariv	skb_queue_tail(&wl->deferred_tx_queue, skb);
98092ef8960aee2f840c6a54c968d40199843f015c0Eliad Peller	queue_work(wl->freezable_wq, &wl->netstack_work);
98125eeb9e3876a161e3afcc820c6cb72e13f9b7c7eIdo Yariv	wl1271_free_tx_id(wl, result->id);
982f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
983f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
984f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho/* Called upon reception of a TX complete interrupt */
985045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivint wlcore_tx_complete(struct wl1271 *wl)
986f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
9872c208890c6d4e16076c6664137703ec813e8fa6cJoe Perches	struct wl1271_acx_mem_map *memmap = wl->target_mem_map;
988ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen	u32 count, fw_counter;
989f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	u32 i;
990045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv	int ret;
991f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
992f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* read the tx results from the chipset */
993045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv	ret = wlcore_read(wl, le32_to_cpu(memmap->tx_result),
994045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv			  wl->tx_res_if, sizeof(*wl->tx_res_if), false);
995045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv	if (ret < 0)
996045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv		goto out;
997045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv
998ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen	fw_counter = le32_to_cpu(wl->tx_res_if->tx_result_fw_counter);
999ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen
1000ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen	/* write host counter to chipset (to ack) */
1001b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv	ret = wlcore_write32(wl, le32_to_cpu(memmap->tx_result) +
1002b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv			     offsetof(struct wl1271_tx_hw_res_if,
1003b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv				      tx_result_host_counter), fw_counter);
1004b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv	if (ret < 0)
1005b0f0ad39e3d2716fe9ca6e50ce4cda87eb409ee0Ido Yariv		goto out;
1006ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen
1007ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen	count = fw_counter - wl->tx_results_count;
100806f7bc7db79fabe6b2ec16eff0f59e4acc21eb72Juuso Oikarinen	wl1271_debug(DEBUG_TX, "tx_complete received, packets: %d", count);
1009f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1010f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* verify that the result buffer is not getting overrun */
1011ffb591cd0e32d817bdbd359dead3baa770b999f8Juuso Oikarinen	if (unlikely(count > TX_HW_RESULT_QUEUE_LEN))
1012f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_warning("TX result overflow from chipset: %d", count);
1013f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1014f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* process the results */
1015f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	for (i = 0; i < count; i++) {
1016f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		struct wl1271_tx_hw_res_descr *result;
1017f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		u8 offset = wl->tx_results_count & TX_HW_RESULT_QUEUE_LEN_MASK;
1018f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1019f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		/* process the packet */
1020f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		result =  &(wl->tx_res_if->tx_results_queue[offset]);
1021f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl1271_tx_complete_packet(wl, result);
1022f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1023f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho		wl->tx_results_count++;
1024f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1025045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv
1026045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yarivout:
1027045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido Yariv	return ret;
1028f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1029045b9b5f4172b2b21af0b9bf5e6dda51146d51a4Ido YarivEXPORT_SYMBOL(wlcore_tx_complete);
1030f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1031a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsovvoid wl1271_tx_reset_link_queues(struct wl1271 *wl, u8 hlid)
1032a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov{
1033a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	struct sk_buff *skb;
1034f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov	int i;
1035a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	unsigned long flags;
10361d36cd892c130a5a781acb282e083b94127f1c50Arik Nemtsov	struct ieee80211_tx_info *info;
1037f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov	int total[NUM_TX_QUEUES];
10388591d42452f16b1888419da4456142864b08ef9eArik Nemtsov	struct wl1271_link *lnk = &wl->links[hlid];
1039a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
1040a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	for (i = 0; i < NUM_TX_QUEUES; i++) {
1041f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		total[i] = 0;
10428591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		while ((skb = skb_dequeue(&lnk->tx_queue[i]))) {
1043a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov			wl1271_debug(DEBUG_TX, "link freeing skb 0x%p", skb);
104479ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov
104579ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov			if (!wl12xx_is_dummy_packet(wl, skb)) {
104679ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov				info = IEEE80211_SKB_CB(skb);
104779ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov				info->status.rates[0].idx = -1;
104879ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov				info->status.rates[0].count = 0;
104979ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov				ieee80211_tx_status_ni(wl->hw, skb);
105079ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov			}
105179ebec76be4e7c2ebed9fb0b9510d10d599ed63eArik Nemtsov
1052f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov			total[i]++;
1053a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov		}
1054a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	}
1055a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
1056a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
10578591d42452f16b1888419da4456142864b08ef9eArik Nemtsov	for (i = 0; i < NUM_TX_QUEUES; i++) {
1058f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		wl->tx_queue_count[i] -= total[i];
10598591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		if (lnk->wlvif)
10608591d42452f16b1888419da4456142864b08ef9eArik Nemtsov			lnk->wlvif->tx_queue_count[i] -= total[i];
10618591d42452f16b1888419da4456142864b08ef9eArik Nemtsov	}
1062a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
1063a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
1064a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov	wl1271_handle_tx_low_watermark(wl);
1065a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov}
1066a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
10677dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov/* caller must hold wl->mutex and TX must be stopped */
1068d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Pellervoid wl12xx_tx_reset_wlvif(struct wl1271 *wl, struct wl12xx_vif *wlvif)
1069f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho{
1070f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	int i;
1071f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho
1072f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	/* TX failure */
1073da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller	for_each_set_bit(i, wlvif->links_map, wl->num_links) {
10745a99610c99625ae86d76014da25659dff72e8792Arik Nemtsov		if (wlvif->bss_type == BSS_TYPE_AP_BSS &&
10755a99610c99625ae86d76014da25659dff72e8792Arik Nemtsov		    i != wlvif->ap.bcast_hlid && i != wlvif->ap.global_hlid) {
10766c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov			/* this calls wl12xx_free_link */
1077c7ffb902cca655e4d6bdda4156407008573bb214Eliad Peller			wl1271_free_sta(wl, wlvif, i);
10786c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov		} else {
10796c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov			u8 hlid = i;
10806c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov			wl12xx_free_link(wl, wlvif, &hlid);
10816c4c45346289ec1c8a6a204e2c81325a4cf96924Arik Nemtsov		}
1082f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho	}
1083d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	wlvif->last_tx_hlid = 0;
1084d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller
10858591d42452f16b1888419da4456142864b08ef9eArik Nemtsov	for (i = 0; i < NUM_TX_QUEUES; i++)
10868591d42452f16b1888419da4456142864b08ef9eArik Nemtsov		wlvif->tx_queue_count[i] = 0;
1087d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller}
1088d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller/* caller must hold wl->mutex and TX must be stopped */
10896639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wl12xx_tx_reset(struct wl1271 *wl)
1090d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller{
1091d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	int i;
1092d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	struct sk_buff *skb;
1093d6a3cc2ef962ad4392a2401cae513a18a6d35099Eliad Peller	struct ieee80211_tx_info *info;
1094a8c0ddb5ba2889e1e11a033ccbadfc600f236a91Arik Nemtsov
10956246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov	/* only reset the queues if something bad happened */
10964c145185175dcca660265d2fcdd4feffc0249f8eVictor Goldenshtein	if (wl1271_tx_total_queue_count(wl) != 0) {
1097da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller		for (i = 0; i < wl->num_links; i++)
10986246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov			wl1271_tx_reset_link_queues(wl, i);
10996246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov
11006246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov		for (i = 0; i < NUM_TX_QUEUES; i++)
11016246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov			wl->tx_queue_count[i] = 0;
11026246ca003f2560e30b9696757efc271284b809f6Arik Nemtsov	}
1103f1acea9a9d48174f982e14a7a488b208d39d825fArik Nemtsov
11042fe33e8cff354a3f320549544bffebbbab680145Ido Yariv	/*
11052fe33e8cff354a3f320549544bffebbbab680145Ido Yariv	 * Make sure the driver is at a consistent state, in case this
11062fe33e8cff354a3f320549544bffebbbab680145Ido Yariv	 * function is called from a context other than interface removal.
11077dece1c8e1044287287d44ac183a946333b55fc3Arik Nemtsov	 * This call will always wake the TX queues.
11082fe33e8cff354a3f320549544bffebbbab680145Ido Yariv	 */
11096639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	wl1271_handle_tx_low_watermark(wl);
11102fe33e8cff354a3f320549544bffebbbab680145Ido Yariv
111172b0624fa5b766133fd0be9099724324b1f0d70eArik Nemtsov	for (i = 0; i < wl->num_tx_desc; i++) {
111250e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv		if (wl->tx_frames[i] == NULL)
111350e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv			continue;
111450e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv
111550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv		skb = wl->tx_frames[i];
111650e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv		wl1271_free_tx_id(wl, i);
111750e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv		wl1271_debug(DEBUG_TX, "freeing skb 0x%p", skb);
111850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv
1119990f5de7384f9e5922e4c7c7572cbf4f29a9441eIdo Yariv		if (!wl12xx_is_dummy_packet(wl, skb)) {
1120ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			/*
1121ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			 * Remove private headers before passing the skb to
1122ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			 * mac80211
1123ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			 */
1124ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			info = IEEE80211_SKB_CB(skb);
1125ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			skb_pull(skb, sizeof(struct wl1271_tx_hw_descr));
11262c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov			if ((wl->quirks & WLCORE_QUIRK_TKIP_HEADER_SPACE) &&
11272c0133a437905591cdaa39cf65a3f7188d20a094Arik Nemtsov			    info->control.hw_key &&
1128ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			    info->control.hw_key->cipher ==
1129ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			    WLAN_CIPHER_SUITE_TKIP) {
1130ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi				int hdrlen = ieee80211_get_hdrlen_from_skb(skb);
11315ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller				memmove(skb->data + WL1271_EXTRA_SPACE_TKIP,
1132ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi					skb->data, hdrlen);
11335ec8a448e0e978103bc5ca7136084b5e2b36989eEliad Peller				skb_pull(skb, WL1271_EXTRA_SPACE_TKIP);
1134ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			}
113550e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv
1136ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			info->status.rates[0].idx = -1;
1137ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi			info->status.rates[0].count = 0;
113850e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv
1139c27d3accb6f06b0afedfe472dfe0c8e7d87ff0a6Eliad Peller			ieee80211_tx_status_ni(wl->hw, skb);
1140ae47c45fd02fdf88d57adc370e78e7a01e2bfcbcShahar Levi		}
114150e9f746f63c9b881f2ca4a35dbdfd34b1a8a215Ido Yariv	}
1142781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen}
1143781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen
1144781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen#define WL1271_TX_FLUSH_TIMEOUT 500000
1145781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen
1146781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen/* caller must *NOT* hold wl->mutex */
1147781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinenvoid wl1271_tx_flush(struct wl1271 *wl)
1148781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen{
1149958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov	unsigned long timeout, start_time;
115018aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov	int i;
1151958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov	start_time = jiffies;
1152958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov	timeout = start_time + usecs_to_jiffies(WL1271_TX_FLUSH_TIMEOUT);
1153781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen
11542c38849f4a247673c8203a569444042e32d82410Arik Nemtsov	/* only one flush should be in progress, for consistent queue state */
11552c38849f4a247673c8203a569444042e32d82410Arik Nemtsov	mutex_lock(&wl->flush_mutex);
11562c38849f4a247673c8203a569444042e32d82410Arik Nemtsov
1157f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov	mutex_lock(&wl->mutex);
1158f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov	if (wl->tx_frames_cnt == 0 && wl1271_tx_total_queue_count(wl) == 0) {
1159f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		mutex_unlock(&wl->mutex);
1160f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		goto out;
1161f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov	}
1162f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov
11632c38849f4a247673c8203a569444042e32d82410Arik Nemtsov	wlcore_stop_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
11642c38849f4a247673c8203a569444042e32d82410Arik Nemtsov
1165781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen	while (!time_after(jiffies, timeout)) {
1166958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov		wl1271_debug(DEBUG_MAC80211, "flushing tx buffer: %d %d",
1167f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov			     wl->tx_frames_cnt,
1168f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov			     wl1271_tx_total_queue_count(wl));
1169f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov
1170f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		/* force Tx and give the driver some time to flush data */
1171f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		mutex_unlock(&wl->mutex);
1172f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		if (wl1271_tx_total_queue_count(wl))
1173f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov			wl1271_tx_work(&wl->tx_work);
1174f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		msleep(20);
1175f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov		mutex_lock(&wl->mutex);
1176f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov
1177f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		if ((wl->tx_frames_cnt == 0) &&
1178f1a46384ad568f72c11edbe2a3ec284bf32f2dbdArik Nemtsov		    (wl1271_tx_total_queue_count(wl) == 0)) {
1179958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov			wl1271_debug(DEBUG_MAC80211, "tx flush took %d ms",
1180958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov				     jiffies_to_msecs(jiffies - start_time));
1181f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov			goto out_wake;
1182781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen		}
1183781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen	}
1184781608c41386b560b501404233fc43d8ef100c71Juuso Oikarinen
1185958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov	wl1271_warning("Unable to flush all TX buffers, "
1186958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov		       "timed out (timeout %d ms",
1187958e303abba61bad165a96e22e138c4763047df2Arik Nemtsov		       WL1271_TX_FLUSH_TIMEOUT / 1000);
118818aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov
118918aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov	/* forcibly flush all Tx buffers on our queues */
1190da08fdfaf09f161c923c9d2b7db2fba8cc9c457cEliad Peller	for (i = 0; i < wl->num_links; i++)
119118aa755b84715f36e2811734f95cb822bcacfd89Arik Nemtsov		wl1271_tx_reset_link_queues(wl, i);
11922c38849f4a247673c8203a569444042e32d82410Arik Nemtsov
1193f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsovout_wake:
11942c38849f4a247673c8203a569444042e32d82410Arik Nemtsov	wlcore_wake_queues(wl, WLCORE_QUEUE_STOP_REASON_FLUSH);
1195f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsov	mutex_unlock(&wl->mutex);
1196f83e54134a6d38437ddee0fda96692a6b0c33b0eArik Nemtsovout:
11972c38849f4a247673c8203a569444042e32d82410Arik Nemtsov	mutex_unlock(&wl->flush_mutex);
1198f5fc0f86b02afef1119b523623b4cde41475bc8cLuciano Coelho}
1199a1c597f2b22cdc228de3c58784b00e80b9b53e03Arik NemtsovEXPORT_SYMBOL_GPL(wl1271_tx_flush);
1200e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov
1201af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Pelleru32 wl1271_tx_min_rate_get(struct wl1271 *wl, u32 rate_set)
1202e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov{
1203af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller	if (WARN_ON(!rate_set))
1204af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller		return 0;
1205e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov
1206af7fbb28efff0c0d8fc0852ad6622e5437a7611eEliad Peller	return BIT(__ffs(rate_set));
1207e0fe371b74326a85029fe8720506e021fe73905aArik Nemtsov}
120878e28062fea51c62280cd17fe6143ed583f83ba0Eliad PellerEXPORT_SYMBOL_GPL(wl1271_tx_min_rate_get);
12096639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12101c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_stop_queue_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
12111c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov			      u8 queue, enum wlcore_queue_stop_reason reason)
12126639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
12131c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
12141c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	bool stopped = !!wl->queue_stop_reasons[hwq];
12156639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12166639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	/* queue should not be stopped for this reason */
12171c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	WARN_ON_ONCE(test_and_set_bit(reason, &wl->queue_stop_reasons[hwq]));
12186639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12196639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	if (stopped)
12206639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov		return;
12216639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12221c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	ieee80211_stop_queue(wl->hw, hwq);
12236639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
12246639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12251c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_stop_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
12266639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov		       enum wlcore_queue_stop_reason reason)
12276639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
12286639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	unsigned long flags;
12296639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12306639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
12311c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	wlcore_stop_queue_locked(wl, wlvif, queue, reason);
12326639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
12336639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
12346639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12351c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_wake_queue(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 queue,
12366639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov		       enum wlcore_queue_stop_reason reason)
12376639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
12386639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	unsigned long flags;
12391c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
12406639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12416639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
12426639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12436639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	/* queue should not be clear for this reason */
12441c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	WARN_ON_ONCE(!test_and_clear_bit(reason, &wl->queue_stop_reasons[hwq]));
12456639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12461c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	if (wl->queue_stop_reasons[hwq])
12476639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov		goto out;
12486639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12491c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	ieee80211_wake_queue(wl->hw, hwq);
12506639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12516639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovout:
12526639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
12536639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
12546639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12556639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsovvoid wlcore_stop_queues(struct wl1271 *wl,
12566639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov			enum wlcore_queue_stop_reason reason)
12576639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
12586639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	int i;
12591c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	unsigned long flags;
12606639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12611c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
12626639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12631c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	/* mark all possible queues as stopped */
12641c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov        for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
12651c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov                WARN_ON_ONCE(test_and_set_bit(reason,
12661c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov					      &wl->queue_stop_reasons[i]));
12676639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12681c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	/* use the global version to make sure all vifs in mac80211 we don't
12691c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	 * know are stopped.
12701c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	 */
12711c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	ieee80211_stop_queues(wl->hw);
12721c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov
12731c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
12746639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
12756639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12761c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovvoid wlcore_wake_queues(struct wl1271 *wl,
12771c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov			enum wlcore_queue_stop_reason reason)
12786639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
12796639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	int i;
12806639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	unsigned long flags;
12816639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12826639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
12836639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12841c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	/* mark all possible queues as awake */
12851c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov        for (i = 0; i < WLCORE_NUM_MAC_ADDRESSES * NUM_TX_QUEUES; i++)
12861c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov		WARN_ON_ONCE(!test_and_clear_bit(reason,
12871c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov						 &wl->queue_stop_reasons[i]));
12886639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12891c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	/* use the global version to make sure all vifs in mac80211 we don't
12901c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	 * know are woken up.
12911c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	 */
12921c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	ieee80211_wake_queues(wl->hw);
12936639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12946639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
12956639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
12966639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
12971c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsovbool wlcore_is_queue_stopped_by_reason(struct wl1271 *wl,
12981c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov				       struct wl12xx_vif *wlvif, u8 queue,
12991c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov				       enum wlcore_queue_stop_reason reason)
13006639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
1301d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	unsigned long flags;
1302d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	bool stopped;
1303d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov
1304d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	spin_lock_irqsave(&wl->wl_lock, flags);
1305d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	stopped = wlcore_is_queue_stopped_by_reason_locked(wl, wlvif, queue,
1306d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov							   reason);
1307d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	spin_unlock_irqrestore(&wl->wl_lock, flags);
1308d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov
1309d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov	return stopped;
1310d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov}
1311d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov
1312d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsovbool wlcore_is_queue_stopped_by_reason_locked(struct wl1271 *wl,
1313d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov				       struct wl12xx_vif *wlvif, u8 queue,
1314d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov				       enum wlcore_queue_stop_reason reason)
1315d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov{
13161c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
1317d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov
13188910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov	assert_spin_locked(&wl->wl_lock);
13191c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	return test_bit(reason, &wl->queue_stop_reasons[hwq]);
13206639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
13216639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov
1322d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsovbool wlcore_is_queue_stopped_locked(struct wl1271 *wl, struct wl12xx_vif *wlvif,
1323d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov				    u8 queue)
13246639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov{
13251c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	int hwq = wlcore_tx_get_mac80211_queue(wlvif, queue);
1326d6037d22f30738e942ddfd29e3fef17deb075420Arik Nemtsov
13278910cfa3ac022feebfe1c4ae021afc34a1c1af25Arik Nemtsov	assert_spin_locked(&wl->wl_lock);
13281c33db782d1d0d9be83feacbb065cd4956f485e7Arik Nemtsov	return !!wl->queue_stop_reasons[hwq];
13296639611467f34038aa63c5cb9f8d9e48171d6022Arik Nemtsov}
1330