162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 462306a36Sopenharmony_ci <http://rt2x00.serialmonkey.com> 562306a36Sopenharmony_ci 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci Module: rt2x00mac 1062306a36Sopenharmony_ci Abstract: rt2x00 generic mac80211 routines. 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ci#include <linux/kernel.h> 1462306a36Sopenharmony_ci#include <linux/module.h> 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include "rt2x00.h" 1762306a36Sopenharmony_ci#include "rt2x00lib.h" 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_cistatic int rt2x00mac_tx_rts_cts(struct rt2x00_dev *rt2x00dev, 2062306a36Sopenharmony_ci struct data_queue *queue, 2162306a36Sopenharmony_ci struct sk_buff *frag_skb) 2262306a36Sopenharmony_ci{ 2362306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(frag_skb); 2462306a36Sopenharmony_ci struct ieee80211_tx_info *rts_info; 2562306a36Sopenharmony_ci struct sk_buff *skb; 2662306a36Sopenharmony_ci unsigned int data_length; 2762306a36Sopenharmony_ci int retval = 0; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_ci if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 3062306a36Sopenharmony_ci data_length = sizeof(struct ieee80211_cts); 3162306a36Sopenharmony_ci else 3262306a36Sopenharmony_ci data_length = sizeof(struct ieee80211_rts); 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci skb = dev_alloc_skb(data_length + rt2x00dev->hw->extra_tx_headroom); 3562306a36Sopenharmony_ci if (unlikely(!skb)) { 3662306a36Sopenharmony_ci rt2x00_warn(rt2x00dev, "Failed to create RTS/CTS frame\n"); 3762306a36Sopenharmony_ci return -ENOMEM; 3862306a36Sopenharmony_ci } 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci skb_reserve(skb, rt2x00dev->hw->extra_tx_headroom); 4162306a36Sopenharmony_ci skb_put(skb, data_length); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* 4462306a36Sopenharmony_ci * Copy TX information over from original frame to 4562306a36Sopenharmony_ci * RTS/CTS frame. Note that we set the no encryption flag 4662306a36Sopenharmony_ci * since we don't want this frame to be encrypted. 4762306a36Sopenharmony_ci * RTS frames should be acked, while CTS-to-self frames 4862306a36Sopenharmony_ci * should not. The ready for TX flag is cleared to prevent 4962306a36Sopenharmony_ci * it being automatically send when the descriptor is 5062306a36Sopenharmony_ci * written to the hardware. 5162306a36Sopenharmony_ci */ 5262306a36Sopenharmony_ci memcpy(skb->cb, frag_skb->cb, sizeof(skb->cb)); 5362306a36Sopenharmony_ci rts_info = IEEE80211_SKB_CB(skb); 5462306a36Sopenharmony_ci rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_RTS_CTS; 5562306a36Sopenharmony_ci rts_info->control.rates[0].flags &= ~IEEE80211_TX_RC_USE_CTS_PROTECT; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 5862306a36Sopenharmony_ci rts_info->flags |= IEEE80211_TX_CTL_NO_ACK; 5962306a36Sopenharmony_ci else 6062306a36Sopenharmony_ci rts_info->flags &= ~IEEE80211_TX_CTL_NO_ACK; 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci /* Disable hardware encryption */ 6362306a36Sopenharmony_ci rts_info->control.hw_key = NULL; 6462306a36Sopenharmony_ci 6562306a36Sopenharmony_ci /* 6662306a36Sopenharmony_ci * RTS/CTS frame should use the length of the frame plus any 6762306a36Sopenharmony_ci * encryption overhead that will be added by the hardware. 6862306a36Sopenharmony_ci */ 6962306a36Sopenharmony_ci data_length += rt2x00crypto_tx_overhead(rt2x00dev, skb); 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci if (tx_info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) 7262306a36Sopenharmony_ci ieee80211_ctstoself_get(rt2x00dev->hw, tx_info->control.vif, 7362306a36Sopenharmony_ci frag_skb->data, data_length, tx_info, 7462306a36Sopenharmony_ci (struct ieee80211_cts *)(skb->data)); 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci ieee80211_rts_get(rt2x00dev->hw, tx_info->control.vif, 7762306a36Sopenharmony_ci frag_skb->data, data_length, tx_info, 7862306a36Sopenharmony_ci (struct ieee80211_rts *)(skb->data)); 7962306a36Sopenharmony_ci 8062306a36Sopenharmony_ci retval = rt2x00queue_write_tx_frame(queue, skb, NULL, true); 8162306a36Sopenharmony_ci if (retval) { 8262306a36Sopenharmony_ci dev_kfree_skb_any(skb); 8362306a36Sopenharmony_ci rt2x00_warn(rt2x00dev, "Failed to send RTS/CTS frame\n"); 8462306a36Sopenharmony_ci } 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci return retval; 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_civoid rt2x00mac_tx(struct ieee80211_hw *hw, 9062306a36Sopenharmony_ci struct ieee80211_tx_control *control, 9162306a36Sopenharmony_ci struct sk_buff *skb) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 9462306a36Sopenharmony_ci struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb); 9562306a36Sopenharmony_ci enum data_queue_qid qid = skb_get_queue_mapping(skb); 9662306a36Sopenharmony_ci struct data_queue *queue = NULL; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* 9962306a36Sopenharmony_ci * Mac80211 might be calling this function while we are trying 10062306a36Sopenharmony_ci * to remove the device or perhaps suspending it. 10162306a36Sopenharmony_ci * Note that we can only stop the TX queues inside the TX path 10262306a36Sopenharmony_ci * due to possible race conditions in mac80211. 10362306a36Sopenharmony_ci */ 10462306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 10562306a36Sopenharmony_ci goto exit_free_skb; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci /* 10862306a36Sopenharmony_ci * Use the ATIM queue if appropriate and present. 10962306a36Sopenharmony_ci */ 11062306a36Sopenharmony_ci if (tx_info->flags & IEEE80211_TX_CTL_SEND_AFTER_DTIM && 11162306a36Sopenharmony_ci rt2x00_has_cap_flag(rt2x00dev, REQUIRE_ATIM_QUEUE)) 11262306a36Sopenharmony_ci qid = QID_ATIM; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, qid); 11562306a36Sopenharmony_ci if (unlikely(!queue)) { 11662306a36Sopenharmony_ci rt2x00_err(rt2x00dev, 11762306a36Sopenharmony_ci "Attempt to send packet over invalid queue %d\n" 11862306a36Sopenharmony_ci "Please file bug report to %s\n", qid, DRV_PROJECT); 11962306a36Sopenharmony_ci goto exit_free_skb; 12062306a36Sopenharmony_ci } 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci /* 12362306a36Sopenharmony_ci * If CTS/RTS is required. create and queue that frame first. 12462306a36Sopenharmony_ci * Make sure we have at least enough entries available to send 12562306a36Sopenharmony_ci * this CTS/RTS frame as well as the data frame. 12662306a36Sopenharmony_ci * Note that when the driver has set the set_rts_threshold() 12762306a36Sopenharmony_ci * callback function it doesn't need software generation of 12862306a36Sopenharmony_ci * either RTS or CTS-to-self frame and handles everything 12962306a36Sopenharmony_ci * inside the hardware. 13062306a36Sopenharmony_ci */ 13162306a36Sopenharmony_ci if (!rt2x00dev->ops->hw->set_rts_threshold && 13262306a36Sopenharmony_ci (tx_info->control.rates[0].flags & (IEEE80211_TX_RC_USE_RTS_CTS | 13362306a36Sopenharmony_ci IEEE80211_TX_RC_USE_CTS_PROTECT))) { 13462306a36Sopenharmony_ci if (rt2x00queue_available(queue) <= 1) { 13562306a36Sopenharmony_ci /* 13662306a36Sopenharmony_ci * Recheck for full queue under lock to avoid race 13762306a36Sopenharmony_ci * conditions with rt2x00lib_txdone(). 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci spin_lock(&queue->tx_lock); 14062306a36Sopenharmony_ci if (rt2x00queue_threshold(queue)) 14162306a36Sopenharmony_ci rt2x00queue_pause_queue(queue); 14262306a36Sopenharmony_ci spin_unlock(&queue->tx_lock); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci goto exit_free_skb; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci if (rt2x00mac_tx_rts_cts(rt2x00dev, queue, skb)) 14862306a36Sopenharmony_ci goto exit_free_skb; 14962306a36Sopenharmony_ci } 15062306a36Sopenharmony_ci 15162306a36Sopenharmony_ci if (unlikely(rt2x00queue_write_tx_frame(queue, skb, control->sta, false))) 15262306a36Sopenharmony_ci goto exit_free_skb; 15362306a36Sopenharmony_ci 15462306a36Sopenharmony_ci return; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci exit_free_skb: 15762306a36Sopenharmony_ci ieee80211_free_txskb(hw, skb); 15862306a36Sopenharmony_ci} 15962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_tx); 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_ciint rt2x00mac_start(struct ieee80211_hw *hw) 16262306a36Sopenharmony_ci{ 16362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 16462306a36Sopenharmony_ci 16562306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 16662306a36Sopenharmony_ci return 0; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) { 16962306a36Sopenharmony_ci /* 17062306a36Sopenharmony_ci * This is special case for ieee80211_restart_hw(), otherwise 17162306a36Sopenharmony_ci * mac80211 never call start() two times in row without stop(); 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_ci set_bit(DEVICE_STATE_RESET, &rt2x00dev->flags); 17462306a36Sopenharmony_ci rt2x00dev->ops->lib->pre_reset_hw(rt2x00dev); 17562306a36Sopenharmony_ci rt2x00lib_stop(rt2x00dev); 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci return rt2x00lib_start(rt2x00dev); 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_start); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_civoid rt2x00mac_stop(struct ieee80211_hw *hw) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 18662306a36Sopenharmony_ci return; 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci rt2x00lib_stop(rt2x00dev); 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_stop); 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_civoid 19362306a36Sopenharmony_cirt2x00mac_reconfig_complete(struct ieee80211_hw *hw, 19462306a36Sopenharmony_ci enum ieee80211_reconfig_type reconfig_type) 19562306a36Sopenharmony_ci{ 19662306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 19762306a36Sopenharmony_ci 19862306a36Sopenharmony_ci if (reconfig_type == IEEE80211_RECONFIG_TYPE_RESTART) 19962306a36Sopenharmony_ci clear_bit(DEVICE_STATE_RESET, &rt2x00dev->flags); 20062306a36Sopenharmony_ci} 20162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_reconfig_complete); 20262306a36Sopenharmony_ci 20362306a36Sopenharmony_ciint rt2x00mac_add_interface(struct ieee80211_hw *hw, 20462306a36Sopenharmony_ci struct ieee80211_vif *vif) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 20762306a36Sopenharmony_ci struct rt2x00_intf *intf = vif_to_intf(vif); 20862306a36Sopenharmony_ci struct data_queue *queue = rt2x00dev->bcn; 20962306a36Sopenharmony_ci struct queue_entry *entry = NULL; 21062306a36Sopenharmony_ci unsigned int i; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci /* 21362306a36Sopenharmony_ci * Don't allow interfaces to be added 21462306a36Sopenharmony_ci * the device has disappeared. 21562306a36Sopenharmony_ci */ 21662306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || 21762306a36Sopenharmony_ci !test_bit(DEVICE_STATE_STARTED, &rt2x00dev->flags)) 21862306a36Sopenharmony_ci return -ENODEV; 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci /* 22162306a36Sopenharmony_ci * Loop through all beacon queues to find a free 22262306a36Sopenharmony_ci * entry. Since there are as much beacon entries 22362306a36Sopenharmony_ci * as the maximum interfaces, this search shouldn't 22462306a36Sopenharmony_ci * fail. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci for (i = 0; i < queue->limit; i++) { 22762306a36Sopenharmony_ci entry = &queue->entries[i]; 22862306a36Sopenharmony_ci if (!test_and_set_bit(ENTRY_BCN_ASSIGNED, &entry->flags)) 22962306a36Sopenharmony_ci break; 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci if (unlikely(i == queue->limit)) 23362306a36Sopenharmony_ci return -ENOBUFS; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci /* 23662306a36Sopenharmony_ci * We are now absolutely sure the interface can be created, 23762306a36Sopenharmony_ci * increase interface count and start initialization. 23862306a36Sopenharmony_ci */ 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) 24162306a36Sopenharmony_ci rt2x00dev->intf_ap_count++; 24262306a36Sopenharmony_ci else 24362306a36Sopenharmony_ci rt2x00dev->intf_sta_count++; 24462306a36Sopenharmony_ci 24562306a36Sopenharmony_ci mutex_init(&intf->beacon_skb_mutex); 24662306a36Sopenharmony_ci intf->beacon = entry; 24762306a36Sopenharmony_ci 24862306a36Sopenharmony_ci /* 24962306a36Sopenharmony_ci * The MAC address must be configured after the device 25062306a36Sopenharmony_ci * has been initialized. Otherwise the device can reset 25162306a36Sopenharmony_ci * the MAC registers. 25262306a36Sopenharmony_ci * The BSSID address must only be configured in AP mode, 25362306a36Sopenharmony_ci * however we should not send an empty BSSID address for 25462306a36Sopenharmony_ci * STA interfaces at this time, since this can cause 25562306a36Sopenharmony_ci * invalid behavior in the device. 25662306a36Sopenharmony_ci */ 25762306a36Sopenharmony_ci rt2x00lib_config_intf(rt2x00dev, intf, vif->type, 25862306a36Sopenharmony_ci vif->addr, NULL); 25962306a36Sopenharmony_ci 26062306a36Sopenharmony_ci /* 26162306a36Sopenharmony_ci * Some filters depend on the current working mode. We can force 26262306a36Sopenharmony_ci * an update during the next configure_filter() run by mac80211 by 26362306a36Sopenharmony_ci * resetting the current packet_filter state. 26462306a36Sopenharmony_ci */ 26562306a36Sopenharmony_ci rt2x00dev->packet_filter = 0; 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return 0; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_add_interface); 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_civoid rt2x00mac_remove_interface(struct ieee80211_hw *hw, 27262306a36Sopenharmony_ci struct ieee80211_vif *vif) 27362306a36Sopenharmony_ci{ 27462306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 27562306a36Sopenharmony_ci struct rt2x00_intf *intf = vif_to_intf(vif); 27662306a36Sopenharmony_ci 27762306a36Sopenharmony_ci /* 27862306a36Sopenharmony_ci * Don't allow interfaces to be remove while 27962306a36Sopenharmony_ci * either the device has disappeared or when 28062306a36Sopenharmony_ci * no interface is present. 28162306a36Sopenharmony_ci */ 28262306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) || 28362306a36Sopenharmony_ci (vif->type == NL80211_IFTYPE_AP && !rt2x00dev->intf_ap_count) || 28462306a36Sopenharmony_ci (vif->type != NL80211_IFTYPE_AP && !rt2x00dev->intf_sta_count)) 28562306a36Sopenharmony_ci return; 28662306a36Sopenharmony_ci 28762306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_AP) 28862306a36Sopenharmony_ci rt2x00dev->intf_ap_count--; 28962306a36Sopenharmony_ci else 29062306a36Sopenharmony_ci rt2x00dev->intf_sta_count--; 29162306a36Sopenharmony_ci 29262306a36Sopenharmony_ci /* 29362306a36Sopenharmony_ci * Release beacon entry so it is available for 29462306a36Sopenharmony_ci * new interfaces again. 29562306a36Sopenharmony_ci */ 29662306a36Sopenharmony_ci clear_bit(ENTRY_BCN_ASSIGNED, &intf->beacon->flags); 29762306a36Sopenharmony_ci 29862306a36Sopenharmony_ci /* 29962306a36Sopenharmony_ci * Make sure the bssid and mac address registers 30062306a36Sopenharmony_ci * are cleared to prevent false ACKing of frames. 30162306a36Sopenharmony_ci */ 30262306a36Sopenharmony_ci rt2x00lib_config_intf(rt2x00dev, intf, 30362306a36Sopenharmony_ci NL80211_IFTYPE_UNSPECIFIED, NULL, NULL); 30462306a36Sopenharmony_ci} 30562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_remove_interface); 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciint rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 31062306a36Sopenharmony_ci struct ieee80211_conf *conf = &hw->conf; 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci /* 31362306a36Sopenharmony_ci * mac80211 might be calling this function while we are trying 31462306a36Sopenharmony_ci * to remove the device or perhaps suspending it. 31562306a36Sopenharmony_ci */ 31662306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 31762306a36Sopenharmony_ci return 0; 31862306a36Sopenharmony_ci 31962306a36Sopenharmony_ci /* 32062306a36Sopenharmony_ci * Some configuration parameters (e.g. channel and antenna values) can 32162306a36Sopenharmony_ci * only be set when the radio is enabled, but do require the RX to 32262306a36Sopenharmony_ci * be off. During this period we should keep link tuning enabled, 32362306a36Sopenharmony_ci * if for any reason the link tuner must be reset, this will be 32462306a36Sopenharmony_ci * handled by rt2x00lib_config(). 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci rt2x00queue_stop_queue(rt2x00dev->rx); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci /* Do not race with link tuner. */ 32962306a36Sopenharmony_ci mutex_lock(&rt2x00dev->conf_mutex); 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci /* 33262306a36Sopenharmony_ci * When we've just turned on the radio, we want to reprogram 33362306a36Sopenharmony_ci * everything to ensure a consistent state 33462306a36Sopenharmony_ci */ 33562306a36Sopenharmony_ci rt2x00lib_config(rt2x00dev, conf, changed); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * After the radio has been enabled we need to configure 33962306a36Sopenharmony_ci * the antenna to the default settings. rt2x00lib_config_antenna() 34062306a36Sopenharmony_ci * should determine if any action should be taken based on 34162306a36Sopenharmony_ci * checking if diversity has been enabled or no antenna changes 34262306a36Sopenharmony_ci * have been made since the last configuration change. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci rt2x00lib_config_antenna(rt2x00dev, rt2x00dev->default_ant); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci mutex_unlock(&rt2x00dev->conf_mutex); 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci /* Turn RX back on */ 34962306a36Sopenharmony_ci rt2x00queue_start_queue(rt2x00dev->rx); 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_ci return 0; 35262306a36Sopenharmony_ci} 35362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_config); 35462306a36Sopenharmony_ci 35562306a36Sopenharmony_civoid rt2x00mac_configure_filter(struct ieee80211_hw *hw, 35662306a36Sopenharmony_ci unsigned int changed_flags, 35762306a36Sopenharmony_ci unsigned int *total_flags, 35862306a36Sopenharmony_ci u64 multicast) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci /* 36362306a36Sopenharmony_ci * Mask off any flags we are going to ignore 36462306a36Sopenharmony_ci * from the total_flags field. 36562306a36Sopenharmony_ci */ 36662306a36Sopenharmony_ci *total_flags &= 36762306a36Sopenharmony_ci FIF_ALLMULTI | 36862306a36Sopenharmony_ci FIF_FCSFAIL | 36962306a36Sopenharmony_ci FIF_PLCPFAIL | 37062306a36Sopenharmony_ci FIF_CONTROL | 37162306a36Sopenharmony_ci FIF_PSPOLL | 37262306a36Sopenharmony_ci FIF_OTHER_BSS; 37362306a36Sopenharmony_ci 37462306a36Sopenharmony_ci /* 37562306a36Sopenharmony_ci * Apply some rules to the filters: 37662306a36Sopenharmony_ci * - Some filters imply different filters to be set. 37762306a36Sopenharmony_ci * - Some things we can't filter out at all. 37862306a36Sopenharmony_ci * - Multicast filter seems to kill broadcast traffic so never use it. 37962306a36Sopenharmony_ci */ 38062306a36Sopenharmony_ci *total_flags |= FIF_ALLMULTI; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci /* 38362306a36Sopenharmony_ci * If the device has a single filter for all control frames, 38462306a36Sopenharmony_ci * FIF_CONTROL and FIF_PSPOLL flags imply each other. 38562306a36Sopenharmony_ci * And if the device has more than one filter for control frames 38662306a36Sopenharmony_ci * of different types, but has no a separate filter for PS Poll frames, 38762306a36Sopenharmony_ci * FIF_CONTROL flag implies FIF_PSPOLL. 38862306a36Sopenharmony_ci */ 38962306a36Sopenharmony_ci if (!rt2x00_has_cap_control_filters(rt2x00dev)) { 39062306a36Sopenharmony_ci if (*total_flags & FIF_CONTROL || *total_flags & FIF_PSPOLL) 39162306a36Sopenharmony_ci *total_flags |= FIF_CONTROL | FIF_PSPOLL; 39262306a36Sopenharmony_ci } 39362306a36Sopenharmony_ci if (!rt2x00_has_cap_control_filter_pspoll(rt2x00dev)) { 39462306a36Sopenharmony_ci if (*total_flags & FIF_CONTROL) 39562306a36Sopenharmony_ci *total_flags |= FIF_PSPOLL; 39662306a36Sopenharmony_ci } 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_ci rt2x00dev->packet_filter = *total_flags; 39962306a36Sopenharmony_ci 40062306a36Sopenharmony_ci rt2x00dev->ops->lib->config_filter(rt2x00dev, *total_flags); 40162306a36Sopenharmony_ci} 40262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_configure_filter); 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic void rt2x00mac_set_tim_iter(void *data, u8 *mac, 40562306a36Sopenharmony_ci struct ieee80211_vif *vif) 40662306a36Sopenharmony_ci{ 40762306a36Sopenharmony_ci struct rt2x00_intf *intf = vif_to_intf(vif); 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci if (vif->type != NL80211_IFTYPE_AP && 41062306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_ADHOC && 41162306a36Sopenharmony_ci vif->type != NL80211_IFTYPE_MESH_POINT) 41262306a36Sopenharmony_ci return; 41362306a36Sopenharmony_ci 41462306a36Sopenharmony_ci set_bit(DELAYED_UPDATE_BEACON, &intf->delayed_flags); 41562306a36Sopenharmony_ci} 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ciint rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta, 41862306a36Sopenharmony_ci bool set) 41962306a36Sopenharmony_ci{ 42062306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags)) 42362306a36Sopenharmony_ci return 0; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ieee80211_iterate_active_interfaces_atomic( 42662306a36Sopenharmony_ci rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL, 42762306a36Sopenharmony_ci rt2x00mac_set_tim_iter, rt2x00dev); 42862306a36Sopenharmony_ci 42962306a36Sopenharmony_ci /* queue work to upodate the beacon template */ 43062306a36Sopenharmony_ci ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work); 43162306a36Sopenharmony_ci return 0; 43262306a36Sopenharmony_ci} 43362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_tim); 43462306a36Sopenharmony_ci 43562306a36Sopenharmony_ci#ifdef CONFIG_RT2X00_LIB_CRYPTO 43662306a36Sopenharmony_cistatic void memcpy_tkip(struct rt2x00lib_crypto *crypto, u8 *key, u8 key_len) 43762306a36Sopenharmony_ci{ 43862306a36Sopenharmony_ci if (key_len > NL80211_TKIP_DATA_OFFSET_ENCR_KEY) 43962306a36Sopenharmony_ci memcpy(crypto->key, 44062306a36Sopenharmony_ci &key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY], 44162306a36Sopenharmony_ci sizeof(crypto->key)); 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci if (key_len > NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY) 44462306a36Sopenharmony_ci memcpy(crypto->tx_mic, 44562306a36Sopenharmony_ci &key[NL80211_TKIP_DATA_OFFSET_TX_MIC_KEY], 44662306a36Sopenharmony_ci sizeof(crypto->tx_mic)); 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci if (key_len > NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY) 44962306a36Sopenharmony_ci memcpy(crypto->rx_mic, 45062306a36Sopenharmony_ci &key[NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY], 45162306a36Sopenharmony_ci sizeof(crypto->rx_mic)); 45262306a36Sopenharmony_ci} 45362306a36Sopenharmony_ci 45462306a36Sopenharmony_ciint rt2x00mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd, 45562306a36Sopenharmony_ci struct ieee80211_vif *vif, struct ieee80211_sta *sta, 45662306a36Sopenharmony_ci struct ieee80211_key_conf *key) 45762306a36Sopenharmony_ci{ 45862306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 45962306a36Sopenharmony_ci int (*set_key) (struct rt2x00_dev *rt2x00dev, 46062306a36Sopenharmony_ci struct rt2x00lib_crypto *crypto, 46162306a36Sopenharmony_ci struct ieee80211_key_conf *key); 46262306a36Sopenharmony_ci struct rt2x00lib_crypto crypto; 46362306a36Sopenharmony_ci static const u8 bcast_addr[ETH_ALEN] = 46462306a36Sopenharmony_ci { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, }; 46562306a36Sopenharmony_ci struct rt2x00_sta *sta_priv = NULL; 46662306a36Sopenharmony_ci 46762306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 46862306a36Sopenharmony_ci return 0; 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci /* The hardware can't do MFP */ 47162306a36Sopenharmony_ci if (!rt2x00_has_cap_hw_crypto(rt2x00dev) || (sta && sta->mfp)) 47262306a36Sopenharmony_ci return -EOPNOTSUPP; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci /* 47562306a36Sopenharmony_ci * To support IBSS RSN, don't program group keys in IBSS, the 47662306a36Sopenharmony_ci * hardware will then not attempt to decrypt the frames. 47762306a36Sopenharmony_ci */ 47862306a36Sopenharmony_ci if (vif->type == NL80211_IFTYPE_ADHOC && 47962306a36Sopenharmony_ci !(key->flags & IEEE80211_KEY_FLAG_PAIRWISE)) 48062306a36Sopenharmony_ci return -EOPNOTSUPP; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci if (key->keylen > 32) 48362306a36Sopenharmony_ci return -ENOSPC; 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci memset(&crypto, 0, sizeof(crypto)); 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci crypto.bssidx = rt2x00lib_get_bssidx(rt2x00dev, vif); 48862306a36Sopenharmony_ci crypto.cipher = rt2x00crypto_key_to_cipher(key); 48962306a36Sopenharmony_ci if (crypto.cipher == CIPHER_NONE) 49062306a36Sopenharmony_ci return -EOPNOTSUPP; 49162306a36Sopenharmony_ci if (crypto.cipher == CIPHER_TKIP && rt2x00_is_usb(rt2x00dev)) 49262306a36Sopenharmony_ci return -EOPNOTSUPP; 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci crypto.cmd = cmd; 49562306a36Sopenharmony_ci 49662306a36Sopenharmony_ci if (sta) { 49762306a36Sopenharmony_ci crypto.address = sta->addr; 49862306a36Sopenharmony_ci sta_priv = sta_to_rt2x00_sta(sta); 49962306a36Sopenharmony_ci crypto.wcid = sta_priv->wcid; 50062306a36Sopenharmony_ci } else 50162306a36Sopenharmony_ci crypto.address = bcast_addr; 50262306a36Sopenharmony_ci 50362306a36Sopenharmony_ci if (crypto.cipher == CIPHER_TKIP) 50462306a36Sopenharmony_ci memcpy_tkip(&crypto, &key->key[0], key->keylen); 50562306a36Sopenharmony_ci else 50662306a36Sopenharmony_ci memcpy(crypto.key, &key->key[0], key->keylen); 50762306a36Sopenharmony_ci /* 50862306a36Sopenharmony_ci * Each BSS has a maximum of 4 shared keys. 50962306a36Sopenharmony_ci * Shared key index values: 51062306a36Sopenharmony_ci * 0) BSS0 key0 51162306a36Sopenharmony_ci * 1) BSS0 key1 51262306a36Sopenharmony_ci * ... 51362306a36Sopenharmony_ci * 4) BSS1 key0 51462306a36Sopenharmony_ci * ... 51562306a36Sopenharmony_ci * 8) BSS2 key0 51662306a36Sopenharmony_ci * ... 51762306a36Sopenharmony_ci * Both pairwise as shared key indeces are determined by 51862306a36Sopenharmony_ci * driver. This is required because the hardware requires 51962306a36Sopenharmony_ci * keys to be assigned in correct order (When key 1 is 52062306a36Sopenharmony_ci * provided but key 0 is not, then the key is not found 52162306a36Sopenharmony_ci * by the hardware during RX). 52262306a36Sopenharmony_ci */ 52362306a36Sopenharmony_ci if (cmd == SET_KEY) 52462306a36Sopenharmony_ci key->hw_key_idx = 0; 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci if (key->flags & IEEE80211_KEY_FLAG_PAIRWISE) 52762306a36Sopenharmony_ci set_key = rt2x00dev->ops->lib->config_pairwise_key; 52862306a36Sopenharmony_ci else 52962306a36Sopenharmony_ci set_key = rt2x00dev->ops->lib->config_shared_key; 53062306a36Sopenharmony_ci 53162306a36Sopenharmony_ci if (!set_key) 53262306a36Sopenharmony_ci return -EOPNOTSUPP; 53362306a36Sopenharmony_ci 53462306a36Sopenharmony_ci return set_key(rt2x00dev, &crypto, key); 53562306a36Sopenharmony_ci} 53662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_key); 53762306a36Sopenharmony_ci#endif /* CONFIG_RT2X00_LIB_CRYPTO */ 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_civoid rt2x00mac_sw_scan_start(struct ieee80211_hw *hw, 54062306a36Sopenharmony_ci struct ieee80211_vif *vif, 54162306a36Sopenharmony_ci const u8 *mac_addr) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 54462306a36Sopenharmony_ci set_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); 54562306a36Sopenharmony_ci rt2x00link_stop_tuner(rt2x00dev); 54662306a36Sopenharmony_ci} 54762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_start); 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_civoid rt2x00mac_sw_scan_complete(struct ieee80211_hw *hw, 55062306a36Sopenharmony_ci struct ieee80211_vif *vif) 55162306a36Sopenharmony_ci{ 55262306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 55362306a36Sopenharmony_ci clear_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags); 55462306a36Sopenharmony_ci rt2x00link_start_tuner(rt2x00dev); 55562306a36Sopenharmony_ci} 55662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_sw_scan_complete); 55762306a36Sopenharmony_ci 55862306a36Sopenharmony_ciint rt2x00mac_get_stats(struct ieee80211_hw *hw, 55962306a36Sopenharmony_ci struct ieee80211_low_level_stats *stats) 56062306a36Sopenharmony_ci{ 56162306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 56262306a36Sopenharmony_ci 56362306a36Sopenharmony_ci /* 56462306a36Sopenharmony_ci * The dot11ACKFailureCount, dot11RTSFailureCount and 56562306a36Sopenharmony_ci * dot11RTSSuccessCount are updated in interrupt time. 56662306a36Sopenharmony_ci * dot11FCSErrorCount is updated in the link tuner. 56762306a36Sopenharmony_ci */ 56862306a36Sopenharmony_ci memcpy(stats, &rt2x00dev->low_level_stats, sizeof(*stats)); 56962306a36Sopenharmony_ci 57062306a36Sopenharmony_ci return 0; 57162306a36Sopenharmony_ci} 57262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_stats); 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_civoid rt2x00mac_bss_info_changed(struct ieee80211_hw *hw, 57562306a36Sopenharmony_ci struct ieee80211_vif *vif, 57662306a36Sopenharmony_ci struct ieee80211_bss_conf *bss_conf, 57762306a36Sopenharmony_ci u64 changes) 57862306a36Sopenharmony_ci{ 57962306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 58062306a36Sopenharmony_ci struct rt2x00_intf *intf = vif_to_intf(vif); 58162306a36Sopenharmony_ci 58262306a36Sopenharmony_ci /* 58362306a36Sopenharmony_ci * mac80211 might be calling this function while we are trying 58462306a36Sopenharmony_ci * to remove the device or perhaps suspending it. 58562306a36Sopenharmony_ci */ 58662306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 58762306a36Sopenharmony_ci return; 58862306a36Sopenharmony_ci 58962306a36Sopenharmony_ci /* 59062306a36Sopenharmony_ci * Update the BSSID. 59162306a36Sopenharmony_ci */ 59262306a36Sopenharmony_ci if (changes & BSS_CHANGED_BSSID) 59362306a36Sopenharmony_ci rt2x00lib_config_intf(rt2x00dev, intf, vif->type, NULL, 59462306a36Sopenharmony_ci bss_conf->bssid); 59562306a36Sopenharmony_ci 59662306a36Sopenharmony_ci /* 59762306a36Sopenharmony_ci * Start/stop beaconing. 59862306a36Sopenharmony_ci */ 59962306a36Sopenharmony_ci if (changes & BSS_CHANGED_BEACON_ENABLED) { 60062306a36Sopenharmony_ci mutex_lock(&intf->beacon_skb_mutex); 60162306a36Sopenharmony_ci 60262306a36Sopenharmony_ci /* 60362306a36Sopenharmony_ci * Clear the 'enable_beacon' flag and clear beacon because 60462306a36Sopenharmony_ci * the beacon queue has been stopped after hardware reset. 60562306a36Sopenharmony_ci */ 60662306a36Sopenharmony_ci if (test_bit(DEVICE_STATE_RESET, &rt2x00dev->flags) && 60762306a36Sopenharmony_ci intf->enable_beacon) { 60862306a36Sopenharmony_ci intf->enable_beacon = false; 60962306a36Sopenharmony_ci rt2x00queue_clear_beacon(rt2x00dev, vif); 61062306a36Sopenharmony_ci } 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (!bss_conf->enable_beacon && intf->enable_beacon) { 61362306a36Sopenharmony_ci rt2x00dev->intf_beaconing--; 61462306a36Sopenharmony_ci intf->enable_beacon = false; 61562306a36Sopenharmony_ci 61662306a36Sopenharmony_ci if (rt2x00dev->intf_beaconing == 0) { 61762306a36Sopenharmony_ci /* 61862306a36Sopenharmony_ci * Last beaconing interface disabled 61962306a36Sopenharmony_ci * -> stop beacon queue. 62062306a36Sopenharmony_ci */ 62162306a36Sopenharmony_ci rt2x00queue_stop_queue(rt2x00dev->bcn); 62262306a36Sopenharmony_ci } 62362306a36Sopenharmony_ci /* 62462306a36Sopenharmony_ci * Clear beacon in the H/W for this vif. This is needed 62562306a36Sopenharmony_ci * to disable beaconing on this particular interface 62662306a36Sopenharmony_ci * and keep it running on other interfaces. 62762306a36Sopenharmony_ci */ 62862306a36Sopenharmony_ci rt2x00queue_clear_beacon(rt2x00dev, vif); 62962306a36Sopenharmony_ci } else if (bss_conf->enable_beacon && !intf->enable_beacon) { 63062306a36Sopenharmony_ci rt2x00dev->intf_beaconing++; 63162306a36Sopenharmony_ci intf->enable_beacon = true; 63262306a36Sopenharmony_ci /* 63362306a36Sopenharmony_ci * Upload beacon to the H/W. This is only required on 63462306a36Sopenharmony_ci * USB devices. PCI devices fetch beacons periodically. 63562306a36Sopenharmony_ci */ 63662306a36Sopenharmony_ci if (rt2x00_is_usb(rt2x00dev)) 63762306a36Sopenharmony_ci rt2x00queue_update_beacon(rt2x00dev, vif); 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci if (rt2x00dev->intf_beaconing == 1) { 64062306a36Sopenharmony_ci /* 64162306a36Sopenharmony_ci * First beaconing interface enabled 64262306a36Sopenharmony_ci * -> start beacon queue. 64362306a36Sopenharmony_ci */ 64462306a36Sopenharmony_ci rt2x00queue_start_queue(rt2x00dev->bcn); 64562306a36Sopenharmony_ci } 64662306a36Sopenharmony_ci } 64762306a36Sopenharmony_ci mutex_unlock(&intf->beacon_skb_mutex); 64862306a36Sopenharmony_ci } 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci /* 65162306a36Sopenharmony_ci * When the association status has changed we must reset the link 65262306a36Sopenharmony_ci * tuner counter. This is because some drivers determine if they 65362306a36Sopenharmony_ci * should perform link tuning based on the number of seconds 65462306a36Sopenharmony_ci * while associated or not associated. 65562306a36Sopenharmony_ci */ 65662306a36Sopenharmony_ci if (changes & BSS_CHANGED_ASSOC) { 65762306a36Sopenharmony_ci rt2x00dev->link.count = 0; 65862306a36Sopenharmony_ci 65962306a36Sopenharmony_ci if (vif->cfg.assoc) 66062306a36Sopenharmony_ci rt2x00dev->intf_associated++; 66162306a36Sopenharmony_ci else 66262306a36Sopenharmony_ci rt2x00dev->intf_associated--; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci rt2x00leds_led_assoc(rt2x00dev, !!rt2x00dev->intf_associated); 66562306a36Sopenharmony_ci } 66662306a36Sopenharmony_ci 66762306a36Sopenharmony_ci /* 66862306a36Sopenharmony_ci * When the erp information has changed, we should perform 66962306a36Sopenharmony_ci * additional configuration steps. For all other changes we are done. 67062306a36Sopenharmony_ci */ 67162306a36Sopenharmony_ci if (changes & (BSS_CHANGED_ERP_CTS_PROT | BSS_CHANGED_ERP_PREAMBLE | 67262306a36Sopenharmony_ci BSS_CHANGED_ERP_SLOT | BSS_CHANGED_BASIC_RATES | 67362306a36Sopenharmony_ci BSS_CHANGED_BEACON_INT | BSS_CHANGED_HT)) 67462306a36Sopenharmony_ci rt2x00lib_config_erp(rt2x00dev, intf, bss_conf, changes); 67562306a36Sopenharmony_ci} 67662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_bss_info_changed); 67762306a36Sopenharmony_ci 67862306a36Sopenharmony_ciint rt2x00mac_conf_tx(struct ieee80211_hw *hw, 67962306a36Sopenharmony_ci struct ieee80211_vif *vif, 68062306a36Sopenharmony_ci unsigned int link_id, u16 queue_idx, 68162306a36Sopenharmony_ci const struct ieee80211_tx_queue_params *params) 68262306a36Sopenharmony_ci{ 68362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 68462306a36Sopenharmony_ci struct data_queue *queue; 68562306a36Sopenharmony_ci 68662306a36Sopenharmony_ci queue = rt2x00queue_get_tx_queue(rt2x00dev, queue_idx); 68762306a36Sopenharmony_ci if (unlikely(!queue)) 68862306a36Sopenharmony_ci return -EINVAL; 68962306a36Sopenharmony_ci 69062306a36Sopenharmony_ci /* 69162306a36Sopenharmony_ci * The passed variables are stored as real value ((2^n)-1). 69262306a36Sopenharmony_ci * Ralink registers require to know the bit number 'n'. 69362306a36Sopenharmony_ci */ 69462306a36Sopenharmony_ci if (params->cw_min > 0) 69562306a36Sopenharmony_ci queue->cw_min = fls(params->cw_min); 69662306a36Sopenharmony_ci else 69762306a36Sopenharmony_ci queue->cw_min = 5; /* cw_min: 2^5 = 32. */ 69862306a36Sopenharmony_ci 69962306a36Sopenharmony_ci if (params->cw_max > 0) 70062306a36Sopenharmony_ci queue->cw_max = fls(params->cw_max); 70162306a36Sopenharmony_ci else 70262306a36Sopenharmony_ci queue->cw_max = 10; /* cw_min: 2^10 = 1024. */ 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci queue->aifs = params->aifs; 70562306a36Sopenharmony_ci queue->txop = params->txop; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci rt2x00_dbg(rt2x00dev, 70862306a36Sopenharmony_ci "Configured TX queue %d - CWmin: %d, CWmax: %d, Aifs: %d, TXop: %d\n", 70962306a36Sopenharmony_ci queue_idx, queue->cw_min, queue->cw_max, queue->aifs, 71062306a36Sopenharmony_ci queue->txop); 71162306a36Sopenharmony_ci 71262306a36Sopenharmony_ci return 0; 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_conf_tx); 71562306a36Sopenharmony_ci 71662306a36Sopenharmony_civoid rt2x00mac_rfkill_poll(struct ieee80211_hw *hw) 71762306a36Sopenharmony_ci{ 71862306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 71962306a36Sopenharmony_ci bool active = !!rt2x00dev->ops->lib->rfkill_poll(rt2x00dev); 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci wiphy_rfkill_set_hw_state(hw->wiphy, !active); 72262306a36Sopenharmony_ci} 72362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_rfkill_poll); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_civoid rt2x00mac_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, 72662306a36Sopenharmony_ci u32 queues, bool drop) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 72962306a36Sopenharmony_ci struct data_queue *queue; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags)) 73262306a36Sopenharmony_ci return; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci set_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags); 73562306a36Sopenharmony_ci 73662306a36Sopenharmony_ci tx_queue_for_each(rt2x00dev, queue) 73762306a36Sopenharmony_ci rt2x00queue_flush_queue(queue, drop); 73862306a36Sopenharmony_ci 73962306a36Sopenharmony_ci clear_bit(DEVICE_STATE_FLUSHING, &rt2x00dev->flags); 74062306a36Sopenharmony_ci} 74162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_flush); 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ciint rt2x00mac_set_antenna(struct ieee80211_hw *hw, u32 tx_ant, u32 rx_ant) 74462306a36Sopenharmony_ci{ 74562306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 74662306a36Sopenharmony_ci struct link_ant *ant = &rt2x00dev->link.ant; 74762306a36Sopenharmony_ci struct antenna_setup *def = &rt2x00dev->default_ant; 74862306a36Sopenharmony_ci struct antenna_setup setup; 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_ci // The antenna value is not supposed to be 0, 75162306a36Sopenharmony_ci // or exceed the maximum number of antenna's. 75262306a36Sopenharmony_ci if (!tx_ant || (tx_ant & ~3) || !rx_ant || (rx_ant & ~3)) 75362306a36Sopenharmony_ci return -EINVAL; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci // When the client tried to configure the antenna to or from 75662306a36Sopenharmony_ci // diversity mode, we must reset the default antenna as well 75762306a36Sopenharmony_ci // as that controls the diversity switch. 75862306a36Sopenharmony_ci if (ant->flags & ANTENNA_TX_DIVERSITY && tx_ant != 3) 75962306a36Sopenharmony_ci ant->flags &= ~ANTENNA_TX_DIVERSITY; 76062306a36Sopenharmony_ci if (ant->flags & ANTENNA_RX_DIVERSITY && rx_ant != 3) 76162306a36Sopenharmony_ci ant->flags &= ~ANTENNA_RX_DIVERSITY; 76262306a36Sopenharmony_ci 76362306a36Sopenharmony_ci // If diversity is being enabled, check if we need hardware 76462306a36Sopenharmony_ci // or software diversity. In the latter case, reset the value, 76562306a36Sopenharmony_ci // and make sure we update the antenna flags to have the 76662306a36Sopenharmony_ci // link tuner pick up the diversity tuning. 76762306a36Sopenharmony_ci if (tx_ant == 3 && def->tx == ANTENNA_SW_DIVERSITY) { 76862306a36Sopenharmony_ci tx_ant = ANTENNA_SW_DIVERSITY; 76962306a36Sopenharmony_ci ant->flags |= ANTENNA_TX_DIVERSITY; 77062306a36Sopenharmony_ci } 77162306a36Sopenharmony_ci 77262306a36Sopenharmony_ci if (rx_ant == 3 && def->rx == ANTENNA_SW_DIVERSITY) { 77362306a36Sopenharmony_ci rx_ant = ANTENNA_SW_DIVERSITY; 77462306a36Sopenharmony_ci ant->flags |= ANTENNA_RX_DIVERSITY; 77562306a36Sopenharmony_ci } 77662306a36Sopenharmony_ci 77762306a36Sopenharmony_ci setup.tx = tx_ant; 77862306a36Sopenharmony_ci setup.rx = rx_ant; 77962306a36Sopenharmony_ci setup.rx_chain_num = 0; 78062306a36Sopenharmony_ci setup.tx_chain_num = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci rt2x00lib_config_antenna(rt2x00dev, setup); 78362306a36Sopenharmony_ci 78462306a36Sopenharmony_ci return 0; 78562306a36Sopenharmony_ci} 78662306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_set_antenna); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ciint rt2x00mac_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant) 78962306a36Sopenharmony_ci{ 79062306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 79162306a36Sopenharmony_ci struct link_ant *ant = &rt2x00dev->link.ant; 79262306a36Sopenharmony_ci struct antenna_setup *active = &rt2x00dev->link.ant.active; 79362306a36Sopenharmony_ci 79462306a36Sopenharmony_ci // When software diversity is active, we must report this to the 79562306a36Sopenharmony_ci // client and not the current active antenna state. 79662306a36Sopenharmony_ci if (ant->flags & ANTENNA_TX_DIVERSITY) 79762306a36Sopenharmony_ci *tx_ant = ANTENNA_HW_DIVERSITY; 79862306a36Sopenharmony_ci else 79962306a36Sopenharmony_ci *tx_ant = active->tx; 80062306a36Sopenharmony_ci 80162306a36Sopenharmony_ci if (ant->flags & ANTENNA_RX_DIVERSITY) 80262306a36Sopenharmony_ci *rx_ant = ANTENNA_HW_DIVERSITY; 80362306a36Sopenharmony_ci else 80462306a36Sopenharmony_ci *rx_ant = active->rx; 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci return 0; 80762306a36Sopenharmony_ci} 80862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_antenna); 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_civoid rt2x00mac_get_ringparam(struct ieee80211_hw *hw, 81162306a36Sopenharmony_ci u32 *tx, u32 *tx_max, u32 *rx, u32 *rx_max) 81262306a36Sopenharmony_ci{ 81362306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 81462306a36Sopenharmony_ci struct data_queue *queue; 81562306a36Sopenharmony_ci 81662306a36Sopenharmony_ci tx_queue_for_each(rt2x00dev, queue) { 81762306a36Sopenharmony_ci *tx += queue->length; 81862306a36Sopenharmony_ci *tx_max += queue->limit; 81962306a36Sopenharmony_ci } 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci *rx = rt2x00dev->rx->length; 82262306a36Sopenharmony_ci *rx_max = rt2x00dev->rx->limit; 82362306a36Sopenharmony_ci} 82462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_get_ringparam); 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_cibool rt2x00mac_tx_frames_pending(struct ieee80211_hw *hw) 82762306a36Sopenharmony_ci{ 82862306a36Sopenharmony_ci struct rt2x00_dev *rt2x00dev = hw->priv; 82962306a36Sopenharmony_ci struct data_queue *queue; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci tx_queue_for_each(rt2x00dev, queue) { 83262306a36Sopenharmony_ci if (!rt2x00queue_empty(queue)) 83362306a36Sopenharmony_ci return true; 83462306a36Sopenharmony_ci } 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci return false; 83762306a36Sopenharmony_ci} 83862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(rt2x00mac_tx_frames_pending); 839