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