162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci	Copyright (C) 2010 Willow Garage <http://www.willowgarage.com>
462306a36Sopenharmony_ci	Copyright (C) 2004 - 2010 Ivo van Doorn <IvDoorn@gmail.com>
562306a36Sopenharmony_ci	Copyright (C) 2004 - 2009 Gertjan van Wingerde <gwingerde@gmail.com>
662306a36Sopenharmony_ci	<http://rt2x00.serialmonkey.com>
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci */
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci/*
1162306a36Sopenharmony_ci	Module: rt2x00lib
1262306a36Sopenharmony_ci	Abstract: rt2x00 queue specific routines.
1362306a36Sopenharmony_ci */
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/kernel.h>
1762306a36Sopenharmony_ci#include <linux/module.h>
1862306a36Sopenharmony_ci#include <linux/dma-mapping.h>
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci#include "rt2x00.h"
2162306a36Sopenharmony_ci#include "rt2x00lib.h"
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistruct sk_buff *rt2x00queue_alloc_rxskb(struct queue_entry *entry, gfp_t gfp)
2462306a36Sopenharmony_ci{
2562306a36Sopenharmony_ci	struct data_queue *queue = entry->queue;
2662306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = queue->rt2x00dev;
2762306a36Sopenharmony_ci	struct sk_buff *skb;
2862306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc;
2962306a36Sopenharmony_ci	unsigned int frame_size;
3062306a36Sopenharmony_ci	unsigned int head_size = 0;
3162306a36Sopenharmony_ci	unsigned int tail_size = 0;
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	/*
3462306a36Sopenharmony_ci	 * The frame size includes descriptor size, because the
3562306a36Sopenharmony_ci	 * hardware directly receive the frame into the skbuffer.
3662306a36Sopenharmony_ci	 */
3762306a36Sopenharmony_ci	frame_size = queue->data_size + queue->desc_size + queue->winfo_size;
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci	/*
4062306a36Sopenharmony_ci	 * The payload should be aligned to a 4-byte boundary,
4162306a36Sopenharmony_ci	 * this means we need at least 3 bytes for moving the frame
4262306a36Sopenharmony_ci	 * into the correct offset.
4362306a36Sopenharmony_ci	 */
4462306a36Sopenharmony_ci	head_size = 4;
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	/*
4762306a36Sopenharmony_ci	 * For IV/EIV/ICV assembly we must make sure there is
4862306a36Sopenharmony_ci	 * at least 8 bytes bytes available in headroom for IV/EIV
4962306a36Sopenharmony_ci	 * and 8 bytes for ICV data as tailroon.
5062306a36Sopenharmony_ci	 */
5162306a36Sopenharmony_ci	if (rt2x00_has_cap_hw_crypto(rt2x00dev)) {
5262306a36Sopenharmony_ci		head_size += 8;
5362306a36Sopenharmony_ci		tail_size += 8;
5462306a36Sopenharmony_ci	}
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci	/*
5762306a36Sopenharmony_ci	 * Allocate skbuffer.
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci	skb = __dev_alloc_skb(frame_size + head_size + tail_size, gfp);
6062306a36Sopenharmony_ci	if (!skb)
6162306a36Sopenharmony_ci		return NULL;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/*
6462306a36Sopenharmony_ci	 * Make sure we not have a frame with the requested bytes
6562306a36Sopenharmony_ci	 * available in the head and tail.
6662306a36Sopenharmony_ci	 */
6762306a36Sopenharmony_ci	skb_reserve(skb, head_size);
6862306a36Sopenharmony_ci	skb_put(skb, frame_size);
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	/*
7162306a36Sopenharmony_ci	 * Populate skbdesc.
7262306a36Sopenharmony_ci	 */
7362306a36Sopenharmony_ci	skbdesc = get_skb_frame_desc(skb);
7462306a36Sopenharmony_ci	memset(skbdesc, 0, sizeof(*skbdesc));
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA)) {
7762306a36Sopenharmony_ci		dma_addr_t skb_dma;
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci		skb_dma = dma_map_single(rt2x00dev->dev, skb->data, skb->len,
8062306a36Sopenharmony_ci					 DMA_FROM_DEVICE);
8162306a36Sopenharmony_ci		if (unlikely(dma_mapping_error(rt2x00dev->dev, skb_dma))) {
8262306a36Sopenharmony_ci			dev_kfree_skb_any(skb);
8362306a36Sopenharmony_ci			return NULL;
8462306a36Sopenharmony_ci		}
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci		skbdesc->skb_dma = skb_dma;
8762306a36Sopenharmony_ci		skbdesc->flags |= SKBDESC_DMA_MAPPED_RX;
8862306a36Sopenharmony_ci	}
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	return skb;
9162306a36Sopenharmony_ci}
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ciint rt2x00queue_map_txskb(struct queue_entry *entry)
9462306a36Sopenharmony_ci{
9562306a36Sopenharmony_ci	struct device *dev = entry->queue->rt2x00dev->dev;
9662306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	skbdesc->skb_dma =
9962306a36Sopenharmony_ci	    dma_map_single(dev, entry->skb->data, entry->skb->len, DMA_TO_DEVICE);
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	if (unlikely(dma_mapping_error(dev, skbdesc->skb_dma)))
10262306a36Sopenharmony_ci		return -ENOMEM;
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	skbdesc->flags |= SKBDESC_DMA_MAPPED_TX;
10562306a36Sopenharmony_ci	rt2x00lib_dmadone(entry);
10662306a36Sopenharmony_ci	return 0;
10762306a36Sopenharmony_ci}
10862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_map_txskb);
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_civoid rt2x00queue_unmap_skb(struct queue_entry *entry)
11162306a36Sopenharmony_ci{
11262306a36Sopenharmony_ci	struct device *dev = entry->queue->rt2x00dev->dev;
11362306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc = get_skb_frame_desc(entry->skb);
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (skbdesc->flags & SKBDESC_DMA_MAPPED_RX) {
11662306a36Sopenharmony_ci		dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len,
11762306a36Sopenharmony_ci				 DMA_FROM_DEVICE);
11862306a36Sopenharmony_ci		skbdesc->flags &= ~SKBDESC_DMA_MAPPED_RX;
11962306a36Sopenharmony_ci	} else if (skbdesc->flags & SKBDESC_DMA_MAPPED_TX) {
12062306a36Sopenharmony_ci		dma_unmap_single(dev, skbdesc->skb_dma, entry->skb->len,
12162306a36Sopenharmony_ci				 DMA_TO_DEVICE);
12262306a36Sopenharmony_ci		skbdesc->flags &= ~SKBDESC_DMA_MAPPED_TX;
12362306a36Sopenharmony_ci	}
12462306a36Sopenharmony_ci}
12562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_unmap_skb);
12662306a36Sopenharmony_ci
12762306a36Sopenharmony_civoid rt2x00queue_free_skb(struct queue_entry *entry)
12862306a36Sopenharmony_ci{
12962306a36Sopenharmony_ci	if (!entry->skb)
13062306a36Sopenharmony_ci		return;
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	rt2x00queue_unmap_skb(entry);
13362306a36Sopenharmony_ci	dev_kfree_skb_any(entry->skb);
13462306a36Sopenharmony_ci	entry->skb = NULL;
13562306a36Sopenharmony_ci}
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_civoid rt2x00queue_align_frame(struct sk_buff *skb)
13862306a36Sopenharmony_ci{
13962306a36Sopenharmony_ci	unsigned int frame_length = skb->len;
14062306a36Sopenharmony_ci	unsigned int align = ALIGN_SIZE(skb, 0);
14162306a36Sopenharmony_ci
14262306a36Sopenharmony_ci	if (!align)
14362306a36Sopenharmony_ci		return;
14462306a36Sopenharmony_ci
14562306a36Sopenharmony_ci	skb_push(skb, align);
14662306a36Sopenharmony_ci	memmove(skb->data, skb->data + align, frame_length);
14762306a36Sopenharmony_ci	skb_trim(skb, frame_length);
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * H/W needs L2 padding between the header and the paylod if header size
15262306a36Sopenharmony_ci * is not 4 bytes aligned.
15362306a36Sopenharmony_ci */
15462306a36Sopenharmony_civoid rt2x00queue_insert_l2pad(struct sk_buff *skb, unsigned int hdr_len)
15562306a36Sopenharmony_ci{
15662306a36Sopenharmony_ci	unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
15762306a36Sopenharmony_ci
15862306a36Sopenharmony_ci	if (!l2pad)
15962306a36Sopenharmony_ci		return;
16062306a36Sopenharmony_ci
16162306a36Sopenharmony_ci	skb_push(skb, l2pad);
16262306a36Sopenharmony_ci	memmove(skb->data, skb->data + l2pad, hdr_len);
16362306a36Sopenharmony_ci}
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_civoid rt2x00queue_remove_l2pad(struct sk_buff *skb, unsigned int hdr_len)
16662306a36Sopenharmony_ci{
16762306a36Sopenharmony_ci	unsigned int l2pad = (skb->len > hdr_len) ? L2PAD_SIZE(hdr_len) : 0;
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	if (!l2pad)
17062306a36Sopenharmony_ci		return;
17162306a36Sopenharmony_ci
17262306a36Sopenharmony_ci	memmove(skb->data + l2pad, skb->data, hdr_len);
17362306a36Sopenharmony_ci	skb_pull(skb, l2pad);
17462306a36Sopenharmony_ci}
17562306a36Sopenharmony_ci
17662306a36Sopenharmony_cistatic void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
17762306a36Sopenharmony_ci						 struct sk_buff *skb,
17862306a36Sopenharmony_ci						 struct txentry_desc *txdesc)
17962306a36Sopenharmony_ci{
18062306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
18162306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
18262306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
18362306a36Sopenharmony_ci	u16 seqno;
18462306a36Sopenharmony_ci
18562306a36Sopenharmony_ci	if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
18662306a36Sopenharmony_ci		return;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
18962306a36Sopenharmony_ci
19062306a36Sopenharmony_ci	if (!rt2x00_has_cap_flag(rt2x00dev, REQUIRE_SW_SEQNO)) {
19162306a36Sopenharmony_ci		/*
19262306a36Sopenharmony_ci		 * rt2800 has a H/W (or F/W) bug, device incorrectly increase
19362306a36Sopenharmony_ci		 * seqno on retransmitted data (non-QOS) and management frames.
19462306a36Sopenharmony_ci		 * To workaround the problem let's generate seqno in software.
19562306a36Sopenharmony_ci		 * Except for beacons which are transmitted periodically by H/W
19662306a36Sopenharmony_ci		 * hence hardware has to assign seqno for them.
19762306a36Sopenharmony_ci		 */
19862306a36Sopenharmony_ci	    	if (ieee80211_is_beacon(hdr->frame_control)) {
19962306a36Sopenharmony_ci			__set_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
20062306a36Sopenharmony_ci			/* H/W will generate sequence number */
20162306a36Sopenharmony_ci			return;
20262306a36Sopenharmony_ci		}
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci		__clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci	/*
20862306a36Sopenharmony_ci	 * The hardware is not able to insert a sequence number. Assign a
20962306a36Sopenharmony_ci	 * software generated one here.
21062306a36Sopenharmony_ci	 *
21162306a36Sopenharmony_ci	 * This is wrong because beacons are not getting sequence
21262306a36Sopenharmony_ci	 * numbers assigned properly.
21362306a36Sopenharmony_ci	 *
21462306a36Sopenharmony_ci	 * A secondary problem exists for drivers that cannot toggle
21562306a36Sopenharmony_ci	 * sequence counting per-frame, since those will override the
21662306a36Sopenharmony_ci	 * sequence counter given by mac80211.
21762306a36Sopenharmony_ci	 */
21862306a36Sopenharmony_ci	if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
21962306a36Sopenharmony_ci		seqno = atomic_add_return(0x10, &intf->seqno);
22062306a36Sopenharmony_ci	else
22162306a36Sopenharmony_ci		seqno = atomic_read(&intf->seqno);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
22462306a36Sopenharmony_ci	hdr->seq_ctrl |= cpu_to_le16(seqno);
22562306a36Sopenharmony_ci}
22662306a36Sopenharmony_ci
22762306a36Sopenharmony_cistatic void rt2x00queue_create_tx_descriptor_plcp(struct rt2x00_dev *rt2x00dev,
22862306a36Sopenharmony_ci						  struct sk_buff *skb,
22962306a36Sopenharmony_ci						  struct txentry_desc *txdesc,
23062306a36Sopenharmony_ci						  const struct rt2x00_rate *hwrate)
23162306a36Sopenharmony_ci{
23262306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
23362306a36Sopenharmony_ci	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
23462306a36Sopenharmony_ci	unsigned int data_length;
23562306a36Sopenharmony_ci	unsigned int duration;
23662306a36Sopenharmony_ci	unsigned int residual;
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	/*
23962306a36Sopenharmony_ci	 * Determine with what IFS priority this frame should be send.
24062306a36Sopenharmony_ci	 * Set ifs to IFS_SIFS when the this is not the first fragment,
24162306a36Sopenharmony_ci	 * or this fragment came after RTS/CTS.
24262306a36Sopenharmony_ci	 */
24362306a36Sopenharmony_ci	if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
24462306a36Sopenharmony_ci		txdesc->u.plcp.ifs = IFS_BACKOFF;
24562306a36Sopenharmony_ci	else
24662306a36Sopenharmony_ci		txdesc->u.plcp.ifs = IFS_SIFS;
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci	/* Data length + CRC + Crypto overhead (IV/EIV/ICV/MIC) */
24962306a36Sopenharmony_ci	data_length = skb->len + 4;
25062306a36Sopenharmony_ci	data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ci	/*
25362306a36Sopenharmony_ci	 * PLCP setup
25462306a36Sopenharmony_ci	 * Length calculation depends on OFDM/CCK rate.
25562306a36Sopenharmony_ci	 */
25662306a36Sopenharmony_ci	txdesc->u.plcp.signal = hwrate->plcp;
25762306a36Sopenharmony_ci	txdesc->u.plcp.service = 0x04;
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (hwrate->flags & DEV_RATE_OFDM) {
26062306a36Sopenharmony_ci		txdesc->u.plcp.length_high = (data_length >> 6) & 0x3f;
26162306a36Sopenharmony_ci		txdesc->u.plcp.length_low = data_length & 0x3f;
26262306a36Sopenharmony_ci	} else {
26362306a36Sopenharmony_ci		/*
26462306a36Sopenharmony_ci		 * Convert length to microseconds.
26562306a36Sopenharmony_ci		 */
26662306a36Sopenharmony_ci		residual = GET_DURATION_RES(data_length, hwrate->bitrate);
26762306a36Sopenharmony_ci		duration = GET_DURATION(data_length, hwrate->bitrate);
26862306a36Sopenharmony_ci
26962306a36Sopenharmony_ci		if (residual != 0) {
27062306a36Sopenharmony_ci			duration++;
27162306a36Sopenharmony_ci
27262306a36Sopenharmony_ci			/*
27362306a36Sopenharmony_ci			 * Check if we need to set the Length Extension
27462306a36Sopenharmony_ci			 */
27562306a36Sopenharmony_ci			if (hwrate->bitrate == 110 && residual <= 30)
27662306a36Sopenharmony_ci				txdesc->u.plcp.service |= 0x80;
27762306a36Sopenharmony_ci		}
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_ci		txdesc->u.plcp.length_high = (duration >> 8) & 0xff;
28062306a36Sopenharmony_ci		txdesc->u.plcp.length_low = duration & 0xff;
28162306a36Sopenharmony_ci
28262306a36Sopenharmony_ci		/*
28362306a36Sopenharmony_ci		 * When preamble is enabled we should set the
28462306a36Sopenharmony_ci		 * preamble bit for the signal.
28562306a36Sopenharmony_ci		 */
28662306a36Sopenharmony_ci		if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
28762306a36Sopenharmony_ci			txdesc->u.plcp.signal |= 0x08;
28862306a36Sopenharmony_ci	}
28962306a36Sopenharmony_ci}
29062306a36Sopenharmony_ci
29162306a36Sopenharmony_cistatic void rt2x00queue_create_tx_descriptor_ht(struct rt2x00_dev *rt2x00dev,
29262306a36Sopenharmony_ci						struct sk_buff *skb,
29362306a36Sopenharmony_ci						struct txentry_desc *txdesc,
29462306a36Sopenharmony_ci						struct ieee80211_sta *sta,
29562306a36Sopenharmony_ci						const struct rt2x00_rate *hwrate)
29662306a36Sopenharmony_ci{
29762306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
29862306a36Sopenharmony_ci	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
29962306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
30062306a36Sopenharmony_ci	struct rt2x00_sta *sta_priv = NULL;
30162306a36Sopenharmony_ci	u8 density = 0;
30262306a36Sopenharmony_ci
30362306a36Sopenharmony_ci	if (sta) {
30462306a36Sopenharmony_ci		sta_priv = sta_to_rt2x00_sta(sta);
30562306a36Sopenharmony_ci		txdesc->u.ht.wcid = sta_priv->wcid;
30662306a36Sopenharmony_ci		density = sta->deflink.ht_cap.ampdu_density;
30762306a36Sopenharmony_ci	}
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_ci	/*
31062306a36Sopenharmony_ci	 * If IEEE80211_TX_RC_MCS is set txrate->idx just contains the
31162306a36Sopenharmony_ci	 * mcs rate to be used
31262306a36Sopenharmony_ci	 */
31362306a36Sopenharmony_ci	if (txrate->flags & IEEE80211_TX_RC_MCS) {
31462306a36Sopenharmony_ci		txdesc->u.ht.mcs = txrate->idx;
31562306a36Sopenharmony_ci
31662306a36Sopenharmony_ci		/*
31762306a36Sopenharmony_ci		 * MIMO PS should be set to 1 for STA's using dynamic SM PS
31862306a36Sopenharmony_ci		 * when using more then one tx stream (>MCS7).
31962306a36Sopenharmony_ci		 */
32062306a36Sopenharmony_ci		if (sta && txdesc->u.ht.mcs > 7 &&
32162306a36Sopenharmony_ci		    sta->deflink.smps_mode == IEEE80211_SMPS_DYNAMIC)
32262306a36Sopenharmony_ci			__set_bit(ENTRY_TXD_HT_MIMO_PS, &txdesc->flags);
32362306a36Sopenharmony_ci	} else {
32462306a36Sopenharmony_ci		txdesc->u.ht.mcs = rt2x00_get_rate_mcs(hwrate->mcs);
32562306a36Sopenharmony_ci		if (txrate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)
32662306a36Sopenharmony_ci			txdesc->u.ht.mcs |= 0x08;
32762306a36Sopenharmony_ci	}
32862306a36Sopenharmony_ci
32962306a36Sopenharmony_ci	if (test_bit(CONFIG_HT_DISABLED, &rt2x00dev->flags)) {
33062306a36Sopenharmony_ci		if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
33162306a36Sopenharmony_ci			txdesc->u.ht.txop = TXOP_SIFS;
33262306a36Sopenharmony_ci		else
33362306a36Sopenharmony_ci			txdesc->u.ht.txop = TXOP_BACKOFF;
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci		/* Left zero on all other settings. */
33662306a36Sopenharmony_ci		return;
33762306a36Sopenharmony_ci	}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_ci	/*
34062306a36Sopenharmony_ci	 * Only one STBC stream is supported for now.
34162306a36Sopenharmony_ci	 */
34262306a36Sopenharmony_ci	if (tx_info->flags & IEEE80211_TX_CTL_STBC)
34362306a36Sopenharmony_ci		txdesc->u.ht.stbc = 1;
34462306a36Sopenharmony_ci
34562306a36Sopenharmony_ci	/*
34662306a36Sopenharmony_ci	 * This frame is eligible for an AMPDU, however, don't aggregate
34762306a36Sopenharmony_ci	 * frames that are intended to probe a specific tx rate.
34862306a36Sopenharmony_ci	 */
34962306a36Sopenharmony_ci	if (tx_info->flags & IEEE80211_TX_CTL_AMPDU &&
35062306a36Sopenharmony_ci	    !(tx_info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE)) {
35162306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_HT_AMPDU, &txdesc->flags);
35262306a36Sopenharmony_ci		txdesc->u.ht.mpdu_density = density;
35362306a36Sopenharmony_ci		txdesc->u.ht.ba_size = 7; /* FIXME: What value is needed? */
35462306a36Sopenharmony_ci	}
35562306a36Sopenharmony_ci
35662306a36Sopenharmony_ci	/*
35762306a36Sopenharmony_ci	 * Set 40Mhz mode if necessary (for legacy rates this will
35862306a36Sopenharmony_ci	 * duplicate the frame to both channels).
35962306a36Sopenharmony_ci	 */
36062306a36Sopenharmony_ci	if (txrate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH ||
36162306a36Sopenharmony_ci	    txrate->flags & IEEE80211_TX_RC_DUP_DATA)
36262306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_HT_BW_40, &txdesc->flags);
36362306a36Sopenharmony_ci	if (txrate->flags & IEEE80211_TX_RC_SHORT_GI)
36462306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_HT_SHORT_GI, &txdesc->flags);
36562306a36Sopenharmony_ci
36662306a36Sopenharmony_ci	/*
36762306a36Sopenharmony_ci	 * Determine IFS values
36862306a36Sopenharmony_ci	 * - Use TXOP_BACKOFF for management frames except beacons
36962306a36Sopenharmony_ci	 * - Use TXOP_SIFS for fragment bursts
37062306a36Sopenharmony_ci	 * - Use TXOP_HTTXOP for everything else
37162306a36Sopenharmony_ci	 *
37262306a36Sopenharmony_ci	 * Note: rt2800 devices won't use CTS protection (if used)
37362306a36Sopenharmony_ci	 * for frames not transmitted with TXOP_HTTXOP
37462306a36Sopenharmony_ci	 */
37562306a36Sopenharmony_ci	if (ieee80211_is_mgmt(hdr->frame_control) &&
37662306a36Sopenharmony_ci	    !ieee80211_is_beacon(hdr->frame_control))
37762306a36Sopenharmony_ci		txdesc->u.ht.txop = TXOP_BACKOFF;
37862306a36Sopenharmony_ci	else if (!(tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT))
37962306a36Sopenharmony_ci		txdesc->u.ht.txop = TXOP_SIFS;
38062306a36Sopenharmony_ci	else
38162306a36Sopenharmony_ci		txdesc->u.ht.txop = TXOP_HTTXOP;
38262306a36Sopenharmony_ci}
38362306a36Sopenharmony_ci
38462306a36Sopenharmony_cistatic void rt2x00queue_create_tx_descriptor(struct rt2x00_dev *rt2x00dev,
38562306a36Sopenharmony_ci					     struct sk_buff *skb,
38662306a36Sopenharmony_ci					     struct txentry_desc *txdesc,
38762306a36Sopenharmony_ci					     struct ieee80211_sta *sta)
38862306a36Sopenharmony_ci{
38962306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
39062306a36Sopenharmony_ci	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
39162306a36Sopenharmony_ci	struct ieee80211_tx_rate *txrate = &tx_info->control.rates[0];
39262306a36Sopenharmony_ci	struct ieee80211_rate *rate;
39362306a36Sopenharmony_ci	const struct rt2x00_rate *hwrate = NULL;
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci	memset(txdesc, 0, sizeof(*txdesc));
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	/*
39862306a36Sopenharmony_ci	 * Header and frame information.
39962306a36Sopenharmony_ci	 */
40062306a36Sopenharmony_ci	txdesc->length = skb->len;
40162306a36Sopenharmony_ci	txdesc->header_length = ieee80211_get_hdrlen_from_skb(skb);
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	/*
40462306a36Sopenharmony_ci	 * Check whether this frame is to be acked.
40562306a36Sopenharmony_ci	 */
40662306a36Sopenharmony_ci	if (!(tx_info->flags & IEEE80211_TX_CTL_NO_ACK))
40762306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_ACK, &txdesc->flags);
40862306a36Sopenharmony_ci
40962306a36Sopenharmony_ci	/*
41062306a36Sopenharmony_ci	 * Check if this is a RTS/CTS frame
41162306a36Sopenharmony_ci	 */
41262306a36Sopenharmony_ci	if (ieee80211_is_rts(hdr->frame_control) ||
41362306a36Sopenharmony_ci	    ieee80211_is_cts(hdr->frame_control)) {
41462306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
41562306a36Sopenharmony_ci		if (ieee80211_is_rts(hdr->frame_control))
41662306a36Sopenharmony_ci			__set_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags);
41762306a36Sopenharmony_ci		else
41862306a36Sopenharmony_ci			__set_bit(ENTRY_TXD_CTS_FRAME, &txdesc->flags);
41962306a36Sopenharmony_ci		if (tx_info->control.rts_cts_rate_idx >= 0)
42062306a36Sopenharmony_ci			rate =
42162306a36Sopenharmony_ci			    ieee80211_get_rts_cts_rate(rt2x00dev->hw, tx_info);
42262306a36Sopenharmony_ci	}
42362306a36Sopenharmony_ci
42462306a36Sopenharmony_ci	/*
42562306a36Sopenharmony_ci	 * Determine retry information.
42662306a36Sopenharmony_ci	 */
42762306a36Sopenharmony_ci	txdesc->retry_limit = tx_info->control.rates[0].count - 1;
42862306a36Sopenharmony_ci	if (txdesc->retry_limit >= rt2x00dev->long_retry)
42962306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_RETRY_MODE, &txdesc->flags);
43062306a36Sopenharmony_ci
43162306a36Sopenharmony_ci	/*
43262306a36Sopenharmony_ci	 * Check if more fragments are pending
43362306a36Sopenharmony_ci	 */
43462306a36Sopenharmony_ci	if (ieee80211_has_morefrags(hdr->frame_control)) {
43562306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
43662306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_MORE_FRAG, &txdesc->flags);
43762306a36Sopenharmony_ci	}
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/*
44062306a36Sopenharmony_ci	 * Check if more frames (!= fragments) are pending
44162306a36Sopenharmony_ci	 */
44262306a36Sopenharmony_ci	if (tx_info->flags & IEEE80211_TX_CTL_MORE_FRAMES)
44362306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_BURST, &txdesc->flags);
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_ci	/*
44662306a36Sopenharmony_ci	 * Beacons and probe responses require the tsf timestamp
44762306a36Sopenharmony_ci	 * to be inserted into the frame.
44862306a36Sopenharmony_ci	 */
44962306a36Sopenharmony_ci	if ((ieee80211_is_beacon(hdr->frame_control) ||
45062306a36Sopenharmony_ci	     ieee80211_is_probe_resp(hdr->frame_control)) &&
45162306a36Sopenharmony_ci	    !(tx_info->flags & IEEE80211_TX_CTL_INJECTED))
45262306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_REQ_TIMESTAMP, &txdesc->flags);
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	if ((tx_info->flags & IEEE80211_TX_CTL_FIRST_FRAGMENT) &&
45562306a36Sopenharmony_ci	    !test_bit(ENTRY_TXD_RTS_FRAME, &txdesc->flags))
45662306a36Sopenharmony_ci		__set_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags);
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	/*
45962306a36Sopenharmony_ci	 * Determine rate modulation.
46062306a36Sopenharmony_ci	 */
46162306a36Sopenharmony_ci	if (txrate->flags & IEEE80211_TX_RC_GREEN_FIELD)
46262306a36Sopenharmony_ci		txdesc->rate_mode = RATE_MODE_HT_GREENFIELD;
46362306a36Sopenharmony_ci	else if (txrate->flags & IEEE80211_TX_RC_MCS)
46462306a36Sopenharmony_ci		txdesc->rate_mode = RATE_MODE_HT_MIX;
46562306a36Sopenharmony_ci	else {
46662306a36Sopenharmony_ci		rate = ieee80211_get_tx_rate(rt2x00dev->hw, tx_info);
46762306a36Sopenharmony_ci		hwrate = rt2x00_get_rate(rate->hw_value);
46862306a36Sopenharmony_ci		if (hwrate->flags & DEV_RATE_OFDM)
46962306a36Sopenharmony_ci			txdesc->rate_mode = RATE_MODE_OFDM;
47062306a36Sopenharmony_ci		else
47162306a36Sopenharmony_ci			txdesc->rate_mode = RATE_MODE_CCK;
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci
47462306a36Sopenharmony_ci	/*
47562306a36Sopenharmony_ci	 * Apply TX descriptor handling by components
47662306a36Sopenharmony_ci	 */
47762306a36Sopenharmony_ci	rt2x00crypto_create_tx_descriptor(rt2x00dev, skb, txdesc);
47862306a36Sopenharmony_ci	rt2x00queue_create_tx_descriptor_seq(rt2x00dev, skb, txdesc);
47962306a36Sopenharmony_ci
48062306a36Sopenharmony_ci	if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_HT_TX_DESC))
48162306a36Sopenharmony_ci		rt2x00queue_create_tx_descriptor_ht(rt2x00dev, skb, txdesc,
48262306a36Sopenharmony_ci						   sta, hwrate);
48362306a36Sopenharmony_ci	else
48462306a36Sopenharmony_ci		rt2x00queue_create_tx_descriptor_plcp(rt2x00dev, skb, txdesc,
48562306a36Sopenharmony_ci						      hwrate);
48662306a36Sopenharmony_ci}
48762306a36Sopenharmony_ci
48862306a36Sopenharmony_cistatic int rt2x00queue_write_tx_data(struct queue_entry *entry,
48962306a36Sopenharmony_ci				     struct txentry_desc *txdesc)
49062306a36Sopenharmony_ci{
49162306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
49262306a36Sopenharmony_ci
49362306a36Sopenharmony_ci	/*
49462306a36Sopenharmony_ci	 * This should not happen, we already checked the entry
49562306a36Sopenharmony_ci	 * was ours. When the hardware disagrees there has been
49662306a36Sopenharmony_ci	 * a queue corruption!
49762306a36Sopenharmony_ci	 */
49862306a36Sopenharmony_ci	if (unlikely(rt2x00dev->ops->lib->get_entry_state &&
49962306a36Sopenharmony_ci		     rt2x00dev->ops->lib->get_entry_state(entry))) {
50062306a36Sopenharmony_ci		rt2x00_err(rt2x00dev,
50162306a36Sopenharmony_ci			   "Corrupt queue %d, accessing entry which is not ours\n"
50262306a36Sopenharmony_ci			   "Please file bug report to %s\n",
50362306a36Sopenharmony_ci			   entry->queue->qid, DRV_PROJECT);
50462306a36Sopenharmony_ci		return -EINVAL;
50562306a36Sopenharmony_ci	}
50662306a36Sopenharmony_ci
50762306a36Sopenharmony_ci	/*
50862306a36Sopenharmony_ci	 * Add the requested extra tx headroom in front of the skb.
50962306a36Sopenharmony_ci	 */
51062306a36Sopenharmony_ci	skb_push(entry->skb, rt2x00dev->extra_tx_headroom);
51162306a36Sopenharmony_ci	memset(entry->skb->data, 0, rt2x00dev->extra_tx_headroom);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	/*
51462306a36Sopenharmony_ci	 * Call the driver's write_tx_data function, if it exists.
51562306a36Sopenharmony_ci	 */
51662306a36Sopenharmony_ci	if (rt2x00dev->ops->lib->write_tx_data)
51762306a36Sopenharmony_ci		rt2x00dev->ops->lib->write_tx_data(entry, txdesc);
51862306a36Sopenharmony_ci
51962306a36Sopenharmony_ci	/*
52062306a36Sopenharmony_ci	 * Map the skb to DMA.
52162306a36Sopenharmony_ci	 */
52262306a36Sopenharmony_ci	if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_DMA) &&
52362306a36Sopenharmony_ci	    rt2x00queue_map_txskb(entry))
52462306a36Sopenharmony_ci		return -ENOMEM;
52562306a36Sopenharmony_ci
52662306a36Sopenharmony_ci	return 0;
52762306a36Sopenharmony_ci}
52862306a36Sopenharmony_ci
52962306a36Sopenharmony_cistatic void rt2x00queue_write_tx_descriptor(struct queue_entry *entry,
53062306a36Sopenharmony_ci					    struct txentry_desc *txdesc)
53162306a36Sopenharmony_ci{
53262306a36Sopenharmony_ci	struct data_queue *queue = entry->queue;
53362306a36Sopenharmony_ci
53462306a36Sopenharmony_ci	queue->rt2x00dev->ops->lib->write_tx_desc(entry, txdesc);
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci	/*
53762306a36Sopenharmony_ci	 * All processing on the frame has been completed, this means
53862306a36Sopenharmony_ci	 * it is now ready to be dumped to userspace through debugfs.
53962306a36Sopenharmony_ci	 */
54062306a36Sopenharmony_ci	rt2x00debug_dump_frame(queue->rt2x00dev, DUMP_FRAME_TX, entry);
54162306a36Sopenharmony_ci}
54262306a36Sopenharmony_ci
54362306a36Sopenharmony_cistatic void rt2x00queue_kick_tx_queue(struct data_queue *queue,
54462306a36Sopenharmony_ci				      struct txentry_desc *txdesc)
54562306a36Sopenharmony_ci{
54662306a36Sopenharmony_ci	/*
54762306a36Sopenharmony_ci	 * Check if we need to kick the queue, there are however a few rules
54862306a36Sopenharmony_ci	 *	1) Don't kick unless this is the last in frame in a burst.
54962306a36Sopenharmony_ci	 *	   When the burst flag is set, this frame is always followed
55062306a36Sopenharmony_ci	 *	   by another frame which in some way are related to eachother.
55162306a36Sopenharmony_ci	 *	   This is true for fragments, RTS or CTS-to-self frames.
55262306a36Sopenharmony_ci	 *	2) Rule 1 can be broken when the available entries
55362306a36Sopenharmony_ci	 *	   in the queue are less then a certain threshold.
55462306a36Sopenharmony_ci	 */
55562306a36Sopenharmony_ci	if (rt2x00queue_threshold(queue) ||
55662306a36Sopenharmony_ci	    !test_bit(ENTRY_TXD_BURST, &txdesc->flags))
55762306a36Sopenharmony_ci		queue->rt2x00dev->ops->lib->kick_queue(queue);
55862306a36Sopenharmony_ci}
55962306a36Sopenharmony_ci
56062306a36Sopenharmony_cistatic void rt2x00queue_bar_check(struct queue_entry *entry)
56162306a36Sopenharmony_ci{
56262306a36Sopenharmony_ci	struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
56362306a36Sopenharmony_ci	struct ieee80211_bar *bar = (void *) (entry->skb->data +
56462306a36Sopenharmony_ci				    rt2x00dev->extra_tx_headroom);
56562306a36Sopenharmony_ci	struct rt2x00_bar_list_entry *bar_entry;
56662306a36Sopenharmony_ci
56762306a36Sopenharmony_ci	if (likely(!ieee80211_is_back_req(bar->frame_control)))
56862306a36Sopenharmony_ci		return;
56962306a36Sopenharmony_ci
57062306a36Sopenharmony_ci	bar_entry = kmalloc(sizeof(*bar_entry), GFP_ATOMIC);
57162306a36Sopenharmony_ci
57262306a36Sopenharmony_ci	/*
57362306a36Sopenharmony_ci	 * If the alloc fails we still send the BAR out but just don't track
57462306a36Sopenharmony_ci	 * it in our bar list. And as a result we will report it to mac80211
57562306a36Sopenharmony_ci	 * back as failed.
57662306a36Sopenharmony_ci	 */
57762306a36Sopenharmony_ci	if (!bar_entry)
57862306a36Sopenharmony_ci		return;
57962306a36Sopenharmony_ci
58062306a36Sopenharmony_ci	bar_entry->entry = entry;
58162306a36Sopenharmony_ci	bar_entry->block_acked = 0;
58262306a36Sopenharmony_ci
58362306a36Sopenharmony_ci	/*
58462306a36Sopenharmony_ci	 * Copy the relevant parts of the 802.11 BAR into out check list
58562306a36Sopenharmony_ci	 * such that we can use RCU for less-overhead in the RX path since
58662306a36Sopenharmony_ci	 * sending BARs and processing the according BlockAck should be
58762306a36Sopenharmony_ci	 * the exception.
58862306a36Sopenharmony_ci	 */
58962306a36Sopenharmony_ci	memcpy(bar_entry->ra, bar->ra, sizeof(bar->ra));
59062306a36Sopenharmony_ci	memcpy(bar_entry->ta, bar->ta, sizeof(bar->ta));
59162306a36Sopenharmony_ci	bar_entry->control = bar->control;
59262306a36Sopenharmony_ci	bar_entry->start_seq_num = bar->start_seq_num;
59362306a36Sopenharmony_ci
59462306a36Sopenharmony_ci	/*
59562306a36Sopenharmony_ci	 * Insert BAR into our BAR check list.
59662306a36Sopenharmony_ci	 */
59762306a36Sopenharmony_ci	spin_lock_bh(&rt2x00dev->bar_list_lock);
59862306a36Sopenharmony_ci	list_add_tail_rcu(&bar_entry->list, &rt2x00dev->bar_list);
59962306a36Sopenharmony_ci	spin_unlock_bh(&rt2x00dev->bar_list_lock);
60062306a36Sopenharmony_ci}
60162306a36Sopenharmony_ci
60262306a36Sopenharmony_ciint rt2x00queue_write_tx_frame(struct data_queue *queue, struct sk_buff *skb,
60362306a36Sopenharmony_ci			       struct ieee80211_sta *sta, bool local)
60462306a36Sopenharmony_ci{
60562306a36Sopenharmony_ci	struct ieee80211_tx_info *tx_info;
60662306a36Sopenharmony_ci	struct queue_entry *entry;
60762306a36Sopenharmony_ci	struct txentry_desc txdesc;
60862306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc;
60962306a36Sopenharmony_ci	u8 rate_idx, rate_flags;
61062306a36Sopenharmony_ci	int ret = 0;
61162306a36Sopenharmony_ci
61262306a36Sopenharmony_ci	/*
61362306a36Sopenharmony_ci	 * Copy all TX descriptor information into txdesc,
61462306a36Sopenharmony_ci	 * after that we are free to use the skb->cb array
61562306a36Sopenharmony_ci	 * for our information.
61662306a36Sopenharmony_ci	 */
61762306a36Sopenharmony_ci	rt2x00queue_create_tx_descriptor(queue->rt2x00dev, skb, &txdesc, sta);
61862306a36Sopenharmony_ci
61962306a36Sopenharmony_ci	/*
62062306a36Sopenharmony_ci	 * All information is retrieved from the skb->cb array,
62162306a36Sopenharmony_ci	 * now we should claim ownership of the driver part of that
62262306a36Sopenharmony_ci	 * array, preserving the bitrate index and flags.
62362306a36Sopenharmony_ci	 */
62462306a36Sopenharmony_ci	tx_info = IEEE80211_SKB_CB(skb);
62562306a36Sopenharmony_ci	rate_idx = tx_info->control.rates[0].idx;
62662306a36Sopenharmony_ci	rate_flags = tx_info->control.rates[0].flags;
62762306a36Sopenharmony_ci	skbdesc = get_skb_frame_desc(skb);
62862306a36Sopenharmony_ci	memset(skbdesc, 0, sizeof(*skbdesc));
62962306a36Sopenharmony_ci	skbdesc->tx_rate_idx = rate_idx;
63062306a36Sopenharmony_ci	skbdesc->tx_rate_flags = rate_flags;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci	if (local)
63362306a36Sopenharmony_ci		skbdesc->flags |= SKBDESC_NOT_MAC80211;
63462306a36Sopenharmony_ci
63562306a36Sopenharmony_ci	/*
63662306a36Sopenharmony_ci	 * When hardware encryption is supported, and this frame
63762306a36Sopenharmony_ci	 * is to be encrypted, we should strip the IV/EIV data from
63862306a36Sopenharmony_ci	 * the frame so we can provide it to the driver separately.
63962306a36Sopenharmony_ci	 */
64062306a36Sopenharmony_ci	if (test_bit(ENTRY_TXD_ENCRYPT, &txdesc.flags) &&
64162306a36Sopenharmony_ci	    !test_bit(ENTRY_TXD_ENCRYPT_IV, &txdesc.flags)) {
64262306a36Sopenharmony_ci		if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_COPY_IV))
64362306a36Sopenharmony_ci			rt2x00crypto_tx_copy_iv(skb, &txdesc);
64462306a36Sopenharmony_ci		else
64562306a36Sopenharmony_ci			rt2x00crypto_tx_remove_iv(skb, &txdesc);
64662306a36Sopenharmony_ci	}
64762306a36Sopenharmony_ci
64862306a36Sopenharmony_ci	/*
64962306a36Sopenharmony_ci	 * When DMA allocation is required we should guarantee to the
65062306a36Sopenharmony_ci	 * driver that the DMA is aligned to a 4-byte boundary.
65162306a36Sopenharmony_ci	 * However some drivers require L2 padding to pad the payload
65262306a36Sopenharmony_ci	 * rather then the header. This could be a requirement for
65362306a36Sopenharmony_ci	 * PCI and USB devices, while header alignment only is valid
65462306a36Sopenharmony_ci	 * for PCI devices.
65562306a36Sopenharmony_ci	 */
65662306a36Sopenharmony_ci	if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_L2PAD))
65762306a36Sopenharmony_ci		rt2x00queue_insert_l2pad(skb, txdesc.header_length);
65862306a36Sopenharmony_ci	else if (rt2x00_has_cap_flag(queue->rt2x00dev, REQUIRE_DMA))
65962306a36Sopenharmony_ci		rt2x00queue_align_frame(skb);
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	/*
66262306a36Sopenharmony_ci	 * That function must be called with bh disabled.
66362306a36Sopenharmony_ci	 */
66462306a36Sopenharmony_ci	spin_lock(&queue->tx_lock);
66562306a36Sopenharmony_ci
66662306a36Sopenharmony_ci	if (unlikely(rt2x00queue_full(queue))) {
66762306a36Sopenharmony_ci		rt2x00_dbg(queue->rt2x00dev, "Dropping frame due to full tx queue %d\n",
66862306a36Sopenharmony_ci			   queue->qid);
66962306a36Sopenharmony_ci		ret = -ENOBUFS;
67062306a36Sopenharmony_ci		goto out;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	entry = rt2x00queue_get_entry(queue, Q_INDEX);
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	if (unlikely(test_and_set_bit(ENTRY_OWNER_DEVICE_DATA,
67662306a36Sopenharmony_ci				      &entry->flags))) {
67762306a36Sopenharmony_ci		rt2x00_err(queue->rt2x00dev,
67862306a36Sopenharmony_ci			   "Arrived at non-free entry in the non-full queue %d\n"
67962306a36Sopenharmony_ci			   "Please file bug report to %s\n",
68062306a36Sopenharmony_ci			   queue->qid, DRV_PROJECT);
68162306a36Sopenharmony_ci		ret = -EINVAL;
68262306a36Sopenharmony_ci		goto out;
68362306a36Sopenharmony_ci	}
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	entry->skb = skb;
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	/*
68862306a36Sopenharmony_ci	 * It could be possible that the queue was corrupted and this
68962306a36Sopenharmony_ci	 * call failed. Since we always return NETDEV_TX_OK to mac80211,
69062306a36Sopenharmony_ci	 * this frame will simply be dropped.
69162306a36Sopenharmony_ci	 */
69262306a36Sopenharmony_ci	if (unlikely(rt2x00queue_write_tx_data(entry, &txdesc))) {
69362306a36Sopenharmony_ci		clear_bit(ENTRY_OWNER_DEVICE_DATA, &entry->flags);
69462306a36Sopenharmony_ci		entry->skb = NULL;
69562306a36Sopenharmony_ci		ret = -EIO;
69662306a36Sopenharmony_ci		goto out;
69762306a36Sopenharmony_ci	}
69862306a36Sopenharmony_ci
69962306a36Sopenharmony_ci	/*
70062306a36Sopenharmony_ci	 * Put BlockAckReqs into our check list for driver BA processing.
70162306a36Sopenharmony_ci	 */
70262306a36Sopenharmony_ci	rt2x00queue_bar_check(entry);
70362306a36Sopenharmony_ci
70462306a36Sopenharmony_ci	set_bit(ENTRY_DATA_PENDING, &entry->flags);
70562306a36Sopenharmony_ci
70662306a36Sopenharmony_ci	rt2x00queue_index_inc(entry, Q_INDEX);
70762306a36Sopenharmony_ci	rt2x00queue_write_tx_descriptor(entry, &txdesc);
70862306a36Sopenharmony_ci	rt2x00queue_kick_tx_queue(queue, &txdesc);
70962306a36Sopenharmony_ci
71062306a36Sopenharmony_ciout:
71162306a36Sopenharmony_ci	/*
71262306a36Sopenharmony_ci	 * Pausing queue has to be serialized with rt2x00lib_txdone(), so we
71362306a36Sopenharmony_ci	 * do this under queue->tx_lock. Bottom halve was already disabled
71462306a36Sopenharmony_ci	 * before ieee80211_xmit() call.
71562306a36Sopenharmony_ci	 */
71662306a36Sopenharmony_ci	if (rt2x00queue_threshold(queue))
71762306a36Sopenharmony_ci		rt2x00queue_pause_queue(queue);
71862306a36Sopenharmony_ci
71962306a36Sopenharmony_ci	spin_unlock(&queue->tx_lock);
72062306a36Sopenharmony_ci	return ret;
72162306a36Sopenharmony_ci}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ciint rt2x00queue_clear_beacon(struct rt2x00_dev *rt2x00dev,
72462306a36Sopenharmony_ci			     struct ieee80211_vif *vif)
72562306a36Sopenharmony_ci{
72662306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
72762306a36Sopenharmony_ci
72862306a36Sopenharmony_ci	if (unlikely(!intf->beacon))
72962306a36Sopenharmony_ci		return -ENOBUFS;
73062306a36Sopenharmony_ci
73162306a36Sopenharmony_ci	/*
73262306a36Sopenharmony_ci	 * Clean up the beacon skb.
73362306a36Sopenharmony_ci	 */
73462306a36Sopenharmony_ci	rt2x00queue_free_skb(intf->beacon);
73562306a36Sopenharmony_ci
73662306a36Sopenharmony_ci	/*
73762306a36Sopenharmony_ci	 * Clear beacon (single bssid devices don't need to clear the beacon
73862306a36Sopenharmony_ci	 * since the beacon queue will get stopped anyway).
73962306a36Sopenharmony_ci	 */
74062306a36Sopenharmony_ci	if (rt2x00dev->ops->lib->clear_beacon)
74162306a36Sopenharmony_ci		rt2x00dev->ops->lib->clear_beacon(intf->beacon);
74262306a36Sopenharmony_ci
74362306a36Sopenharmony_ci	return 0;
74462306a36Sopenharmony_ci}
74562306a36Sopenharmony_ci
74662306a36Sopenharmony_ciint rt2x00queue_update_beacon(struct rt2x00_dev *rt2x00dev,
74762306a36Sopenharmony_ci			      struct ieee80211_vif *vif)
74862306a36Sopenharmony_ci{
74962306a36Sopenharmony_ci	struct rt2x00_intf *intf = vif_to_intf(vif);
75062306a36Sopenharmony_ci	struct skb_frame_desc *skbdesc;
75162306a36Sopenharmony_ci	struct txentry_desc txdesc;
75262306a36Sopenharmony_ci
75362306a36Sopenharmony_ci	if (unlikely(!intf->beacon))
75462306a36Sopenharmony_ci		return -ENOBUFS;
75562306a36Sopenharmony_ci
75662306a36Sopenharmony_ci	/*
75762306a36Sopenharmony_ci	 * Clean up the beacon skb.
75862306a36Sopenharmony_ci	 */
75962306a36Sopenharmony_ci	rt2x00queue_free_skb(intf->beacon);
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	intf->beacon->skb = ieee80211_beacon_get(rt2x00dev->hw, vif, 0);
76262306a36Sopenharmony_ci	if (!intf->beacon->skb)
76362306a36Sopenharmony_ci		return -ENOMEM;
76462306a36Sopenharmony_ci
76562306a36Sopenharmony_ci	/*
76662306a36Sopenharmony_ci	 * Copy all TX descriptor information into txdesc,
76762306a36Sopenharmony_ci	 * after that we are free to use the skb->cb array
76862306a36Sopenharmony_ci	 * for our information.
76962306a36Sopenharmony_ci	 */
77062306a36Sopenharmony_ci	rt2x00queue_create_tx_descriptor(rt2x00dev, intf->beacon->skb, &txdesc, NULL);
77162306a36Sopenharmony_ci
77262306a36Sopenharmony_ci	/*
77362306a36Sopenharmony_ci	 * Fill in skb descriptor
77462306a36Sopenharmony_ci	 */
77562306a36Sopenharmony_ci	skbdesc = get_skb_frame_desc(intf->beacon->skb);
77662306a36Sopenharmony_ci	memset(skbdesc, 0, sizeof(*skbdesc));
77762306a36Sopenharmony_ci
77862306a36Sopenharmony_ci	/*
77962306a36Sopenharmony_ci	 * Send beacon to hardware.
78062306a36Sopenharmony_ci	 */
78162306a36Sopenharmony_ci	rt2x00dev->ops->lib->write_beacon(intf->beacon, &txdesc);
78262306a36Sopenharmony_ci
78362306a36Sopenharmony_ci	return 0;
78462306a36Sopenharmony_ci
78562306a36Sopenharmony_ci}
78662306a36Sopenharmony_ci
78762306a36Sopenharmony_cibool rt2x00queue_for_each_entry(struct data_queue *queue,
78862306a36Sopenharmony_ci				enum queue_index start,
78962306a36Sopenharmony_ci				enum queue_index end,
79062306a36Sopenharmony_ci				void *data,
79162306a36Sopenharmony_ci				bool (*fn)(struct queue_entry *entry,
79262306a36Sopenharmony_ci					   void *data))
79362306a36Sopenharmony_ci{
79462306a36Sopenharmony_ci	unsigned long irqflags;
79562306a36Sopenharmony_ci	unsigned int index_start;
79662306a36Sopenharmony_ci	unsigned int index_end;
79762306a36Sopenharmony_ci	unsigned int i;
79862306a36Sopenharmony_ci
79962306a36Sopenharmony_ci	if (unlikely(start >= Q_INDEX_MAX || end >= Q_INDEX_MAX)) {
80062306a36Sopenharmony_ci		rt2x00_err(queue->rt2x00dev,
80162306a36Sopenharmony_ci			   "Entry requested from invalid index range (%d - %d)\n",
80262306a36Sopenharmony_ci			   start, end);
80362306a36Sopenharmony_ci		return true;
80462306a36Sopenharmony_ci	}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_ci	/*
80762306a36Sopenharmony_ci	 * Only protect the range we are going to loop over,
80862306a36Sopenharmony_ci	 * if during our loop a extra entry is set to pending
80962306a36Sopenharmony_ci	 * it should not be kicked during this run, since it
81062306a36Sopenharmony_ci	 * is part of another TX operation.
81162306a36Sopenharmony_ci	 */
81262306a36Sopenharmony_ci	spin_lock_irqsave(&queue->index_lock, irqflags);
81362306a36Sopenharmony_ci	index_start = queue->index[start];
81462306a36Sopenharmony_ci	index_end = queue->index[end];
81562306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->index_lock, irqflags);
81662306a36Sopenharmony_ci
81762306a36Sopenharmony_ci	/*
81862306a36Sopenharmony_ci	 * Start from the TX done pointer, this guarantees that we will
81962306a36Sopenharmony_ci	 * send out all frames in the correct order.
82062306a36Sopenharmony_ci	 */
82162306a36Sopenharmony_ci	if (index_start < index_end) {
82262306a36Sopenharmony_ci		for (i = index_start; i < index_end; i++) {
82362306a36Sopenharmony_ci			if (fn(&queue->entries[i], data))
82462306a36Sopenharmony_ci				return true;
82562306a36Sopenharmony_ci		}
82662306a36Sopenharmony_ci	} else {
82762306a36Sopenharmony_ci		for (i = index_start; i < queue->limit; i++) {
82862306a36Sopenharmony_ci			if (fn(&queue->entries[i], data))
82962306a36Sopenharmony_ci				return true;
83062306a36Sopenharmony_ci		}
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci		for (i = 0; i < index_end; i++) {
83362306a36Sopenharmony_ci			if (fn(&queue->entries[i], data))
83462306a36Sopenharmony_ci				return true;
83562306a36Sopenharmony_ci		}
83662306a36Sopenharmony_ci	}
83762306a36Sopenharmony_ci
83862306a36Sopenharmony_ci	return false;
83962306a36Sopenharmony_ci}
84062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_for_each_entry);
84162306a36Sopenharmony_ci
84262306a36Sopenharmony_cistruct queue_entry *rt2x00queue_get_entry(struct data_queue *queue,
84362306a36Sopenharmony_ci					  enum queue_index index)
84462306a36Sopenharmony_ci{
84562306a36Sopenharmony_ci	struct queue_entry *entry;
84662306a36Sopenharmony_ci	unsigned long irqflags;
84762306a36Sopenharmony_ci
84862306a36Sopenharmony_ci	if (unlikely(index >= Q_INDEX_MAX)) {
84962306a36Sopenharmony_ci		rt2x00_err(queue->rt2x00dev, "Entry requested from invalid index type (%d)\n",
85062306a36Sopenharmony_ci			   index);
85162306a36Sopenharmony_ci		return NULL;
85262306a36Sopenharmony_ci	}
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	spin_lock_irqsave(&queue->index_lock, irqflags);
85562306a36Sopenharmony_ci
85662306a36Sopenharmony_ci	entry = &queue->entries[queue->index[index]];
85762306a36Sopenharmony_ci
85862306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->index_lock, irqflags);
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	return entry;
86162306a36Sopenharmony_ci}
86262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_get_entry);
86362306a36Sopenharmony_ci
86462306a36Sopenharmony_civoid rt2x00queue_index_inc(struct queue_entry *entry, enum queue_index index)
86562306a36Sopenharmony_ci{
86662306a36Sopenharmony_ci	struct data_queue *queue = entry->queue;
86762306a36Sopenharmony_ci	unsigned long irqflags;
86862306a36Sopenharmony_ci
86962306a36Sopenharmony_ci	if (unlikely(index >= Q_INDEX_MAX)) {
87062306a36Sopenharmony_ci		rt2x00_err(queue->rt2x00dev,
87162306a36Sopenharmony_ci			   "Index change on invalid index type (%d)\n", index);
87262306a36Sopenharmony_ci		return;
87362306a36Sopenharmony_ci	}
87462306a36Sopenharmony_ci
87562306a36Sopenharmony_ci	spin_lock_irqsave(&queue->index_lock, irqflags);
87662306a36Sopenharmony_ci
87762306a36Sopenharmony_ci	queue->index[index]++;
87862306a36Sopenharmony_ci	if (queue->index[index] >= queue->limit)
87962306a36Sopenharmony_ci		queue->index[index] = 0;
88062306a36Sopenharmony_ci
88162306a36Sopenharmony_ci	entry->last_action = jiffies;
88262306a36Sopenharmony_ci
88362306a36Sopenharmony_ci	if (index == Q_INDEX) {
88462306a36Sopenharmony_ci		queue->length++;
88562306a36Sopenharmony_ci	} else if (index == Q_INDEX_DONE) {
88662306a36Sopenharmony_ci		queue->length--;
88762306a36Sopenharmony_ci		queue->count++;
88862306a36Sopenharmony_ci	}
88962306a36Sopenharmony_ci
89062306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->index_lock, irqflags);
89162306a36Sopenharmony_ci}
89262306a36Sopenharmony_ci
89362306a36Sopenharmony_cistatic void rt2x00queue_pause_queue_nocheck(struct data_queue *queue)
89462306a36Sopenharmony_ci{
89562306a36Sopenharmony_ci	switch (queue->qid) {
89662306a36Sopenharmony_ci	case QID_AC_VO:
89762306a36Sopenharmony_ci	case QID_AC_VI:
89862306a36Sopenharmony_ci	case QID_AC_BE:
89962306a36Sopenharmony_ci	case QID_AC_BK:
90062306a36Sopenharmony_ci		/*
90162306a36Sopenharmony_ci		 * For TX queues, we have to disable the queue
90262306a36Sopenharmony_ci		 * inside mac80211.
90362306a36Sopenharmony_ci		 */
90462306a36Sopenharmony_ci		ieee80211_stop_queue(queue->rt2x00dev->hw, queue->qid);
90562306a36Sopenharmony_ci		break;
90662306a36Sopenharmony_ci	default:
90762306a36Sopenharmony_ci		break;
90862306a36Sopenharmony_ci	}
90962306a36Sopenharmony_ci}
91062306a36Sopenharmony_civoid rt2x00queue_pause_queue(struct data_queue *queue)
91162306a36Sopenharmony_ci{
91262306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
91362306a36Sopenharmony_ci	    !test_bit(QUEUE_STARTED, &queue->flags) ||
91462306a36Sopenharmony_ci	    test_and_set_bit(QUEUE_PAUSED, &queue->flags))
91562306a36Sopenharmony_ci		return;
91662306a36Sopenharmony_ci
91762306a36Sopenharmony_ci	rt2x00queue_pause_queue_nocheck(queue);
91862306a36Sopenharmony_ci}
91962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_pause_queue);
92062306a36Sopenharmony_ci
92162306a36Sopenharmony_civoid rt2x00queue_unpause_queue(struct data_queue *queue)
92262306a36Sopenharmony_ci{
92362306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
92462306a36Sopenharmony_ci	    !test_bit(QUEUE_STARTED, &queue->flags) ||
92562306a36Sopenharmony_ci	    !test_and_clear_bit(QUEUE_PAUSED, &queue->flags))
92662306a36Sopenharmony_ci		return;
92762306a36Sopenharmony_ci
92862306a36Sopenharmony_ci	switch (queue->qid) {
92962306a36Sopenharmony_ci	case QID_AC_VO:
93062306a36Sopenharmony_ci	case QID_AC_VI:
93162306a36Sopenharmony_ci	case QID_AC_BE:
93262306a36Sopenharmony_ci	case QID_AC_BK:
93362306a36Sopenharmony_ci		/*
93462306a36Sopenharmony_ci		 * For TX queues, we have to enable the queue
93562306a36Sopenharmony_ci		 * inside mac80211.
93662306a36Sopenharmony_ci		 */
93762306a36Sopenharmony_ci		ieee80211_wake_queue(queue->rt2x00dev->hw, queue->qid);
93862306a36Sopenharmony_ci		break;
93962306a36Sopenharmony_ci	case QID_RX:
94062306a36Sopenharmony_ci		/*
94162306a36Sopenharmony_ci		 * For RX we need to kick the queue now in order to
94262306a36Sopenharmony_ci		 * receive frames.
94362306a36Sopenharmony_ci		 */
94462306a36Sopenharmony_ci		queue->rt2x00dev->ops->lib->kick_queue(queue);
94562306a36Sopenharmony_ci		break;
94662306a36Sopenharmony_ci	default:
94762306a36Sopenharmony_ci		break;
94862306a36Sopenharmony_ci	}
94962306a36Sopenharmony_ci}
95062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_unpause_queue);
95162306a36Sopenharmony_ci
95262306a36Sopenharmony_civoid rt2x00queue_start_queue(struct data_queue *queue)
95362306a36Sopenharmony_ci{
95462306a36Sopenharmony_ci	mutex_lock(&queue->status_lock);
95562306a36Sopenharmony_ci
95662306a36Sopenharmony_ci	if (!test_bit(DEVICE_STATE_PRESENT, &queue->rt2x00dev->flags) ||
95762306a36Sopenharmony_ci	    test_and_set_bit(QUEUE_STARTED, &queue->flags)) {
95862306a36Sopenharmony_ci		mutex_unlock(&queue->status_lock);
95962306a36Sopenharmony_ci		return;
96062306a36Sopenharmony_ci	}
96162306a36Sopenharmony_ci
96262306a36Sopenharmony_ci	set_bit(QUEUE_PAUSED, &queue->flags);
96362306a36Sopenharmony_ci
96462306a36Sopenharmony_ci	queue->rt2x00dev->ops->lib->start_queue(queue);
96562306a36Sopenharmony_ci
96662306a36Sopenharmony_ci	rt2x00queue_unpause_queue(queue);
96762306a36Sopenharmony_ci
96862306a36Sopenharmony_ci	mutex_unlock(&queue->status_lock);
96962306a36Sopenharmony_ci}
97062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_start_queue);
97162306a36Sopenharmony_ci
97262306a36Sopenharmony_civoid rt2x00queue_stop_queue(struct data_queue *queue)
97362306a36Sopenharmony_ci{
97462306a36Sopenharmony_ci	mutex_lock(&queue->status_lock);
97562306a36Sopenharmony_ci
97662306a36Sopenharmony_ci	if (!test_and_clear_bit(QUEUE_STARTED, &queue->flags)) {
97762306a36Sopenharmony_ci		mutex_unlock(&queue->status_lock);
97862306a36Sopenharmony_ci		return;
97962306a36Sopenharmony_ci	}
98062306a36Sopenharmony_ci
98162306a36Sopenharmony_ci	rt2x00queue_pause_queue_nocheck(queue);
98262306a36Sopenharmony_ci
98362306a36Sopenharmony_ci	queue->rt2x00dev->ops->lib->stop_queue(queue);
98462306a36Sopenharmony_ci
98562306a36Sopenharmony_ci	mutex_unlock(&queue->status_lock);
98662306a36Sopenharmony_ci}
98762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_stop_queue);
98862306a36Sopenharmony_ci
98962306a36Sopenharmony_civoid rt2x00queue_flush_queue(struct data_queue *queue, bool drop)
99062306a36Sopenharmony_ci{
99162306a36Sopenharmony_ci	bool tx_queue =
99262306a36Sopenharmony_ci		(queue->qid == QID_AC_VO) ||
99362306a36Sopenharmony_ci		(queue->qid == QID_AC_VI) ||
99462306a36Sopenharmony_ci		(queue->qid == QID_AC_BE) ||
99562306a36Sopenharmony_ci		(queue->qid == QID_AC_BK);
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	if (rt2x00queue_empty(queue))
99862306a36Sopenharmony_ci		return;
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	/*
100162306a36Sopenharmony_ci	 * If we are not supposed to drop any pending
100262306a36Sopenharmony_ci	 * frames, this means we must force a start (=kick)
100362306a36Sopenharmony_ci	 * to the queue to make sure the hardware will
100462306a36Sopenharmony_ci	 * start transmitting.
100562306a36Sopenharmony_ci	 */
100662306a36Sopenharmony_ci	if (!drop && tx_queue)
100762306a36Sopenharmony_ci		queue->rt2x00dev->ops->lib->kick_queue(queue);
100862306a36Sopenharmony_ci
100962306a36Sopenharmony_ci	/*
101062306a36Sopenharmony_ci	 * Check if driver supports flushing, if that is the case we can
101162306a36Sopenharmony_ci	 * defer the flushing to the driver. Otherwise we must use the
101262306a36Sopenharmony_ci	 * alternative which just waits for the queue to become empty.
101362306a36Sopenharmony_ci	 */
101462306a36Sopenharmony_ci	if (likely(queue->rt2x00dev->ops->lib->flush_queue))
101562306a36Sopenharmony_ci		queue->rt2x00dev->ops->lib->flush_queue(queue, drop);
101662306a36Sopenharmony_ci
101762306a36Sopenharmony_ci	/*
101862306a36Sopenharmony_ci	 * The queue flush has failed...
101962306a36Sopenharmony_ci	 */
102062306a36Sopenharmony_ci	if (unlikely(!rt2x00queue_empty(queue)))
102162306a36Sopenharmony_ci		rt2x00_warn(queue->rt2x00dev, "Queue %d failed to flush\n",
102262306a36Sopenharmony_ci			    queue->qid);
102362306a36Sopenharmony_ci}
102462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_flush_queue);
102562306a36Sopenharmony_ci
102662306a36Sopenharmony_civoid rt2x00queue_start_queues(struct rt2x00_dev *rt2x00dev)
102762306a36Sopenharmony_ci{
102862306a36Sopenharmony_ci	struct data_queue *queue;
102962306a36Sopenharmony_ci
103062306a36Sopenharmony_ci	/*
103162306a36Sopenharmony_ci	 * rt2x00queue_start_queue will call ieee80211_wake_queue
103262306a36Sopenharmony_ci	 * for each queue after is has been properly initialized.
103362306a36Sopenharmony_ci	 */
103462306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue)
103562306a36Sopenharmony_ci		rt2x00queue_start_queue(queue);
103662306a36Sopenharmony_ci
103762306a36Sopenharmony_ci	rt2x00queue_start_queue(rt2x00dev->rx);
103862306a36Sopenharmony_ci}
103962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_start_queues);
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_civoid rt2x00queue_stop_queues(struct rt2x00_dev *rt2x00dev)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct data_queue *queue;
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	/*
104662306a36Sopenharmony_ci	 * rt2x00queue_stop_queue will call ieee80211_stop_queue
104762306a36Sopenharmony_ci	 * as well, but we are completely shutting doing everything
104862306a36Sopenharmony_ci	 * now, so it is much safer to stop all TX queues at once,
104962306a36Sopenharmony_ci	 * and use rt2x00queue_stop_queue for cleaning up.
105062306a36Sopenharmony_ci	 */
105162306a36Sopenharmony_ci	ieee80211_stop_queues(rt2x00dev->hw);
105262306a36Sopenharmony_ci
105362306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue)
105462306a36Sopenharmony_ci		rt2x00queue_stop_queue(queue);
105562306a36Sopenharmony_ci
105662306a36Sopenharmony_ci	rt2x00queue_stop_queue(rt2x00dev->rx);
105762306a36Sopenharmony_ci}
105862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_stop_queues);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_civoid rt2x00queue_flush_queues(struct rt2x00_dev *rt2x00dev, bool drop)
106162306a36Sopenharmony_ci{
106262306a36Sopenharmony_ci	struct data_queue *queue;
106362306a36Sopenharmony_ci
106462306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue)
106562306a36Sopenharmony_ci		rt2x00queue_flush_queue(queue, drop);
106662306a36Sopenharmony_ci
106762306a36Sopenharmony_ci	rt2x00queue_flush_queue(rt2x00dev->rx, drop);
106862306a36Sopenharmony_ci}
106962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00queue_flush_queues);
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic void rt2x00queue_reset(struct data_queue *queue)
107262306a36Sopenharmony_ci{
107362306a36Sopenharmony_ci	unsigned long irqflags;
107462306a36Sopenharmony_ci	unsigned int i;
107562306a36Sopenharmony_ci
107662306a36Sopenharmony_ci	spin_lock_irqsave(&queue->index_lock, irqflags);
107762306a36Sopenharmony_ci
107862306a36Sopenharmony_ci	queue->count = 0;
107962306a36Sopenharmony_ci	queue->length = 0;
108062306a36Sopenharmony_ci
108162306a36Sopenharmony_ci	for (i = 0; i < Q_INDEX_MAX; i++)
108262306a36Sopenharmony_ci		queue->index[i] = 0;
108362306a36Sopenharmony_ci
108462306a36Sopenharmony_ci	spin_unlock_irqrestore(&queue->index_lock, irqflags);
108562306a36Sopenharmony_ci}
108662306a36Sopenharmony_ci
108762306a36Sopenharmony_civoid rt2x00queue_init_queues(struct rt2x00_dev *rt2x00dev)
108862306a36Sopenharmony_ci{
108962306a36Sopenharmony_ci	struct data_queue *queue;
109062306a36Sopenharmony_ci	unsigned int i;
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_ci	queue_for_each(rt2x00dev, queue) {
109362306a36Sopenharmony_ci		rt2x00queue_reset(queue);
109462306a36Sopenharmony_ci
109562306a36Sopenharmony_ci		for (i = 0; i < queue->limit; i++)
109662306a36Sopenharmony_ci			rt2x00dev->ops->lib->clear_entry(&queue->entries[i]);
109762306a36Sopenharmony_ci	}
109862306a36Sopenharmony_ci}
109962306a36Sopenharmony_ci
110062306a36Sopenharmony_cistatic int rt2x00queue_alloc_entries(struct data_queue *queue)
110162306a36Sopenharmony_ci{
110262306a36Sopenharmony_ci	struct queue_entry *entries;
110362306a36Sopenharmony_ci	unsigned int entry_size;
110462306a36Sopenharmony_ci	unsigned int i;
110562306a36Sopenharmony_ci
110662306a36Sopenharmony_ci	rt2x00queue_reset(queue);
110762306a36Sopenharmony_ci
110862306a36Sopenharmony_ci	/*
110962306a36Sopenharmony_ci	 * Allocate all queue entries.
111062306a36Sopenharmony_ci	 */
111162306a36Sopenharmony_ci	entry_size = sizeof(*entries) + queue->priv_size;
111262306a36Sopenharmony_ci	entries = kcalloc(queue->limit, entry_size, GFP_KERNEL);
111362306a36Sopenharmony_ci	if (!entries)
111462306a36Sopenharmony_ci		return -ENOMEM;
111562306a36Sopenharmony_ci
111662306a36Sopenharmony_ci#define QUEUE_ENTRY_PRIV_OFFSET(__base, __index, __limit, __esize, __psize) \
111762306a36Sopenharmony_ci	(((char *)(__base)) + ((__limit) * (__esize)) + \
111862306a36Sopenharmony_ci	    ((__index) * (__psize)))
111962306a36Sopenharmony_ci
112062306a36Sopenharmony_ci	for (i = 0; i < queue->limit; i++) {
112162306a36Sopenharmony_ci		entries[i].flags = 0;
112262306a36Sopenharmony_ci		entries[i].queue = queue;
112362306a36Sopenharmony_ci		entries[i].skb = NULL;
112462306a36Sopenharmony_ci		entries[i].entry_idx = i;
112562306a36Sopenharmony_ci		entries[i].priv_data =
112662306a36Sopenharmony_ci		    QUEUE_ENTRY_PRIV_OFFSET(entries, i, queue->limit,
112762306a36Sopenharmony_ci					    sizeof(*entries), queue->priv_size);
112862306a36Sopenharmony_ci	}
112962306a36Sopenharmony_ci
113062306a36Sopenharmony_ci#undef QUEUE_ENTRY_PRIV_OFFSET
113162306a36Sopenharmony_ci
113262306a36Sopenharmony_ci	queue->entries = entries;
113362306a36Sopenharmony_ci
113462306a36Sopenharmony_ci	return 0;
113562306a36Sopenharmony_ci}
113662306a36Sopenharmony_ci
113762306a36Sopenharmony_cistatic void rt2x00queue_free_skbs(struct data_queue *queue)
113862306a36Sopenharmony_ci{
113962306a36Sopenharmony_ci	unsigned int i;
114062306a36Sopenharmony_ci
114162306a36Sopenharmony_ci	if (!queue->entries)
114262306a36Sopenharmony_ci		return;
114362306a36Sopenharmony_ci
114462306a36Sopenharmony_ci	for (i = 0; i < queue->limit; i++) {
114562306a36Sopenharmony_ci		rt2x00queue_free_skb(&queue->entries[i]);
114662306a36Sopenharmony_ci	}
114762306a36Sopenharmony_ci}
114862306a36Sopenharmony_ci
114962306a36Sopenharmony_cistatic int rt2x00queue_alloc_rxskbs(struct data_queue *queue)
115062306a36Sopenharmony_ci{
115162306a36Sopenharmony_ci	unsigned int i;
115262306a36Sopenharmony_ci	struct sk_buff *skb;
115362306a36Sopenharmony_ci
115462306a36Sopenharmony_ci	for (i = 0; i < queue->limit; i++) {
115562306a36Sopenharmony_ci		skb = rt2x00queue_alloc_rxskb(&queue->entries[i], GFP_KERNEL);
115662306a36Sopenharmony_ci		if (!skb)
115762306a36Sopenharmony_ci			return -ENOMEM;
115862306a36Sopenharmony_ci		queue->entries[i].skb = skb;
115962306a36Sopenharmony_ci	}
116062306a36Sopenharmony_ci
116162306a36Sopenharmony_ci	return 0;
116262306a36Sopenharmony_ci}
116362306a36Sopenharmony_ci
116462306a36Sopenharmony_ciint rt2x00queue_initialize(struct rt2x00_dev *rt2x00dev)
116562306a36Sopenharmony_ci{
116662306a36Sopenharmony_ci	struct data_queue *queue;
116762306a36Sopenharmony_ci	int status;
116862306a36Sopenharmony_ci
116962306a36Sopenharmony_ci	status = rt2x00queue_alloc_entries(rt2x00dev->rx);
117062306a36Sopenharmony_ci	if (status)
117162306a36Sopenharmony_ci		goto exit;
117262306a36Sopenharmony_ci
117362306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue) {
117462306a36Sopenharmony_ci		status = rt2x00queue_alloc_entries(queue);
117562306a36Sopenharmony_ci		if (status)
117662306a36Sopenharmony_ci			goto exit;
117762306a36Sopenharmony_ci	}
117862306a36Sopenharmony_ci
117962306a36Sopenharmony_ci	status = rt2x00queue_alloc_entries(rt2x00dev->bcn);
118062306a36Sopenharmony_ci	if (status)
118162306a36Sopenharmony_ci		goto exit;
118262306a36Sopenharmony_ci
118362306a36Sopenharmony_ci	if (rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) {
118462306a36Sopenharmony_ci		status = rt2x00queue_alloc_entries(rt2x00dev->atim);
118562306a36Sopenharmony_ci		if (status)
118662306a36Sopenharmony_ci			goto exit;
118762306a36Sopenharmony_ci	}
118862306a36Sopenharmony_ci
118962306a36Sopenharmony_ci	status = rt2x00queue_alloc_rxskbs(rt2x00dev->rx);
119062306a36Sopenharmony_ci	if (status)
119162306a36Sopenharmony_ci		goto exit;
119262306a36Sopenharmony_ci
119362306a36Sopenharmony_ci	return 0;
119462306a36Sopenharmony_ci
119562306a36Sopenharmony_ciexit:
119662306a36Sopenharmony_ci	rt2x00_err(rt2x00dev, "Queue entries allocation failed\n");
119762306a36Sopenharmony_ci
119862306a36Sopenharmony_ci	rt2x00queue_uninitialize(rt2x00dev);
119962306a36Sopenharmony_ci
120062306a36Sopenharmony_ci	return status;
120162306a36Sopenharmony_ci}
120262306a36Sopenharmony_ci
120362306a36Sopenharmony_civoid rt2x00queue_uninitialize(struct rt2x00_dev *rt2x00dev)
120462306a36Sopenharmony_ci{
120562306a36Sopenharmony_ci	struct data_queue *queue;
120662306a36Sopenharmony_ci
120762306a36Sopenharmony_ci	rt2x00queue_free_skbs(rt2x00dev->rx);
120862306a36Sopenharmony_ci
120962306a36Sopenharmony_ci	queue_for_each(rt2x00dev, queue) {
121062306a36Sopenharmony_ci		kfree(queue->entries);
121162306a36Sopenharmony_ci		queue->entries = NULL;
121262306a36Sopenharmony_ci	}
121362306a36Sopenharmony_ci}
121462306a36Sopenharmony_ci
121562306a36Sopenharmony_cistatic void rt2x00queue_init(struct rt2x00_dev *rt2x00dev,
121662306a36Sopenharmony_ci			     struct data_queue *queue, enum data_queue_qid qid)
121762306a36Sopenharmony_ci{
121862306a36Sopenharmony_ci	mutex_init(&queue->status_lock);
121962306a36Sopenharmony_ci	spin_lock_init(&queue->tx_lock);
122062306a36Sopenharmony_ci	spin_lock_init(&queue->index_lock);
122162306a36Sopenharmony_ci
122262306a36Sopenharmony_ci	queue->rt2x00dev = rt2x00dev;
122362306a36Sopenharmony_ci	queue->qid = qid;
122462306a36Sopenharmony_ci	queue->txop = 0;
122562306a36Sopenharmony_ci	queue->aifs = 2;
122662306a36Sopenharmony_ci	queue->cw_min = 5;
122762306a36Sopenharmony_ci	queue->cw_max = 10;
122862306a36Sopenharmony_ci
122962306a36Sopenharmony_ci	rt2x00dev->ops->queue_init(queue);
123062306a36Sopenharmony_ci
123162306a36Sopenharmony_ci	queue->threshold = DIV_ROUND_UP(queue->limit, 10);
123262306a36Sopenharmony_ci}
123362306a36Sopenharmony_ci
123462306a36Sopenharmony_ciint rt2x00queue_allocate(struct rt2x00_dev *rt2x00dev)
123562306a36Sopenharmony_ci{
123662306a36Sopenharmony_ci	struct data_queue *queue;
123762306a36Sopenharmony_ci	enum data_queue_qid qid;
123862306a36Sopenharmony_ci	unsigned int req_atim =
123962306a36Sopenharmony_ci	    rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE);
124062306a36Sopenharmony_ci
124162306a36Sopenharmony_ci	/*
124262306a36Sopenharmony_ci	 * We need the following queues:
124362306a36Sopenharmony_ci	 * RX: 1
124462306a36Sopenharmony_ci	 * TX: ops->tx_queues
124562306a36Sopenharmony_ci	 * Beacon: 1
124662306a36Sopenharmony_ci	 * Atim: 1 (if required)
124762306a36Sopenharmony_ci	 */
124862306a36Sopenharmony_ci	rt2x00dev->data_queues = 2 + rt2x00dev->ops->tx_queues + req_atim;
124962306a36Sopenharmony_ci
125062306a36Sopenharmony_ci	queue = kcalloc(rt2x00dev->data_queues, sizeof(*queue), GFP_KERNEL);
125162306a36Sopenharmony_ci	if (!queue)
125262306a36Sopenharmony_ci		return -ENOMEM;
125362306a36Sopenharmony_ci
125462306a36Sopenharmony_ci	/*
125562306a36Sopenharmony_ci	 * Initialize pointers
125662306a36Sopenharmony_ci	 */
125762306a36Sopenharmony_ci	rt2x00dev->rx = queue;
125862306a36Sopenharmony_ci	rt2x00dev->tx = &queue[1];
125962306a36Sopenharmony_ci	rt2x00dev->bcn = &queue[1 + rt2x00dev->ops->tx_queues];
126062306a36Sopenharmony_ci	rt2x00dev->atim = req_atim ? &queue[2 + rt2x00dev->ops->tx_queues] : NULL;
126162306a36Sopenharmony_ci
126262306a36Sopenharmony_ci	/*
126362306a36Sopenharmony_ci	 * Initialize queue parameters.
126462306a36Sopenharmony_ci	 * RX: qid = QID_RX
126562306a36Sopenharmony_ci	 * TX: qid = QID_AC_VO + index
126662306a36Sopenharmony_ci	 * TX: cw_min: 2^5 = 32.
126762306a36Sopenharmony_ci	 * TX: cw_max: 2^10 = 1024.
126862306a36Sopenharmony_ci	 * BCN: qid = QID_BEACON
126962306a36Sopenharmony_ci	 * ATIM: qid = QID_ATIM
127062306a36Sopenharmony_ci	 */
127162306a36Sopenharmony_ci	rt2x00queue_init(rt2x00dev, rt2x00dev->rx, QID_RX);
127262306a36Sopenharmony_ci
127362306a36Sopenharmony_ci	qid = QID_AC_VO;
127462306a36Sopenharmony_ci	tx_queue_for_each(rt2x00dev, queue)
127562306a36Sopenharmony_ci		rt2x00queue_init(rt2x00dev, queue, qid++);
127662306a36Sopenharmony_ci
127762306a36Sopenharmony_ci	rt2x00queue_init(rt2x00dev, rt2x00dev->bcn, QID_BEACON);
127862306a36Sopenharmony_ci	if (req_atim)
127962306a36Sopenharmony_ci		rt2x00queue_init(rt2x00dev, rt2x00dev->atim, QID_ATIM);
128062306a36Sopenharmony_ci
128162306a36Sopenharmony_ci	return 0;
128262306a36Sopenharmony_ci}
128362306a36Sopenharmony_ci
128462306a36Sopenharmony_civoid rt2x00queue_free(struct rt2x00_dev *rt2x00dev)
128562306a36Sopenharmony_ci{
128662306a36Sopenharmony_ci	kfree(rt2x00dev->rx);
128762306a36Sopenharmony_ci	rt2x00dev->rx = NULL;
128862306a36Sopenharmony_ci	rt2x00dev->tx = NULL;
128962306a36Sopenharmony_ci	rt2x00dev->bcn = NULL;
129062306a36Sopenharmony_ci}
1291