mirror of
https://github.com/coolsnowwolf/lede.git
synced 2025-04-19 03:43:29 +00:00
mac80211: netifd: Use a mask when using Usage: iw [options] command
Options: --debug enable netlink debugging --version show version (3.4) Commands: help [command] Print usage for all or a specific command, e.g. "help wowlan" or "help wowlan enable". event [-t] [-r] [-f] Monitor events from the kernel. -t - print timestamp -r - print relative timstamp -f - print full frame for auth/assoc etc. phy list List all wireless devices and their capabilities. phy <phyname> info Show capabilities for the specified wireless device. dev List all network interfaces for wireless hardware. dev <devname> info Show information for this interface. dev <devname> del Remove this virtual interface dev <devname> interface add <name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] phy <phyname> interface add <name> type <type> [mesh_id <meshid>] [4addr on|off] [flags <flag>*] Add a new virtual interface with the given configuration. Valid interface types are: managed, ibss, monitor, mesh, wds. The flags are only used for monitor interfaces, valid flags are: none: no special flags fcsfail: show frames with FCS errors control: show control frames otherbss: show frames from other BSSes cook: use cooked mode The mesh_id is used only for mesh mode. dev <devname> ibss join <SSID> <freq in MHz> [HT20|HT40+|HT40-|NOHT] [fixed-freq] [<fixed bssid>] [beacon-interval <TU>] [basic-rates <rate in Mbps,rate2,...>] [mcast-rate <rate in Mbps>] [key d:0:abcde] Join the IBSS cell with the given SSID, if it doesn't exist create it on the given frequency. When fixed frequency is requested, don't join/create a cell on a different frequency. When a fixed BSSID is requested use that BSSID and do not adopt another cell's BSSID even if it has higher TSF and the same SSID. If an IBSS is created, create it with the specified basic-rates, multicast-rate and beacon-interval. dev <devname> ibss leave Leave the current IBSS cell. dev <devname> station dump List all stations known, e.g. the AP on managed interfaces dev <devname> station set <MAC address> vlan <ifindex> Set an AP VLAN for this station. dev <devname> station set <MAC address> plink_action <open|block> Set mesh peer link action for this station (peer). dev <devname> station del <MAC address> Remove the given station entry (use with caution!) dev <devname> station get <MAC address> Get information for a specific station. dev <devname> survey dump List all gathered channel survey data dev <devname> mesh leave Leave a mesh. dev <devname> mesh join <mesh ID> [mcast-rate <rate in Mbps>] [<param>=<value>]* Join a mesh with the given mesh ID with mcast-rate and mesh parameters. dev <devname> mpath dump List known mesh paths. dev <devname> mpath set <destination MAC address> next_hop <next hop MAC address> Set an existing mesh path's next hop. dev <devname> mpath new <destination MAC address> next_hop <next hop MAC address> Create a new mesh path (instead of relying on automatic discovery). dev <devname> mpath del <MAC address> Remove the mesh path to the given node. dev <devname> mpath get <MAC address> Get information on mesh path to the given node. dev <devname> scan [-u] [freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive] Scan on the given frequencies and probe for the given SSIDs (or wildcard if not given) unless passive scanning is requested. If -u is specified print unknown data in the scan results. Specified (vendor) IEs must be well-formed. dev <devname> scan trigger [freq <freq>*] [ies <hex as 00:11:..>] [ssid <ssid>*|passive] Trigger a scan on the given frequencies with probing for the given SSIDs (or wildcard if not given) unless passive scanning is requested. dev <devname> scan dump [-u] Dump the current scan results. If -u is specified, print unknown data in scan results. reg get Print out the kernel's current regulatory domain information. reg set <ISO/IEC 3166-1 alpha2> Notify the kernel about the current regulatory domain. dev <devname> connect [-w] <SSID> [<freq in MHz>] [<bssid>] [key 0:abcde d:1:6162636465] Join the network with the given SSID (and frequency, BSSID). With -w, wait for the connect to finish or fail. dev <devname> disconnect Disconnect from the current network. dev <devname> link Print information about the current link, if any. dev <devname> offchannel <freq> <duration> Leave operating channel and go to the given channel for a while. dev <devname> cqm rssi <threshold|off> [<hysteresis>] Set connection quality monitor RSSI threshold. phy <phyname> wowlan show Show WoWLAN status. phy <phyname> wowlan disable Disable WoWLAN. phy <phyname> wowlan enable [any] [disconnect] [magic-packet] [gtk-rekey-failure] [eap-identity-request] [4way-handshake] [rfkill-release] [patterns <pattern>*] Enable WoWLAN with the given triggers. Each pattern is given as a bytestring with '-' in places where any byte may be present, e.g. 00:11:22:-:44 will match 00:11:22:33:44 and 00:11:22:33:ff:44 etc. dev <devname> roc start <freq> <time> phy <phyname> set antenna <bitmap> | all | <tx bitmap> <rx bitmap> Set a bitmap of allowed antennas to use for TX and RX. The driver may reject antenna configurations it cannot support. dev <devname> set txpower <auto|fixed|limit> [<tx power in mBm>] Specify transmit power level and setting type. phy <phyname> set txpower <auto|fixed|limit> [<tx power in mBm>] Specify transmit power level and setting type. phy <phyname> set distance <distance> Set appropriate coverage class for given link distance in meters. Valid values: 0 - 114750 phy <phyname> set coverage <coverage class> Set coverage class (1 for every 3 usec of air propagation time). Valid values: 0 - 255. phy <phyname> set netns <pid> Put this wireless device into a different network namespace phy <phyname> set rts <rts threshold|off> Set rts threshold. phy <phyname> set frag <fragmentation threshold|off> Set fragmentation threshold. dev <devname> set channel <channel> [HT20|HT40+|HT40-] phy <phyname> set channel <channel> [HT20|HT40+|HT40-] dev <devname> set freq <freq> [HT20|HT40+|HT40-] phy <phyname> set freq <freq> [HT20|HT40+|HT40-] Set frequency/channel the hardware is using, including HT configuration. phy <phyname> set name <new name> Rename this wireless device. dev <devname> set peer <MAC address> Set interface WDS peer. dev <devname> set noack_map <map> Set the NoAck map for the TIDs. (0x0009 = BE, 0x0006 = BK, 0x0030 = VI, 0x00C0 = VO) dev <devname> set 4addr <on|off> Set interface 4addr (WDS) mode. dev <devname> set type <type> Set interface type/mode. Valid interface types are: managed, ibss, monitor, mesh, wds. dev <devname> set meshid <meshid> dev <devname> set monitor <flag>* Set monitor flags. Valid flags are: none: no special flags fcsfail: show frames with FCS errors control: show control frames otherbss: show frames from other BSSes cook: use cooked mode dev <devname> set mesh_param <param>=<value> [<param>=<value>]* Set mesh parameter (run command without any to see available ones). dev <devname> set power_save <on|off> Set power save state to on or off. dev <devname> set bitrates [legacy-<2.4|5> <legacy rate in Mbps>*] [mcs-<2.4|5> <MCS index>*] Sets up the specified rate masks. Not passing any arguments would clear the existing mask (if any). dev <devname> get mesh_param [<param>] Retrieve mesh parameter (run command without any to see available ones). dev <devname> get power_save <param> Retrieve power save state. You can omit the 'phy' or 'dev' if the identification is unique, e.g. "iw wlan0 info" or "iw phy0 info". (Don't when scripting.) Do NOT screenscrape this tool, we don't consider its output stable.
This commit is contained in:
parent
ec09753204
commit
88beed4c56
@ -11,7 +11,7 @@ include $(INCLUDE_DIR)/kernel.mk
|
||||
PKG_NAME:=mac80211
|
||||
|
||||
PKG_VERSION:=4.19.23-1
|
||||
PKG_RELEASE:=4
|
||||
PKG_RELEASE:=5
|
||||
PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v4.19.23/
|
||||
PKG_HASH:=703e940b542eb56067fcd847a7c69398dcc9829f34472647eea4211cb2ab3b83
|
||||
|
||||
@ -259,7 +259,7 @@ endef
|
||||
define KernelPackage/mt7601u
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=MT7601U-based USB dongles Wireless Driver
|
||||
DEPENDS+= +kmod-mac80211 +@DRIVER_11N_SUPPORT @USB_SUPPORT +kmod-usb-core +mt7601u-firmware
|
||||
DEPENDS+= +kmod-mac80211 +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT @USB_SUPPORT +kmod-usb-core +mt7601u-firmware
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/mediatek/mt7601u/mt7601u.ko
|
||||
AUTOLOAD:=$(call AutoProbe,mt7601u)
|
||||
endef
|
||||
@ -275,7 +275,7 @@ endef
|
||||
|
||||
define KernelPackage/p54-common
|
||||
$(call KernelPackage/p54/Default)
|
||||
DEPENDS+= @PCI_SUPPORT||@USB_SUPPORT||@TARGET_omap24xx +kmod-mac80211 +kmod-lib-crc-ccitt
|
||||
DEPENDS+= @PCI_SUPPORT||@USB_SUPPORT||@TARGET_omap24xx +kmod-mac80211 +kmod-lib-crc-ccitt +@DRIVER_11W_SUPPORT
|
||||
TITLE+= (COMMON)
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intersil/p54/p54common.ko
|
||||
endef
|
||||
@ -381,7 +381,7 @@ $(eval $(call Download,zd1211rw))
|
||||
define KernelPackage/zd1211rw
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=Zydas ZD1211 support
|
||||
DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-mac80211
|
||||
DEPENDS+= @USB_SUPPORT +kmod-usb-core +kmod-mac80211 +@DRIVER_11W_SUPPORT
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/zydas/zd1211rw/zd1211rw.ko
|
||||
AUTOLOAD:=$(call AutoProbe,zd1211rw)
|
||||
endef
|
||||
|
@ -270,7 +270,7 @@ endef
|
||||
define KernelPackage/carl9170
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=Driver for Atheros AR9170 USB sticks
|
||||
DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core +@DRIVER_11N_SUPPORT +carl9170-firmware
|
||||
DEPENDS:=@USB_SUPPORT +kmod-mac80211 +kmod-ath +kmod-usb-core +kmod-input-core +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT +carl9170-firmware
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ath/carl9170/carl9170.ko
|
||||
AUTOLOAD:=$(call AutoProbe,carl9170)
|
||||
endef
|
||||
|
@ -433,8 +433,8 @@ define KernelPackage/brcmfmac
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=Broadcom IEEE802.11n USB FullMAC WLAN driver
|
||||
URL:=https://wireless.wiki.kernel.org/en/users/drivers/brcm80211
|
||||
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +kmod-brcmutil \
|
||||
+BRCMFMAC_SDIO:kmod-mmc @!TARGET_uml \
|
||||
DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT \
|
||||
+kmod-brcmutil +BRCMFMAC_SDIO:kmod-mmc @!TARGET_uml \
|
||||
+BRCMFMAC_USB:kmod-usb-core +BRCMFMAC_USB:brcmfmac-firmware-usb
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/broadcom/brcm80211/brcmfmac/brcmfmac.ko
|
||||
AUTOLOAD:=$(call AutoProbe,brcmfmac)
|
||||
|
@ -781,11 +781,14 @@ drv_mac80211_setup() {
|
||||
done
|
||||
}
|
||||
|
||||
set_default rxantenna all
|
||||
set_default txantenna all
|
||||
set_default rxantenna 0xffffffff
|
||||
set_default txantenna 0xffffffff
|
||||
set_default distance 0
|
||||
set_default antenna_gain 0
|
||||
|
||||
[ "$txantenna" = "all" ] && txantenna=0xffffffff
|
||||
[ "$rxantenna" = "all" ] && rxantenna=0xffffffff
|
||||
|
||||
iw phy "$phy" set antenna $txantenna $rxantenna >/dev/null 2>&1
|
||||
iw phy "$phy" set antenna_gain $antenna_gain
|
||||
iw phy "$phy" set distance "$distance"
|
||||
|
@ -15,7 +15,7 @@ config-$(call config_package,ipw2200) += IPW2200
|
||||
|
||||
define KernelPackage/iwlwifi
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT @!LINUX_3_18
|
||||
DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11W_SUPPORT @!LINUX_3_18
|
||||
TITLE:=Intel AGN Wireless support
|
||||
FILES:= \
|
||||
$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \
|
||||
|
@ -1,8 +1,24 @@
|
||||
diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
|
||||
index 1ab507c..f62f7c0 100644
|
||||
From c92df3d93ad09f219e0728b39d40dc0a69d0760f Mon Sep 17 00:00:00 2001
|
||||
From: Vijayakumar Durai <vijayakumar.durai1@vivint.com>
|
||||
Date: Tue Feb 26 19:29:30 2019 +0530
|
||||
Subject: [PATCH] rt2x00: do not increment sequence number while
|
||||
re-transmitting
|
||||
|
||||
Currently STA+AP re-transmitting the management frames with
|
||||
incremented sequence number if hardware is assigning the sequence.
|
||||
|
||||
Fix is to assign the sequence number for Beacon by hardware
|
||||
and for other Management frames software will assign the
|
||||
sequence number
|
||||
|
||||
Signed-off-by: Vijayakumar Durai <vijayakumar.durai1@vivint.com>
|
||||
---
|
||||
.../net/wireless/ralink/rt2x00/rt2x00queue.c | 26 +++++++++----------
|
||||
1 file changed, 12 insertions(+), 14 deletions(-)
|
||||
|
||||
--- a/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
|
||||
+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00queue.c
|
||||
@@ -207,22 +207,20 @@ static void rt2x00queue_create_tx_descriptor_seq(struct rt2x00_dev *rt2x00dev,
|
||||
@@ -207,22 +207,20 @@ static void rt2x00queue_create_tx_descri
|
||||
*/
|
||||
if (test_bit(CONFIG_QOS_DISABLED, &rt2x00dev->flags))
|
||||
__clear_bit(ENTRY_TXD_GENERATE_SEQ, &txdesc->flags);
|
||||
|
@ -0,0 +1,272 @@
|
||||
From: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
Date: Wed, 11 Jul 2018 00:12:53 +0530
|
||||
Subject: [PATCH] mac80211: add stop/start logic for software TXQs
|
||||
|
||||
Sometimes, it is required to stop the transmissions momentarily and
|
||||
resume it later; stopping the txqs becomes very critical in scenarios where
|
||||
the packet transmission has to be ceased completely. For example, during
|
||||
the hardware restart, during off channel operations,
|
||||
when initiating CSA(upon detecting a radar on the DFS channel), etc.
|
||||
|
||||
The TX queue stop/start logic in mac80211 works well in stopping the TX
|
||||
when drivers make use of netdev queues, i.e, when Qdiscs in network layer
|
||||
take care of traffic scheduling. Since the devices implementing
|
||||
wake_tx_queue can run without Qdiscs, packets will be handed to mac80211
|
||||
directly without queueing them in the netdev queues.
|
||||
|
||||
Also, mac80211 does not invoke any of the
|
||||
netif_stop_*/netif_wake_* APIs if wake_tx_queue is implemented.
|
||||
Since the queues are not stopped in this case, transmissions can continue
|
||||
and this will impact negatively on the operation of the wireless device.
|
||||
|
||||
For example,
|
||||
During hardware restart, we stop the netdev queues so that packets are
|
||||
not sent to the driver. Since ath10k implements wake_tx_queue,
|
||||
TX queues will not be stopped and packets might reach the hardware while
|
||||
it is restarting; this can make hardware unresponsive and the only
|
||||
possible option for recovery is to reboot the entire system.
|
||||
|
||||
There is another problem to this, it is observed that the packets
|
||||
were sent on the DFS channel for a prolonged duration after radar
|
||||
detection impacting the channel closing time.
|
||||
|
||||
We can still invoke netif stop/wake APIs when wake_tx_queue is implemented
|
||||
but this could lead to packet drops in network layer; adding stop/start
|
||||
logic for software TXQs in mac80211 instead makes more sense; the change
|
||||
proposed adds the same in mac80211.
|
||||
|
||||
Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1504,6 +1504,8 @@ enum ieee80211_vif_flags {
|
||||
* @drv_priv: data area for driver use, will always be aligned to
|
||||
* sizeof(void \*).
|
||||
* @txq: the multicast data TX queue (if driver uses the TXQ abstraction)
|
||||
+ * @txqs_stopped: per AC flag to indicate that intermediate TXQs are stopped,
|
||||
+ * protected by fq->lock.
|
||||
*/
|
||||
struct ieee80211_vif {
|
||||
enum nl80211_iftype type;
|
||||
@@ -1528,6 +1530,8 @@ struct ieee80211_vif {
|
||||
|
||||
unsigned int probe_req_reg;
|
||||
|
||||
+ bool txqs_stopped[IEEE80211_NUM_ACS];
|
||||
+
|
||||
/* must be last */
|
||||
u8 drv_priv[0] __aligned(sizeof(void *));
|
||||
};
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -818,6 +818,7 @@ enum txq_info_flags {
|
||||
IEEE80211_TXQ_STOP,
|
||||
IEEE80211_TXQ_AMPDU,
|
||||
IEEE80211_TXQ_NO_AMSDU,
|
||||
+ IEEE80211_TXQ_STOP_NETIF_TX,
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1226,6 +1227,7 @@ struct ieee80211_local {
|
||||
|
||||
struct sk_buff_head pending[IEEE80211_MAX_QUEUES];
|
||||
struct tasklet_struct tx_pending_tasklet;
|
||||
+ struct tasklet_struct wake_txqs_tasklet;
|
||||
|
||||
atomic_t agg_queue_stop[IEEE80211_MAX_QUEUES];
|
||||
|
||||
@@ -2039,6 +2041,7 @@ void ieee80211_txq_remove_vlan(struct ie
|
||||
struct ieee80211_sub_if_data *sdata);
|
||||
void ieee80211_fill_txq_stats(struct cfg80211_txq_stats *txqstats,
|
||||
struct txq_info *txqi);
|
||||
+void ieee80211_wake_txqs(unsigned long data);
|
||||
void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
|
||||
u16 transaction, u16 auth_alg, u16 status,
|
||||
const u8 *extra, size_t extra_len, const u8 *bssid,
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -686,6 +686,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
|
||||
(unsigned long)local);
|
||||
|
||||
+ if (ops->wake_tx_queue)
|
||||
+ tasklet_init(&local->wake_txqs_tasklet, ieee80211_wake_txqs,
|
||||
+ (unsigned long)local);
|
||||
+
|
||||
tasklet_init(&local->tasklet,
|
||||
ieee80211_tasklet_handler,
|
||||
(unsigned long) local);
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3482,13 +3482,19 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
struct ieee80211_tx_info *info;
|
||||
struct ieee80211_tx_data tx;
|
||||
ieee80211_tx_result r;
|
||||
- struct ieee80211_vif *vif;
|
||||
+ struct ieee80211_vif *vif = txq->vif;
|
||||
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
- if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags))
|
||||
+ if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
|
||||
+ test_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags))
|
||||
goto out;
|
||||
|
||||
+ if (vif->txqs_stopped[ieee80211_ac_from_tid(txq->tid)]) {
|
||||
+ set_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags);
|
||||
+ goto out;
|
||||
+ }
|
||||
+
|
||||
/* Make sure fragments stay together. */
|
||||
skb = __skb_dequeue(&txqi->frags);
|
||||
if (skb)
|
||||
@@ -3583,6 +3589,7 @@ begin:
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
||||
+
|
||||
out:
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -240,6 +240,99 @@ __le16 ieee80211_ctstoself_duration(stru
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_ctstoself_duration);
|
||||
|
||||
+static void __ieee80211_wake_txqs(struct ieee80211_sub_if_data *sdata, int ac)
|
||||
+{
|
||||
+ struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_vif *vif = &sdata->vif;
|
||||
+ struct fq *fq = &local->fq;
|
||||
+ struct ps_data *ps = NULL;
|
||||
+ struct txq_info *txqi;
|
||||
+ struct sta_info *sta;
|
||||
+ int i;
|
||||
+
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
+
|
||||
+ if (sdata->vif.type == NL80211_IFTYPE_AP)
|
||||
+ ps = &sdata->bss->ps;
|
||||
+
|
||||
+ sdata->vif.txqs_stopped[ac] = false;
|
||||
+
|
||||
+ list_for_each_entry_rcu(sta, &local->sta_list, list) {
|
||||
+ if (sdata != sta->sdata)
|
||||
+ continue;
|
||||
+
|
||||
+ for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
+ struct ieee80211_txq *txq = sta->sta.txq[i];
|
||||
+
|
||||
+ txqi = to_txq_info(txq);
|
||||
+
|
||||
+ if (ac != txq->ac)
|
||||
+ continue;
|
||||
+
|
||||
+ if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX,
|
||||
+ &txqi->flags))
|
||||
+ continue;
|
||||
+
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (!vif->txq)
|
||||
+ goto out;
|
||||
+
|
||||
+ txqi = to_txq_info(vif->txq);
|
||||
+
|
||||
+ if (!test_and_clear_bit(IEEE80211_TXQ_STOP_NETIF_TX, &txqi->flags) ||
|
||||
+ (ps && atomic_read(&ps->num_sta_ps)) || ac != vif->txq->ac)
|
||||
+ goto out;
|
||||
+
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+ return;
|
||||
+out:
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+}
|
||||
+
|
||||
+void ieee80211_wake_txqs(unsigned long data)
|
||||
+{
|
||||
+ struct ieee80211_local *local = (struct ieee80211_local *)data;
|
||||
+ struct ieee80211_sub_if_data *sdata;
|
||||
+ int n_acs = IEEE80211_NUM_ACS;
|
||||
+ unsigned long flags;
|
||||
+ int i;
|
||||
+
|
||||
+ rcu_read_lock();
|
||||
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
+
|
||||
+ if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
+ n_acs = 1;
|
||||
+
|
||||
+ for (i = 0; i < local->hw.queues; i++) {
|
||||
+ if (local->queue_stop_reasons[i])
|
||||
+ continue;
|
||||
+
|
||||
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
+ list_for_each_entry_rcu(sdata, &local->interfaces, list) {
|
||||
+ int ac;
|
||||
+
|
||||
+ for (ac = 0; ac < n_acs; ac++) {
|
||||
+ int ac_queue = sdata->vif.hw_queue[ac];
|
||||
+
|
||||
+ if (ac_queue == i ||
|
||||
+ sdata->vif.cab_queue == i)
|
||||
+ __ieee80211_wake_txqs(sdata, ac);
|
||||
+ }
|
||||
+ }
|
||||
+ spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
|
||||
+ }
|
||||
+
|
||||
+ spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
|
||||
+ rcu_read_unlock();
|
||||
+}
|
||||
+
|
||||
void ieee80211_propagate_queue_wake(struct ieee80211_local *local, int queue)
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
@@ -308,6 +401,9 @@ static void __ieee80211_wake_queue(struc
|
||||
rcu_read_unlock();
|
||||
} else
|
||||
tasklet_schedule(&local->tx_pending_tasklet);
|
||||
+
|
||||
+ if (local->ops->wake_tx_queue)
|
||||
+ tasklet_schedule(&local->wake_txqs_tasklet);
|
||||
}
|
||||
|
||||
void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
|
||||
@@ -351,9 +447,6 @@ static void __ieee80211_stop_queue(struc
|
||||
if (__test_and_set_bit(reason, &local->queue_stop_reasons[queue]))
|
||||
return;
|
||||
|
||||
- if (local->ops->wake_tx_queue)
|
||||
- return;
|
||||
-
|
||||
if (local->hw.queues < IEEE80211_NUM_ACS)
|
||||
n_acs = 1;
|
||||
|
||||
@@ -366,8 +459,15 @@ static void __ieee80211_stop_queue(struc
|
||||
|
||||
for (ac = 0; ac < n_acs; ac++) {
|
||||
if (sdata->vif.hw_queue[ac] == queue ||
|
||||
- sdata->vif.cab_queue == queue)
|
||||
- netif_stop_subqueue(sdata->dev, ac);
|
||||
+ sdata->vif.cab_queue == queue) {
|
||||
+ if (!local->ops->wake_tx_queue) {
|
||||
+ netif_stop_subqueue(sdata->dev, ac);
|
||||
+ continue;
|
||||
+ }
|
||||
+ spin_lock(&local->fq.lock);
|
||||
+ sdata->vif.txqs_stopped[ac] = true;
|
||||
+ spin_unlock(&local->fq.lock);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
rcu_read_unlock();
|
@ -0,0 +1,33 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 1 Mar 2019 14:42:56 +0100
|
||||
Subject: [PATCH] mac80211: do not call driver wake_tx_queue op during reconfig
|
||||
|
||||
There are several scenarios in which mac80211 can call drv_wake_tx_queue
|
||||
after ieee80211_restart_hw has been called and has not yet completed.
|
||||
Driver private structs are considered uninitialized until mac80211 has
|
||||
uploaded the vifs, stations and keys again, so using private tx queue
|
||||
data during that time is not safe.
|
||||
|
||||
The driver can also not rely on drv_reconfig_complete to figure out when
|
||||
it is safe to accept drv_wake_tx_queue calls again, because it is only
|
||||
called after all tx queues are woken again.
|
||||
|
||||
To fix this, bail out early in drv_wake_tx_queue if local->in_reconfig
|
||||
is set.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1166,6 +1166,9 @@ static inline void drv_wake_tx_queue(str
|
||||
{
|
||||
struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->txq.vif);
|
||||
|
||||
+ if (local->in_reconfig)
|
||||
+ return;
|
||||
+
|
||||
if (!check_sdata_in_driver(sdata))
|
||||
return;
|
||||
|
@ -0,0 +1,37 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Fri, 22 Feb 2019 13:21:15 +0100
|
||||
Subject: [PATCH] mac80211: allocate tailroom for forwarded mesh packets
|
||||
|
||||
Forwarded packets enter the tx path through ieee80211_add_pending_skb,
|
||||
which skips the ieee80211_skb_resize call.
|
||||
Fixes WARN_ON in ccmp_encrypt_skb and resulting packet loss.
|
||||
|
||||
Cc: stable@vger.kernel.org
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2598,6 +2598,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
u16 ac, q, hdrlen;
|
||||
+ int tailroom = 0;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
@@ -2684,8 +2685,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
if (!ifmsh->mshcfg.dot11MeshForwarding)
|
||||
goto out;
|
||||
|
||||
+ if (sdata->crypto_tx_tailroom_needed_cnt)
|
||||
+ tailroom = IEEE80211_ENCRYPT_TAILROOM;
|
||||
+
|
||||
fwd_skb = skb_copy_expand(skb, local->tx_headroom +
|
||||
- sdata->encrypt_headroom, 0, GFP_ATOMIC);
|
||||
+ sdata->encrypt_headroom,
|
||||
+ tailroom, GFP_ATOMIC);
|
||||
if (!fwd_skb)
|
||||
goto out;
|
||||
|
@ -67,7 +67,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
ccflags-y += -DDEBUG
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -1304,18 +1304,12 @@ static int __init ieee80211_init(void)
|
||||
@@ -1308,18 +1308,12 @@ static int __init ieee80211_init(void)
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@ -86,7 +86,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
rc80211_minstrel_exit();
|
||||
|
||||
return ret;
|
||||
@@ -1323,7 +1317,6 @@ static int __init ieee80211_init(void)
|
||||
@@ -1327,7 +1321,6 @@ static int __init ieee80211_init(void)
|
||||
|
||||
static void __exit ieee80211_exit(void)
|
||||
{
|
@ -136,82 +136,72 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
- MCS_GROUP(1, 0, BW_20),
|
||||
- MCS_GROUP(2, 0, BW_20),
|
||||
- MCS_GROUP(3, 0, BW_20),
|
||||
-
|
||||
- MCS_GROUP(1, 1, BW_20),
|
||||
- MCS_GROUP(2, 1, BW_20),
|
||||
- MCS_GROUP(3, 1, BW_20),
|
||||
-
|
||||
- MCS_GROUP(1, 0, BW_40),
|
||||
- MCS_GROUP(2, 0, BW_40),
|
||||
- MCS_GROUP(3, 0, BW_40),
|
||||
-
|
||||
- MCS_GROUP(1, 1, BW_40),
|
||||
- MCS_GROUP(2, 1, BW_40),
|
||||
- MCS_GROUP(3, 1, BW_40),
|
||||
-
|
||||
- CCK_GROUP,
|
||||
-
|
||||
- VHT_GROUP(1, 0, BW_20),
|
||||
- VHT_GROUP(2, 0, BW_20),
|
||||
- VHT_GROUP(3, 0, BW_20),
|
||||
-
|
||||
- VHT_GROUP(1, 1, BW_20),
|
||||
- VHT_GROUP(2, 1, BW_20),
|
||||
- VHT_GROUP(3, 1, BW_20),
|
||||
-
|
||||
- VHT_GROUP(1, 0, BW_40),
|
||||
- VHT_GROUP(2, 0, BW_40),
|
||||
- VHT_GROUP(3, 0, BW_40),
|
||||
-
|
||||
- VHT_GROUP(1, 1, BW_40),
|
||||
- VHT_GROUP(2, 1, BW_40),
|
||||
- VHT_GROUP(3, 1, BW_40),
|
||||
-
|
||||
- VHT_GROUP(1, 0, BW_80),
|
||||
- VHT_GROUP(2, 0, BW_80),
|
||||
- VHT_GROUP(3, 0, BW_80),
|
||||
-
|
||||
- VHT_GROUP(1, 1, BW_80),
|
||||
- VHT_GROUP(2, 1, BW_80),
|
||||
- VHT_GROUP(3, 1, BW_80),
|
||||
+ MCS_GROUP(1, 0, BW_20, 5),
|
||||
+ MCS_GROUP(2, 0, BW_20, 4),
|
||||
+ MCS_GROUP(3, 0, BW_20, 4),
|
||||
+
|
||||
|
||||
- MCS_GROUP(1, 1, BW_20),
|
||||
- MCS_GROUP(2, 1, BW_20),
|
||||
- MCS_GROUP(3, 1, BW_20),
|
||||
+ MCS_GROUP(1, 1, BW_20, 5),
|
||||
+ MCS_GROUP(2, 1, BW_20, 4),
|
||||
+ MCS_GROUP(3, 1, BW_20, 4),
|
||||
+
|
||||
|
||||
- MCS_GROUP(1, 0, BW_40),
|
||||
- MCS_GROUP(2, 0, BW_40),
|
||||
- MCS_GROUP(3, 0, BW_40),
|
||||
+ MCS_GROUP(1, 0, BW_40, 4),
|
||||
+ MCS_GROUP(2, 0, BW_40, 4),
|
||||
+ MCS_GROUP(3, 0, BW_40, 4),
|
||||
+
|
||||
|
||||
- MCS_GROUP(1, 1, BW_40),
|
||||
- MCS_GROUP(2, 1, BW_40),
|
||||
- MCS_GROUP(3, 1, BW_40),
|
||||
+ MCS_GROUP(1, 1, BW_40, 4),
|
||||
+ MCS_GROUP(2, 1, BW_40, 4),
|
||||
+ MCS_GROUP(3, 1, BW_40, 4),
|
||||
+
|
||||
|
||||
- CCK_GROUP,
|
||||
+ CCK_GROUP(8),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 0, BW_20),
|
||||
- VHT_GROUP(2, 0, BW_20),
|
||||
- VHT_GROUP(3, 0, BW_20),
|
||||
+ VHT_GROUP(1, 0, BW_20, 5),
|
||||
+ VHT_GROUP(2, 0, BW_20, 4),
|
||||
+ VHT_GROUP(3, 0, BW_20, 4),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 1, BW_20),
|
||||
- VHT_GROUP(2, 1, BW_20),
|
||||
- VHT_GROUP(3, 1, BW_20),
|
||||
+ VHT_GROUP(1, 1, BW_20, 5),
|
||||
+ VHT_GROUP(2, 1, BW_20, 4),
|
||||
+ VHT_GROUP(3, 1, BW_20, 4),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 0, BW_40),
|
||||
- VHT_GROUP(2, 0, BW_40),
|
||||
- VHT_GROUP(3, 0, BW_40),
|
||||
+ VHT_GROUP(1, 0, BW_40, 4),
|
||||
+ VHT_GROUP(2, 0, BW_40, 4),
|
||||
+ VHT_GROUP(3, 0, BW_40, 4),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 1, BW_40),
|
||||
- VHT_GROUP(2, 1, BW_40),
|
||||
- VHT_GROUP(3, 1, BW_40),
|
||||
+ VHT_GROUP(1, 1, BW_40, 4),
|
||||
+ VHT_GROUP(2, 1, BW_40, 4),
|
||||
+ VHT_GROUP(3, 1, BW_40, 4),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 0, BW_80),
|
||||
- VHT_GROUP(2, 0, BW_80),
|
||||
- VHT_GROUP(3, 0, BW_80),
|
||||
+ VHT_GROUP(1, 0, BW_80, 4),
|
||||
+ VHT_GROUP(2, 0, BW_80, 4),
|
||||
+ VHT_GROUP(3, 0, BW_80, 4),
|
||||
+
|
||||
|
||||
- VHT_GROUP(1, 1, BW_80),
|
||||
- VHT_GROUP(2, 1, BW_80),
|
||||
- VHT_GROUP(3, 1, BW_80),
|
||||
+ VHT_GROUP(1, 1, BW_80, 4),
|
||||
+ VHT_GROUP(2, 1, BW_80, 4),
|
||||
+ VHT_GROUP(3, 1, BW_80, 4),
|
@ -22,7 +22,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3194,6 +3194,7 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
@@ -3185,6 +3185,7 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
u8 max_subframes = sta->sta.max_amsdu_subframes;
|
||||
int max_frags = local->hw.max_tx_fragments;
|
||||
int max_amsdu_len = sta->sta.max_amsdu_len;
|
||||
@ -30,7 +30,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
__be16 len;
|
||||
void *data;
|
||||
bool ret = false;
|
||||
@@ -3225,12 +3226,13 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
@@ -3216,12 +3217,13 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
|
||||
head = skb_peek_tail(&flow->queue);
|
||||
if (!head)
|
||||
@ -46,7 +46,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
|
||||
nfrags = 1 + skb_shinfo(skb)->nr_frags;
|
||||
nfrags += 1 + skb_shinfo(head)->nr_frags;
|
||||
@@ -3288,6 +3290,9 @@ out_recalc:
|
||||
@@ -3279,6 +3281,9 @@ out_recalc:
|
||||
fq_recalc_backlog(fq, tin, flow);
|
||||
}
|
||||
out:
|
@ -1,5 +1,5 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 16 Jan 2019 21:47:54 +0100
|
||||
Date: Wed, 16 Jan 2019 22:32:12 +0100
|
||||
Subject: [PATCH] mac80211: minstrel_ht: add flag to indicate
|
||||
missing/inaccurate tx A-MPDU length
|
||||
|
||||
@ -9,13 +9,14 @@ to use a fixed value in its internal calculation (which gives better results
|
||||
than just defaulting to 1).
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2130,6 +2130,9 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
|
||||
* Padding will be added after ieee80211_hdr, before IV/LLC.
|
||||
@@ -2131,6 +2131,9 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't
|
||||
* support QoS NDP for AP probing - that's most likely a driver bug.
|
||||
*
|
||||
+ * @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
|
||||
+ * length in tx status information
|
||||
@ -24,19 +25,19 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -2176,6 +2179,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
|
||||
IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
|
||||
IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
|
||||
IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
|
||||
+ IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -215,6 +215,7 @@ static const char *hw_flag_names[] = {
|
||||
@@ -214,6 +214,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(SUPPORTS_TDLS_BUFFER_STA),
|
||||
FLAG(DEAUTH_NEED_MGD_TX_PREP),
|
||||
FLAG(DOESNT_SUPPORT_QOS_NDP),
|
||||
FLAG(NEEDS_ALIGNED4_SKBS),
|
||||
+ FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||
#undef FLAG
|
||||
};
|
@ -0,0 +1,21 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 13 Mar 2019 18:52:56 +0100
|
||||
Subject: [PATCH] mac80211: fix unaligned access in mesh table hash function
|
||||
|
||||
The pointer to the last four bytes of the address is not guaranteed to be
|
||||
aligned, so we need to use __get_unaligned_cpu32 here
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -23,7 +23,7 @@ static void mesh_path_free_rcu(struct me
|
||||
static u32 mesh_table_hash(const void *addr, u32 len, u32 seed)
|
||||
{
|
||||
/* Use last four bytes of hw addr as hash index */
|
||||
- return jhash_1word(*(u32 *)(addr+2), seed);
|
||||
+ return jhash_1word(__get_unaligned_cpu32(addr+2), seed);
|
||||
}
|
||||
|
||||
static const struct rhashtable_params mesh_rht_params = {
|
@ -0,0 +1,292 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:06 -0800
|
||||
Subject: [PATCH] mac80211: Add TXQ scheduling API
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds an API to mac80211 to handle scheduling of TXQs. The interface
|
||||
between driver and mac80211 for TXQ handling is changed by adding two new
|
||||
functions: ieee80211_next_txq(), which will return the next TXQ to schedule
|
||||
in the current round-robin rotation, and ieee80211_return_txq(), which the
|
||||
driver uses to indicate that it has finished scheduling a TXQ (which will
|
||||
then be put back in the scheduling rotation if it isn't empty).
|
||||
|
||||
The driver must call ieee80211_txq_schedule_start() at the start of each
|
||||
scheduling session, and ieee80211_txq_schedule_end() at the end. The API
|
||||
then guarantees that the same TXQ is not returned twice in the same
|
||||
session (so a driver can loop on ieee80211_next_txq() without worrying
|
||||
about breaking the loop.
|
||||
|
||||
Usage of the new API is optional, so drivers can be ported one at a time.
|
||||
In this patch, the actual scheduling performed by mac80211 is simple
|
||||
round-robin, but a subsequent commit adds airtime fairness awareness to the
|
||||
scheduler.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
[minor kernel-doc fix, propagate sparse locking checks out]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -107,9 +107,15 @@
|
||||
* The driver is expected to initialize its private per-queue data for stations
|
||||
* and interfaces in the .add_interface and .sta_add ops.
|
||||
*
|
||||
- * The driver can't access the queue directly. To dequeue a frame, it calls
|
||||
- * ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a queue, it
|
||||
- * calls the .wake_tx_queue driver op.
|
||||
+ * The driver can't access the queue directly. To dequeue a frame from a
|
||||
+ * txq, it calls ieee80211_tx_dequeue(). Whenever mac80211 adds a new frame to a
|
||||
+ * queue, it calls the .wake_tx_queue driver op.
|
||||
+ *
|
||||
+ * Drivers can optionally delegate responsibility for scheduling queues to
|
||||
+ * mac80211, to take advantage of airtime fairness accounting. In this case, to
|
||||
+ * obtain the next queue to pull frames from, the driver calls
|
||||
+ * ieee80211_next_txq(). The driver is then expected to return the txq using
|
||||
+ * ieee80211_return_txq().
|
||||
*
|
||||
* For AP powersave TIM handling, the driver only needs to indicate if it has
|
||||
* buffered packets in the driver specific data structures by calling
|
||||
@@ -5979,7 +5985,8 @@ void ieee80211_unreserve_tid(struct ieee
|
||||
* ieee80211_tx_dequeue - dequeue a packet from a software tx queue
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
- * @txq: pointer obtained from station or virtual interface
|
||||
+ * @txq: pointer obtained from station or virtual interface, or from
|
||||
+ * ieee80211_next_txq()
|
||||
*
|
||||
* Returns the skb if successful, %NULL if no frame was available.
|
||||
*/
|
||||
@@ -5987,6 +5994,54 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
struct ieee80211_txq *txq);
|
||||
|
||||
/**
|
||||
+ * ieee80211_next_txq - get next tx queue to pull packets from
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to return packets from.
|
||||
+ *
|
||||
+ * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
+ * and ieee80211_txq_schedule_end().
|
||||
+ * Returns the next txq if successful, %NULL if no queue is eligible. If a txq
|
||||
+ * is returned, it should be returned with ieee80211_return_txq() after the
|
||||
+ * driver has finished scheduling it.
|
||||
+ */
|
||||
+struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ *
|
||||
+ * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
+ * and ieee80211_txq_schedule_end().
|
||||
+ */
|
||||
+void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to acquire locks for
|
||||
+ *
|
||||
+ * Acquire locks needed to schedule TXQs from the given AC. Should be called
|
||||
+ * before ieee80211_next_txq() or ieee80211_return_txq().
|
||||
+ */
|
||||
+void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __acquires(txq_lock);
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @ac: AC number to acquire locks for
|
||||
+ *
|
||||
+ * Release locks previously acquired by ieee80211_txq_schedule_end().
|
||||
+ */
|
||||
+void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __releases(txq_lock);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
|
||||
*
|
||||
* The values are not guaranteed to be coherent with regard to each other, i.e.
|
||||
--- a/net/mac80211/agg-tx.c
|
||||
+++ b/net/mac80211/agg-tx.c
|
||||
@@ -229,7 +229,7 @@ ieee80211_agg_start_txq(struct sta_info
|
||||
clear_bit(IEEE80211_TXQ_STOP, &txqi->flags);
|
||||
local_bh_disable();
|
||||
rcu_read_lock();
|
||||
- drv_wake_tx_queue(sta->sdata->local, txqi);
|
||||
+ schedule_and_wake_txq(sta->sdata->local, txqi);
|
||||
rcu_read_unlock();
|
||||
local_bh_enable();
|
||||
}
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1176,6 +1176,15 @@ static inline void drv_wake_tx_queue(str
|
||||
local->ops->wake_tx_queue(&local->hw, &txq->txq);
|
||||
}
|
||||
|
||||
+static inline void schedule_and_wake_txq(struct ieee80211_local *local,
|
||||
+ struct txq_info *txqi)
|
||||
+{
|
||||
+ spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ ieee80211_return_txq(&local->hw, &txqi->txq);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ drv_wake_tx_queue(local, txqi);
|
||||
+}
|
||||
+
|
||||
static inline int drv_start_nan(struct ieee80211_local *local,
|
||||
struct ieee80211_sub_if_data *sdata,
|
||||
struct cfg80211_nan_conf *conf)
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -829,6 +829,8 @@ enum txq_info_flags {
|
||||
* a fq_flow which is already owned by a different tin
|
||||
* @def_cvars: codel vars for @def_flow
|
||||
* @frags: used to keep fragments created after dequeue
|
||||
+ * @schedule_order: used with ieee80211_local->active_txqs
|
||||
+ * @schedule_round: counter to prevent infinite loops on TXQ scheduling
|
||||
*/
|
||||
struct txq_info {
|
||||
struct fq_tin tin;
|
||||
@@ -836,6 +838,8 @@ struct txq_info {
|
||||
struct codel_vars def_cvars;
|
||||
struct codel_stats cstats;
|
||||
struct sk_buff_head frags;
|
||||
+ struct list_head schedule_order;
|
||||
+ u16 schedule_round;
|
||||
unsigned long flags;
|
||||
|
||||
/* keep last! */
|
||||
@@ -1127,6 +1131,11 @@ struct ieee80211_local {
|
||||
struct codel_vars *cvars;
|
||||
struct codel_params cparams;
|
||||
|
||||
+ /* protects active_txqs and txqi->schedule_order */
|
||||
+ spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
|
||||
+ struct list_head active_txqs[IEEE80211_NUM_ACS];
|
||||
+ u16 schedule_round[IEEE80211_NUM_ACS];
|
||||
+
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -652,6 +652,11 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
spin_lock_init(&local->rx_path_lock);
|
||||
spin_lock_init(&local->queue_stop_reason_lock);
|
||||
|
||||
+ for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
+ INIT_LIST_HEAD(&local->active_txqs[i]);
|
||||
+ spin_lock_init(&local->active_txq_lock[i]);
|
||||
+ }
|
||||
+
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -1244,7 +1244,7 @@ void ieee80211_sta_ps_deliver_wakeup(str
|
||||
if (!txq_has_queue(sta->sta.txq[i]))
|
||||
continue;
|
||||
|
||||
- drv_wake_tx_queue(local, to_txq_info(sta->sta.txq[i]));
|
||||
+ schedule_and_wake_txq(local, to_txq_info(sta->sta.txq[i]));
|
||||
}
|
||||
}
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1441,6 +1441,7 @@ void ieee80211_txq_init(struct ieee80211
|
||||
codel_vars_init(&txqi->def_cvars);
|
||||
codel_stats_init(&txqi->cstats);
|
||||
__skb_queue_head_init(&txqi->frags);
|
||||
+ INIT_LIST_HEAD(&txqi->schedule_order);
|
||||
|
||||
txqi->txq.vif = &sdata->vif;
|
||||
|
||||
@@ -1464,6 +1465,9 @@ void ieee80211_txq_purge(struct ieee8021
|
||||
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
|
||||
+ spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ list_del_init(&txqi->schedule_order);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
}
|
||||
|
||||
void ieee80211_txq_set_params(struct ieee80211_local *local)
|
||||
@@ -1580,7 +1584,7 @@ static bool ieee80211_queue_skb(struct i
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
spin_unlock_bh(&fq->lock);
|
||||
|
||||
- drv_wake_tx_queue(local, txqi);
|
||||
+ schedule_and_wake_txq(local, txqi);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -3602,6 +3606,60 @@ out:
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
|
||||
+struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct txq_info *txqi = NULL;
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+
|
||||
+ txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
+ struct txq_info,
|
||||
+ schedule_order);
|
||||
+
|
||||
+ if (!txqi || txqi->schedule_round == local->schedule_round[ac])
|
||||
+ return NULL;
|
||||
+
|
||||
+ list_del_init(&txqi->schedule_order);
|
||||
+ txqi->schedule_round = local->schedule_round[ac];
|
||||
+ return &txqi->txq;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_next_txq);
|
||||
+
|
||||
+void ieee80211_return_txq(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct txq_info *txqi = to_txq_info(txq);
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[txq->ac]);
|
||||
+
|
||||
+ if (list_empty(&txqi->schedule_order) &&
|
||||
+ (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets))
|
||||
+ list_add_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txq->ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
+
|
||||
+void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __acquires(txq_lock)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ local->schedule_round[ac]++;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
||||
+
|
||||
+void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
+ __releases(txq_lock)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_schedule_end);
|
||||
+
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
||||
u32 info_flags)
|
@ -0,0 +1,202 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:07 -0800
|
||||
Subject: [PATCH] cfg80211: Add airtime statistics and settings
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds TX airtime statistics to the cfg80211 station dump (to go along
|
||||
with the RX info already present), and adds a new parameter to set the
|
||||
airtime weight of each station. The latter allows userspace to implement
|
||||
policies for different stations by varying their weights.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
[rmanohar@codeaurora.org: fixed checkpatch warnings]
|
||||
Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
[move airtime weight != 0 check into policy]
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -988,6 +988,7 @@ enum station_parameters_apply_mask {
|
||||
* @support_p2p_ps: information if station supports P2P PS mechanism
|
||||
* @he_capa: HE capabilities of station
|
||||
* @he_capa_len: the length of the HE capabilities
|
||||
+ * @airtime_weight: airtime scheduler weight for this station
|
||||
*/
|
||||
struct station_parameters {
|
||||
const u8 *supported_rates;
|
||||
@@ -1017,6 +1018,7 @@ struct station_parameters {
|
||||
int support_p2p_ps;
|
||||
const struct ieee80211_he_cap_elem *he_capa;
|
||||
u8 he_capa_len;
|
||||
+ u16 airtime_weight;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1284,6 +1286,8 @@ struct cfg80211_tid_stats {
|
||||
* @rx_beacon_signal_avg: signal strength average (in dBm) for beacons received
|
||||
* from this peer
|
||||
* @rx_duration: aggregate PPDU duration(usecs) for all the frames from a peer
|
||||
+ * @tx_duration: aggregate PPDU duration(usecs) for all the frames to a peer
|
||||
+ * @airtime_weight: current airtime scheduling weight
|
||||
* @pertid: per-TID statistics, see &struct cfg80211_tid_stats, using the last
|
||||
* (IEEE80211_NUM_TIDS) index for MSDUs not encapsulated in QoS-MPDUs.
|
||||
* Note that this doesn't use the @filled bit, but is used if non-NULL.
|
||||
@@ -1330,12 +1334,15 @@ struct station_info {
|
||||
|
||||
u32 expected_throughput;
|
||||
|
||||
- u64 rx_beacon;
|
||||
+ u64 tx_duration;
|
||||
u64 rx_duration;
|
||||
+ u64 rx_beacon;
|
||||
u8 rx_beacon_signal_avg;
|
||||
struct cfg80211_tid_stats *pertid;
|
||||
s8 ack_signal;
|
||||
s8 avg_ack_signal;
|
||||
+
|
||||
+ u16 airtime_weight;
|
||||
};
|
||||
|
||||
#if IS_ENABLED(CPTCFG_CFG80211)
|
||||
@@ -2361,6 +2368,8 @@ enum wiphy_params_flags {
|
||||
WIPHY_PARAM_TXQ_QUANTUM = 1 << 8,
|
||||
};
|
||||
|
||||
+#define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256
|
||||
+
|
||||
/**
|
||||
* struct cfg80211_pmksa - PMK Security Association
|
||||
*
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -2241,6 +2241,9 @@ enum nl80211_commands {
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
*
|
||||
+ * @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
|
||||
+ * scheduler.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2682,6 +2685,14 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
|
||||
+ /* not backported yet */
|
||||
+ NL80211_ATTR_FTM_RESPONDER,
|
||||
+ NL80211_ATTR_FTM_RESPONDER_STATS,
|
||||
+ NL80211_ATTR_TIMEOUT,
|
||||
+ NL80211_ATTR_PEER_MEASUREMENTS,
|
||||
+
|
||||
+ NL80211_ATTR_AIRTIME_WEIGHT,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
@@ -3052,6 +3063,9 @@ enum nl80211_sta_bss_param {
|
||||
* @NL80211_STA_INFO_ACK_SIGNAL: signal strength of the last ACK frame(u8, dBm)
|
||||
* @NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG: avg signal strength of (data)
|
||||
* ACK frame (s8, dBm)
|
||||
+ * @NL80211_STA_INFO_TX_DURATION: aggregate PPDU duration for all frames
|
||||
+ * sent to the station (u64, usec)
|
||||
+ * @NL80211_STA_INFO_AIRTIME_WEIGHT: current airtime weight for station (u16)
|
||||
* @__NL80211_STA_INFO_AFTER_LAST: internal
|
||||
* @NL80211_STA_INFO_MAX: highest possible station info attribute
|
||||
*/
|
||||
@@ -3093,6 +3107,14 @@ enum nl80211_sta_info {
|
||||
NL80211_STA_INFO_ACK_SIGNAL,
|
||||
NL80211_STA_INFO_DATA_ACK_SIGNAL_AVG,
|
||||
|
||||
+ /* not backported yet */
|
||||
+ NL80211_STA_INFO_RX_MPDUS,
|
||||
+ NL80211_STA_INFO_FCS_ERROR_COUNT,
|
||||
+ NL80211_STA_INFO_CONNECTED_TO_GATE,
|
||||
+
|
||||
+ NL80211_STA_INFO_TX_DURATION,
|
||||
+ NL80211_STA_INFO_AIRTIME_WEIGHT,
|
||||
+
|
||||
/* keep last */
|
||||
__NL80211_STA_INFO_AFTER_LAST,
|
||||
NL80211_STA_INFO_MAX = __NL80211_STA_INFO_AFTER_LAST - 1
|
||||
@@ -5224,6 +5246,10 @@ enum nl80211_feature_flags {
|
||||
* except for supported rates from the probe request content if requested
|
||||
* by the %NL80211_SCAN_FLAG_MIN_PREQ_CONTENT flag.
|
||||
*
|
||||
+ * @NL80211_EXT_FEATURE_AIRTIME_FAIRNESS: Driver supports getting airtime
|
||||
+ * fairness for transmitted packets and has enabled airtime fairness
|
||||
+ * scheduling.
|
||||
+ *
|
||||
* @NUM_NL80211_EXT_FEATURES: number of extended features.
|
||||
* @MAX_NL80211_EXT_FEATURES: highest extended feature index.
|
||||
*/
|
||||
@@ -5260,6 +5286,12 @@ enum nl80211_ext_feature_index {
|
||||
NL80211_EXT_FEATURE_SCAN_RANDOM_SN,
|
||||
NL80211_EXT_FEATURE_SCAN_MIN_PREQ_CONTENT,
|
||||
|
||||
+ /* --- not backported yet --- */
|
||||
+ NL80211_EXT_FEATURE_CAN_REPLACE_PTK0,
|
||||
+ NL80211_EXT_FEATURE_ENABLE_FTM_RESPONDER,
|
||||
+
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS,
|
||||
+
|
||||
/* add new features before the definition below */
|
||||
NUM_NL80211_EXT_FEATURES,
|
||||
MAX_NL80211_EXT_FEATURES = NUM_NL80211_EXT_FEATURES - 1
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -430,6 +430,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
|
||||
[NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_HE_MAX_CAPABILITY_LEN },
|
||||
+ [NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -4658,6 +4659,11 @@ static int nl80211_send_station(struct s
|
||||
PUT_SINFO(PLID, plid, u16);
|
||||
PUT_SINFO(PLINK_STATE, plink_state, u8);
|
||||
PUT_SINFO_U64(RX_DURATION, rx_duration);
|
||||
+ PUT_SINFO_U64(TX_DURATION, tx_duration);
|
||||
+
|
||||
+ if (wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ PUT_SINFO(AIRTIME_WEIGHT, airtime_weight, u16);
|
||||
|
||||
switch (rdev->wiphy.signal_type) {
|
||||
case CFG80211_SIGNAL_TYPE_MBM:
|
||||
@@ -5294,6 +5300,15 @@ static int nl80211_set_station(struct sk
|
||||
nla_get_u8(info->attrs[NL80211_ATTR_OPMODE_NOTIF]);
|
||||
}
|
||||
|
||||
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
|
||||
+ params.airtime_weight =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
|
||||
+
|
||||
+ if (params.airtime_weight &&
|
||||
+ !wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
/* Include parameters for TDLS peer (will check later) */
|
||||
err = nl80211_set_station_tdls(info, ¶ms);
|
||||
if (err)
|
||||
@@ -5432,6 +5447,15 @@ static int nl80211_new_station(struct sk
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
+ if (info->attrs[NL80211_ATTR_AIRTIME_WEIGHT])
|
||||
+ params.airtime_weight =
|
||||
+ nla_get_u16(info->attrs[NL80211_ATTR_AIRTIME_WEIGHT]);
|
||||
+
|
||||
+ if (params.airtime_weight &&
|
||||
+ !wiphy_ext_feature_isset(&rdev->wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
err = nl80211_parse_sta_channel_info(info, ¶ms);
|
||||
if (err)
|
||||
return err;
|
@ -0,0 +1,522 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@toke.dk>
|
||||
Date: Tue, 18 Dec 2018 17:02:08 -0800
|
||||
Subject: [PATCH] mac80211: Add airtime accounting and scheduling to TXQs
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
This adds airtime accounting and scheduling to the mac80211 TXQ
|
||||
scheduler. A new callback, ieee80211_sta_register_airtime(), is added
|
||||
that drivers can call to report airtime usage for stations.
|
||||
|
||||
When airtime information is present, mac80211 will schedule TXQs
|
||||
(through ieee80211_next_txq()) in a way that enforces airtime fairness
|
||||
between active stations. This scheduling works the same way as the ath9k
|
||||
in-driver airtime fairness scheduling. If no airtime usage is reported
|
||||
by the driver, the scheduler will default to round-robin scheduling.
|
||||
|
||||
For drivers that don't control TXQ scheduling in software, a new API
|
||||
function, ieee80211_txq_may_transmit(), is added which the driver can use
|
||||
to check if the TXQ is eligible for transmission, or should be throttled to
|
||||
enforce fairness. Calls to this function must also be enclosed in
|
||||
ieee80211_txq_schedule_{start,end}() calls to ensure proper locking.
|
||||
|
||||
The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
|
||||
aligned aginst driver's own round-robin scheduler list. i.e it rotates
|
||||
the TXQ list till it makes the requested node becomes the first entry
|
||||
in TXQ list. Thus both the TXQ list and driver's list are in sync.
|
||||
|
||||
Co-developed-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
Signed-off-by: Louie Lu <git@louie.lu>
|
||||
[added debugfs write op to reset airtime counter]
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
|
||||
Signed-off-by: Rajkumar Manoharan <rmanohar@codeaurora.org>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2304,6 +2304,9 @@ enum ieee80211_hw_flags {
|
||||
* supported by HW.
|
||||
* @max_nan_de_entries: maximum number of NAN DE functions supported by the
|
||||
* device.
|
||||
+ *
|
||||
+ * @weight_multipler: Driver specific airtime weight multiplier used while
|
||||
+ * refilling deficit of each TXQ.
|
||||
*/
|
||||
struct ieee80211_hw {
|
||||
struct ieee80211_conf conf;
|
||||
@@ -2339,6 +2342,7 @@ struct ieee80211_hw {
|
||||
u8 n_cipher_schemes;
|
||||
const struct ieee80211_cipher_scheme *cipher_schemes;
|
||||
u8 max_nan_de_entries;
|
||||
+ u8 weight_multiplier;
|
||||
};
|
||||
|
||||
static inline bool _ieee80211_hw_check(struct ieee80211_hw *hw,
|
||||
@@ -5299,6 +5303,34 @@ void ieee80211_sta_eosp(struct ieee80211
|
||||
void ieee80211_send_eosp_nullfunc(struct ieee80211_sta *pubsta, int tid);
|
||||
|
||||
/**
|
||||
+ * ieee80211_sta_register_airtime - register airtime usage for a sta/tid
|
||||
+ *
|
||||
+ * Register airtime usage for a given sta on a given tid. The driver can call
|
||||
+ * this function to notify mac80211 that a station used a certain amount of
|
||||
+ * airtime. This information will be used by the TXQ scheduler to schedule
|
||||
+ * stations in a way that ensures airtime fairness.
|
||||
+ *
|
||||
+ * The reported airtime should as a minimum include all time that is spent
|
||||
+ * transmitting to the remote station, including overhead and padding, but not
|
||||
+ * including time spent waiting for a TXOP. If the time is not reported by the
|
||||
+ * hardware it can in some cases be calculated from the rate and known frame
|
||||
+ * composition. When possible, the time should include any failed transmission
|
||||
+ * attempts.
|
||||
+ *
|
||||
+ * The driver can either call this function synchronously for every packet or
|
||||
+ * aggregate, or asynchronously as airtime usage information becomes available.
|
||||
+ * TX and RX airtime can be reported together, or separately by setting one of
|
||||
+ * them to 0.
|
||||
+ *
|
||||
+ * @pubsta: the station
|
||||
+ * @tid: the TID to register airtime for
|
||||
+ * @tx_airtime: airtime used during TX (in usec)
|
||||
+ * @rx_airtime: airtime used during RX (in usec)
|
||||
+ */
|
||||
+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
|
||||
+ u32 tx_airtime, u32 rx_airtime);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_iter_keys - iterate keys programmed into the device
|
||||
* @hw: pointer obtained from ieee80211_alloc_hw()
|
||||
* @vif: virtual interface to iterate, may be %NULL for all
|
||||
@@ -6042,6 +6074,33 @@ void ieee80211_txq_schedule_end(struct i
|
||||
__releases(txq_lock);
|
||||
|
||||
/**
|
||||
+ * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
|
||||
+ *
|
||||
+ * This function is used to check whether given txq is allowed to transmit by
|
||||
+ * the airtime scheduler, and can be used by drivers to access the airtime
|
||||
+ * fairness accounting without going using the scheduling order enfored by
|
||||
+ * next_txq().
|
||||
+ *
|
||||
+ * Returns %true if the airtime scheduler thinks the TXQ should be allowed to
|
||||
+ * transmit, and %false if it should be throttled. This function can also have
|
||||
+ * the side effect of rotating the TXQ in the scheduler rotation, which will
|
||||
+ * eventually bring the deficit to positive and allow the station to transmit
|
||||
+ * again.
|
||||
+ *
|
||||
+ * The API ieee80211_txq_may_transmit() also ensures that TXQ list will be
|
||||
+ * aligned aginst driver's own round-robin scheduler list. i.e it rotates
|
||||
+ * the TXQ list till it makes the requested node becomes the first entry
|
||||
+ * in TXQ list. Thus both the TXQ list and driver's list are in sync. If this
|
||||
+ * function returns %true, the driver is expected to schedule packets
|
||||
+ * for transmission, and then return the TXQ through ieee80211_return_txq().
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ */
|
||||
+bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_get_depth - get pending frame/byte count of given txq
|
||||
*
|
||||
* The values are not guaranteed to be coherent with regard to each other, i.e.
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -1430,6 +1430,9 @@ static int sta_apply_parameters(struct i
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
sta_apply_mesh_params(local, sta, params);
|
||||
|
||||
+ if (params->airtime_weight)
|
||||
+ sta->airtime_weight = params->airtime_weight;
|
||||
+
|
||||
/* set the STA state after all sta info from usermode has been set */
|
||||
if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
|
||||
set & BIT(NL80211_STA_FLAG_ASSOCIATED)) {
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -380,6 +380,9 @@ void debugfs_hw_add(struct ieee80211_loc
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD_MODE(aqm, 0600);
|
||||
|
||||
+ debugfs_create_u16("airtime_flags", 0600,
|
||||
+ phyd, &local->airtime_flags);
|
||||
+
|
||||
statsd = debugfs_create_dir("statistics", phyd);
|
||||
|
||||
/* if the dir failed, don't put all the other things into the root! */
|
||||
--- a/net/mac80211/debugfs_sta.c
|
||||
+++ b/net/mac80211/debugfs_sta.c
|
||||
@@ -178,9 +178,9 @@ static ssize_t sta_aqm_read(struct file
|
||||
txqi->tin.tx_bytes,
|
||||
txqi->tin.tx_packets,
|
||||
txqi->flags,
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_STOP) ? "STOP" : "RUN",
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_AMPDU) ? " AMPDU" : "",
|
||||
- txqi->flags & (1<<IEEE80211_TXQ_NO_AMSDU) ? " NO-AMSDU" : "");
|
||||
+ test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ? "STOP" : "RUN",
|
||||
+ test_bit(IEEE80211_TXQ_AMPDU, &txqi->flags) ? " AMPDU" : "",
|
||||
+ test_bit(IEEE80211_TXQ_NO_AMSDU, &txqi->flags) ? " NO-AMSDU" : "");
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
@@ -192,6 +192,64 @@ static ssize_t sta_aqm_read(struct file
|
||||
}
|
||||
STA_OPS(aqm);
|
||||
|
||||
+static ssize_t sta_airtime_read(struct file *file, char __user *userbuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct sta_info *sta = file->private_data;
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ size_t bufsz = 200;
|
||||
+ char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
|
||||
+ u64 rx_airtime = 0, tx_airtime = 0;
|
||||
+ s64 deficit[IEEE80211_NUM_ACS];
|
||||
+ ssize_t rv;
|
||||
+ int ac;
|
||||
+
|
||||
+ if (!buf)
|
||||
+ return -ENOMEM;
|
||||
+
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ rx_airtime += sta->airtime[ac].rx_airtime;
|
||||
+ tx_airtime += sta->airtime[ac].tx_airtime;
|
||||
+ deficit[ac] = sta->airtime[ac].deficit;
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+ }
|
||||
+
|
||||
+ p += scnprintf(p, bufsz + buf - p,
|
||||
+ "RX: %llu us\nTX: %llu us\nWeight: %u\n"
|
||||
+ "Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
|
||||
+ rx_airtime,
|
||||
+ tx_airtime,
|
||||
+ sta->airtime_weight,
|
||||
+ deficit[0],
|
||||
+ deficit[1],
|
||||
+ deficit[2],
|
||||
+ deficit[3]);
|
||||
+
|
||||
+ rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
|
||||
+ kfree(buf);
|
||||
+ return rv;
|
||||
+}
|
||||
+
|
||||
+static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf,
|
||||
+ size_t count, loff_t *ppos)
|
||||
+{
|
||||
+ struct sta_info *sta = file->private_data;
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ int ac;
|
||||
+
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ sta->airtime[ac].rx_airtime = 0;
|
||||
+ sta->airtime[ac].tx_airtime = 0;
|
||||
+ sta->airtime[ac].deficit = sta->airtime_weight;
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+ }
|
||||
+
|
||||
+ return count;
|
||||
+}
|
||||
+STA_OPS_RW(airtime);
|
||||
+
|
||||
static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
@@ -546,6 +604,10 @@ void ieee80211_sta_debugfs_add(struct st
|
||||
if (local->ops->wake_tx_queue)
|
||||
DEBUGFS_ADD(aqm);
|
||||
|
||||
+ if (wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ DEBUGFS_ADD(airtime);
|
||||
+
|
||||
if (sizeof(sta->driver_buffered_tids) == sizeof(u32))
|
||||
debugfs_create_x32("driver_buffered_tids", 0400,
|
||||
sta->debugfs_dir,
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1136,6 +1136,8 @@ struct ieee80211_local {
|
||||
struct list_head active_txqs[IEEE80211_NUM_ACS];
|
||||
u16 schedule_round[IEEE80211_NUM_ACS];
|
||||
|
||||
+ u16 airtime_flags;
|
||||
+
|
||||
const struct ieee80211_ops *ops;
|
||||
|
||||
/*
|
||||
--- a/net/mac80211/main.c
|
||||
+++ b/net/mac80211/main.c
|
||||
@@ -656,6 +656,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
|
||||
INIT_LIST_HEAD(&local->active_txqs[i]);
|
||||
spin_lock_init(&local->active_txq_lock[i]);
|
||||
}
|
||||
+ local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
|
||||
|
||||
INIT_LIST_HEAD(&local->chanctx_list);
|
||||
mutex_init(&local->chanctx_mtx);
|
||||
@@ -1142,6 +1143,9 @@ int ieee80211_register_hw(struct ieee802
|
||||
if (!local->hw.max_nan_de_entries)
|
||||
local->hw.max_nan_de_entries = IEEE80211_MAX_NAN_INSTANCE_ID;
|
||||
|
||||
+ if (!local->hw.weight_multiplier)
|
||||
+ local->hw.weight_multiplier = 1;
|
||||
+
|
||||
result = ieee80211_wep_init(local);
|
||||
if (result < 0)
|
||||
wiphy_debug(local->hw.wiphy, "Failed to initialize wep: %d\n",
|
||||
--- a/net/mac80211/sta_info.c
|
||||
+++ b/net/mac80211/sta_info.c
|
||||
@@ -90,7 +90,6 @@ static void __cleanup_single_sta(struct
|
||||
struct tid_ampdu_tx *tid_tx;
|
||||
struct ieee80211_sub_if_data *sdata = sta->sdata;
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
- struct fq *fq = &local->fq;
|
||||
struct ps_data *ps;
|
||||
|
||||
if (test_sta_flag(sta, WLAN_STA_PS_STA) ||
|
||||
@@ -115,9 +114,7 @@ static void __cleanup_single_sta(struct
|
||||
for (i = 0; i < ARRAY_SIZE(sta->sta.txq); i++) {
|
||||
struct txq_info *txqi = to_txq_info(sta->sta.txq[i]);
|
||||
|
||||
- spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_purge(local, txqi);
|
||||
- spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,9 +378,12 @@ struct sta_info *sta_info_alloc(struct i
|
||||
if (sta_prepare_rate_control(local, sta, gfp))
|
||||
goto free_txq;
|
||||
|
||||
+ sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
|
||||
+
|
||||
for (i = 0; i < IEEE80211_NUM_ACS; i++) {
|
||||
skb_queue_head_init(&sta->ps_tx_buf[i]);
|
||||
skb_queue_head_init(&sta->tx_filtered[i]);
|
||||
+ sta->airtime[i].deficit = sta->airtime_weight;
|
||||
}
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_TIDS; i++)
|
||||
@@ -1821,6 +1821,27 @@ void ieee80211_sta_set_buffered(struct i
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_sta_set_buffered);
|
||||
|
||||
+void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
|
||||
+ u32 tx_airtime, u32 rx_airtime)
|
||||
+{
|
||||
+ struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
|
||||
+ struct ieee80211_local *local = sta->sdata->local;
|
||||
+ u8 ac = ieee80211_ac_from_tid(tid);
|
||||
+ u32 airtime = 0;
|
||||
+
|
||||
+ if (sta->local->airtime_flags & AIRTIME_USE_TX)
|
||||
+ airtime += tx_airtime;
|
||||
+ if (sta->local->airtime_flags & AIRTIME_USE_RX)
|
||||
+ airtime += rx_airtime;
|
||||
+
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
+ sta->airtime[ac].tx_airtime += tx_airtime;
|
||||
+ sta->airtime[ac].rx_airtime += rx_airtime;
|
||||
+ sta->airtime[ac].deficit -= airtime;
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_sta_register_airtime);
|
||||
+
|
||||
int sta_info_move_state(struct sta_info *sta,
|
||||
enum ieee80211_sta_state new_state)
|
||||
{
|
||||
@@ -2183,6 +2204,23 @@ void sta_set_sinfo(struct sta_info *sta,
|
||||
sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_FAILED);
|
||||
}
|
||||
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_RX_DURATION))) {
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
+ sinfo->rx_duration += sta->airtime[ac].rx_airtime;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_RX_DURATION);
|
||||
+ }
|
||||
+
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_TX_DURATION))) {
|
||||
+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++)
|
||||
+ sinfo->tx_duration += sta->airtime[ac].tx_airtime;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_TX_DURATION);
|
||||
+ }
|
||||
+
|
||||
+ if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
|
||||
+ sinfo->airtime_weight = sta->airtime_weight;
|
||||
+ sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
|
||||
+ }
|
||||
+
|
||||
sinfo->rx_dropped_misc = sta->rx_stats.dropped;
|
||||
if (sta->pcpu_rx_stats) {
|
||||
for_each_possible_cpu(cpu) {
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -127,6 +127,16 @@ enum ieee80211_agg_stop_reason {
|
||||
AGG_STOP_DESTROY_STA,
|
||||
};
|
||||
|
||||
+/* Debugfs flags to enable/disable use of RX/TX airtime in scheduler */
|
||||
+#define AIRTIME_USE_TX BIT(0)
|
||||
+#define AIRTIME_USE_RX BIT(1)
|
||||
+
|
||||
+struct airtime_info {
|
||||
+ u64 rx_airtime;
|
||||
+ u64 tx_airtime;
|
||||
+ s64 deficit;
|
||||
+};
|
||||
+
|
||||
struct sta_info;
|
||||
|
||||
/**
|
||||
@@ -563,6 +573,9 @@ struct sta_info {
|
||||
} tx_stats;
|
||||
u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
|
||||
|
||||
+ struct airtime_info airtime[IEEE80211_NUM_ACS];
|
||||
+ u16 airtime_weight;
|
||||
+
|
||||
/*
|
||||
* Aggregation information, locked with lock.
|
||||
*/
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -825,6 +825,12 @@ static void __ieee80211_tx_status(struct
|
||||
ieee80211_sta_tx_notify(sta->sdata, (void *) skb->data,
|
||||
acked, info->status.tx_time);
|
||||
|
||||
+ if (info->status.tx_time &&
|
||||
+ wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ ieee80211_sta_register_airtime(&sta->sta, tid,
|
||||
+ info->status.tx_time, 0);
|
||||
+
|
||||
if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
|
||||
if (info->flags & IEEE80211_TX_STAT_ACK) {
|
||||
if (sta->status_stats.lost_packets)
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1463,8 +1463,11 @@ void ieee80211_txq_purge(struct ieee8021
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
fq_tin_reset(fq, tin, fq_skb_free_func);
|
||||
ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+
|
||||
spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
list_del_init(&txqi->schedule_order);
|
||||
spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
@@ -3613,11 +3616,28 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
|
||||
lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
|
||||
+ begin:
|
||||
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
struct txq_info,
|
||||
schedule_order);
|
||||
+ if (!txqi)
|
||||
+ return NULL;
|
||||
|
||||
- if (!txqi || txqi->schedule_round == local->schedule_round[ac])
|
||||
+ if (txqi->txq.sta) {
|
||||
+ struct sta_info *sta = container_of(txqi->txq.sta,
|
||||
+ struct sta_info, sta);
|
||||
+
|
||||
+ if (sta->airtime[txqi->txq.ac].deficit < 0) {
|
||||
+ sta->airtime[txqi->txq.ac].deficit +=
|
||||
+ sta->airtime_weight;
|
||||
+ list_move_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txqi->txq.ac]);
|
||||
+ goto begin;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+
|
||||
+ if (txqi->schedule_round == local->schedule_round[ac])
|
||||
return NULL;
|
||||
|
||||
list_del_init(&txqi->schedule_order);
|
||||
@@ -3635,12 +3655,74 @@ void ieee80211_return_txq(struct ieee802
|
||||
lockdep_assert_held(&local->active_txq_lock[txq->ac]);
|
||||
|
||||
if (list_empty(&txqi->schedule_order) &&
|
||||
- (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets))
|
||||
- list_add_tail(&txqi->schedule_order,
|
||||
- &local->active_txqs[txq->ac]);
|
||||
+ (!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
|
||||
+ /* If airtime accounting is active, always enqueue STAs at the
|
||||
+ * head of the list to ensure that they only get moved to the
|
||||
+ * back by the airtime DRR scheduler once they have a negative
|
||||
+ * deficit. A station that already has a negative deficit will
|
||||
+ * get immediately moved to the back of the list on the next
|
||||
+ * call to ieee80211_next_txq().
|
||||
+ */
|
||||
+ if (txqi->txq.sta &&
|
||||
+ wiphy_ext_feature_isset(local->hw.wiphy,
|
||||
+ NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
|
||||
+ list_add(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txq->ac]);
|
||||
+ else
|
||||
+ list_add_tail(&txqi->schedule_order,
|
||||
+ &local->active_txqs[txq->ac]);
|
||||
+ }
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
|
||||
+bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
|
||||
+ struct sta_info *sta;
|
||||
+ u8 ac = txq->ac;
|
||||
+
|
||||
+ lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+
|
||||
+ if (!txqi->txq.sta)
|
||||
+ goto out;
|
||||
+
|
||||
+ if (list_empty(&txqi->schedule_order))
|
||||
+ goto out;
|
||||
+
|
||||
+ list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
|
||||
+ schedule_order) {
|
||||
+ if (iter == txqi)
|
||||
+ break;
|
||||
+
|
||||
+ if (!iter->txq.sta) {
|
||||
+ list_move_tail(&iter->schedule_order,
|
||||
+ &local->active_txqs[ac]);
|
||||
+ continue;
|
||||
+ }
|
||||
+ sta = container_of(iter->txq.sta, struct sta_info, sta);
|
||||
+ if (sta->airtime[ac].deficit < 0)
|
||||
+ sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
+ list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
|
||||
+ }
|
||||
+
|
||||
+ sta = container_of(txqi->txq.sta, struct sta_info, sta);
|
||||
+ if (sta->airtime[ac].deficit >= 0)
|
||||
+ goto out;
|
||||
+
|
||||
+ sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
+ list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
|
||||
+
|
||||
+ return false;
|
||||
+out:
|
||||
+ if (!list_empty(&txqi->schedule_order))
|
||||
+ list_del_init(&txqi->schedule_order);
|
||||
+
|
||||
+ return true;
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_txq_may_transmit);
|
||||
+
|
||||
void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
__acquires(txq_lock)
|
||||
{
|
@ -0,0 +1,73 @@
|
||||
From: =?UTF-8?q?Toke=20H=C3=B8iland-J=C3=B8rgensen?= <toke@redhat.com>
|
||||
Date: Tue, 22 Jan 2019 15:20:16 +0100
|
||||
Subject: [PATCH] mac80211: Expose ieee80211_schedule_txq() function
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
Content-Transfer-Encoding: 8bit
|
||||
|
||||
Since we reworked ieee80211_return_txq() so it assumes that the caller
|
||||
takes care of logging, we need another function that can be called without
|
||||
holding any locks. Introduce ieee80211_schedule_txq() which serves this
|
||||
purpose.
|
||||
|
||||
Signed-off-by: Toke Høiland-Jørgensen <toke@redhat.com>
|
||||
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -6074,6 +6074,19 @@ void ieee80211_txq_schedule_end(struct i
|
||||
__releases(txq_lock);
|
||||
|
||||
/**
|
||||
+ * ieee80211_schedule_txq - schedule a TXQ for transmission
|
||||
+ *
|
||||
+ * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
+ *
|
||||
+ * Schedules a TXQ for transmission if it is not already scheduled. Takes a
|
||||
+ * lock, which means it must *not* be called between
|
||||
+ * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end()
|
||||
+ */
|
||||
+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
+ __acquires(txq_lock) __releases(txq_lock);
|
||||
+
|
||||
+/**
|
||||
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
|
||||
*
|
||||
* This function is used to check whether given txq is allowed to transmit by
|
||||
--- a/net/mac80211/driver-ops.h
|
||||
+++ b/net/mac80211/driver-ops.h
|
||||
@@ -1179,9 +1179,7 @@ static inline void drv_wake_tx_queue(str
|
||||
static inline void schedule_and_wake_txq(struct ieee80211_local *local,
|
||||
struct txq_info *txqi)
|
||||
{
|
||||
- spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
- ieee80211_return_txq(&local->hw, &txqi->txq);
|
||||
- spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
|
||||
+ ieee80211_schedule_txq(&local->hw, &txqi->txq);
|
||||
drv_wake_tx_queue(local, txqi);
|
||||
}
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3675,6 +3675,19 @@ void ieee80211_return_txq(struct ieee802
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
|
||||
+void ieee80211_schedule_txq(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
+ __acquires(txq_lock) __releases(txq_lock)
|
||||
+{
|
||||
+ struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct txq_info *txqi = to_txq_info(txq);
|
||||
+
|
||||
+ spin_lock_bh(&local->active_txq_lock[txq->ac]);
|
||||
+ ieee80211_return_txq(hw, txq);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[txq->ac]);
|
||||
+}
|
||||
+EXPORT_SYMBOL(ieee80211_schedule_txq);
|
||||
+
|
||||
bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
|
||||
struct ieee80211_txq *txq)
|
||||
{
|
@ -2,11 +2,11 @@ From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Date: Fri, 19 Feb 2016 11:01:49 +0100
|
||||
Subject: [PATCH] mac80211: add hdrlen to ieee80211_tx_data
|
||||
|
||||
Add hdrlen to ieee80211_tx_data and use this
|
||||
when wep/ccmd/tkip. This is preparation for
|
||||
aligned4 code.
|
||||
This is preparation for adding support for inserting padding between the
|
||||
802.11 header and LLC data
|
||||
|
||||
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
@ -48,25 +48,34 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
tx->sta = sta;
|
||||
@@ -3507,6 +3507,7 @@ begin:
|
||||
@@ -3525,6 +3525,7 @@ begin:
|
||||
tx.local = local;
|
||||
tx.skb = skb;
|
||||
tx.sdata = vif_to_sdata(info->control.vif);
|
||||
+ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
||||
+ tx.hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (txq->sta)
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
@@ -3843,6 +3844,7 @@ ieee80211_build_data_template(struct iee
|
||||
@@ -3551,7 +3552,7 @@ begin:
|
||||
|
||||
if (tx.key &&
|
||||
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
|
||||
- pn_offs = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ pn_offs = tx.hdrlen;
|
||||
|
||||
ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
|
||||
tx.key, skb);
|
||||
@@ -4008,6 +4009,7 @@ ieee80211_build_data_template(struct iee
|
||||
hdr = (void *)skb->data;
|
||||
tx.sta = sta_info_get(sdata, hdr->addr1);
|
||||
tx.skb = skb;
|
||||
+ tx.hdrlen = ieee80211_padded_hdrlen(&tx.local->hw, hdr->frame_control);
|
||||
+ tx.hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
|
||||
if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) {
|
||||
rcu_read_unlock();
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1290,6 +1290,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||
@@ -1390,6 +1390,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
@ -74,7 +83,7 @@ Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
int err;
|
||||
|
||||
/* 24 + 6 = header + auth_algo + auth_transaction + status_code */
|
||||
@@ -1313,8 +1314,10 @@ void ieee80211_send_auth(struct ieee8021
|
||||
@@ -1413,8 +1414,10 @@ void ieee80211_send_auth(struct ieee8021
|
||||
skb_put_data(skb, extra, extra_len);
|
||||
|
||||
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
@ -0,0 +1,304 @@
|
||||
From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Date: Sun, 10 Mar 2019 17:22:08 +0100
|
||||
Subject: [PATCH] mac80211: add TX_NEEDS_ALIGNED4_SKBS hw flag
|
||||
|
||||
The driver should set this flag if the hardware requires tx skb data
|
||||
(starting with the LLC header) to be aligned to 4 bytes.
|
||||
|
||||
Padding is added after ieee80211_hdr, before IV/LLC.
|
||||
|
||||
Before this patch, we have to do memmove(hdrlen) twice in the driver:
|
||||
Once before we pass this to HW and once again in tx completion
|
||||
(to fix up the skb for monitor mode).
|
||||
|
||||
With this patch we can skip this memmove() and thus reduce CPU cycles in
|
||||
the data path.
|
||||
|
||||
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2140,6 +2140,9 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN: Driver does not report accurate A-MPDU
|
||||
* length in tx status information
|
||||
*
|
||||
+ * @IEEE80211_HW_TX_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
|
||||
+ * Padding will be added after ieee80211_hdr, before IV/LLC.
|
||||
+ *
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -2186,6 +2189,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
|
||||
IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
|
||||
IEEE80211_HW_TX_STATUS_NO_AMPDU_LEN,
|
||||
+ IEEE80211_HW_TX_NEEDS_ALIGNED4_SKBS,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
@@ -2472,6 +2476,40 @@ ieee80211_get_alt_retry_rate(const struc
|
||||
void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb);
|
||||
|
||||
/**
|
||||
+ * ieee80211_hdr_padsize - get size of padding between 802.11 header and LLC
|
||||
+ * @hw: the hardware
|
||||
+ * @hdrlen: 802.11 header length
|
||||
+ */
|
||||
+static inline unsigned int
|
||||
+ieee80211_hdr_padsize(struct ieee80211_hw *hw, unsigned int hdrlen)
|
||||
+{
|
||||
+ /*
|
||||
+ * While hdrlen is already aligned to two-byte boundaries,
|
||||
+ * simple check with & 2 will return correct padsize.
|
||||
+ */
|
||||
+ if (ieee80211_hw_check(hw, TX_NEEDS_ALIGNED4_SKBS))
|
||||
+ return hdrlen & 2;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+/**
|
||||
+ * ieee80211_padded_hdrlen - get padded 802.11 header size
|
||||
+ * @hw: the hardware
|
||||
+ * @fc: frame control field in little-endian format
|
||||
+ */
|
||||
+static inline unsigned int
|
||||
+ieee80211_padded_hdrlen(struct ieee80211_hw *hw, __le16 fc)
|
||||
+{
|
||||
+ unsigned int hdrlen;
|
||||
+
|
||||
+ hdrlen = ieee80211_hdrlen(fc);
|
||||
+ hdrlen += ieee80211_hdr_padsize(hw, hdrlen);
|
||||
+
|
||||
+ return hdrlen;
|
||||
+}
|
||||
+
|
||||
+
|
||||
+/**
|
||||
* DOC: Hardware crypto acceleration
|
||||
*
|
||||
* mac80211 is capable of taking advantage of many hardware
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1871,6 +1871,10 @@ int ieee80211_if_add(struct ieee80211_lo
|
||||
+ 8 /* rfc1042/bridge tunnel */
|
||||
- ETH_HLEN /* ethernet hard_header_len */
|
||||
+ IEEE80211_ENCRYPT_HEADROOM;
|
||||
+
|
||||
+ if (ieee80211_hw_check(&local->hw, TX_NEEDS_ALIGNED4_SKBS))
|
||||
+ ndev->needed_headroom += 2; /* padding */
|
||||
+
|
||||
ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
|
||||
|
||||
ret = dev_alloc_name(ndev, ndev->name);
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -103,13 +103,15 @@ void mesh_path_assign_nexthop(struct mes
|
||||
static void prepare_for_gate(struct sk_buff *skb, char *dst_addr,
|
||||
struct mesh_path *gate_mpath)
|
||||
{
|
||||
+ struct ieee80211_sub_if_data *sdata = gate_mpath->sdata;
|
||||
+ struct ieee80211_hw *hw = &sdata->local->hw;
|
||||
struct ieee80211_hdr *hdr;
|
||||
struct ieee80211s_hdr *mshdr;
|
||||
int mesh_hdrlen, hdrlen;
|
||||
char *next_hop;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
||||
mshdr = (struct ieee80211s_hdr *) (skb->data + hdrlen);
|
||||
|
||||
if (!(mshdr->flags & MESH_FLAGS_AE)) {
|
||||
--- a/net/mac80211/rx.c
|
||||
+++ b/net/mac80211/rx.c
|
||||
@@ -2597,7 +2597,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
struct ieee80211_local *local = rx->local;
|
||||
struct ieee80211_sub_if_data *sdata = rx->sdata;
|
||||
struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
|
||||
- u16 ac, q, hdrlen;
|
||||
+ u16 ac, q, hdrlen, padsize;
|
||||
int tailroom = 0;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
@@ -2688,7 +2688,9 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
if (sdata->crypto_tx_tailroom_needed_cnt)
|
||||
tailroom = IEEE80211_ENCRYPT_TAILROOM;
|
||||
|
||||
- fwd_skb = skb_copy_expand(skb, local->tx_headroom +
|
||||
+ padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
|
||||
+
|
||||
+ fwd_skb = skb_copy_expand(skb, local->tx_headroom + padsize +
|
||||
sdata->encrypt_headroom,
|
||||
tailroom, GFP_ATOMIC);
|
||||
if (!fwd_skb)
|
||||
@@ -2720,6 +2722,12 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
|
||||
return RX_DROP_MONITOR;
|
||||
}
|
||||
|
||||
+ if (padsize) {
|
||||
+ skb_push(fwd_skb, padsize);
|
||||
+ memmove(fwd_skb->data, skb->data + padsize, hdrlen);
|
||||
+ memset(fwd_skb->data + hdrlen, 0, padsize);
|
||||
+ }
|
||||
+
|
||||
IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, fwded_frames);
|
||||
ieee80211_add_pending_skb(local, fwd_skb);
|
||||
out:
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -311,7 +311,7 @@ struct ieee80211_fast_tx {
|
||||
u8 hdr_len;
|
||||
u8 sa_offs, da_offs, pn_offs;
|
||||
u8 band;
|
||||
- u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
|
||||
+ u8 hdr[30 + 2 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
|
||||
sizeof(rfc1042_header)] __aligned(2);
|
||||
|
||||
struct rcu_head rcu_head;
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -515,6 +515,7 @@ static void ieee80211_report_used_skb(st
|
||||
{
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
+ struct ieee80211_hw *hw = &local->hw;
|
||||
bool acked = info->flags & IEEE80211_TX_STAT_ACK;
|
||||
|
||||
if (dropped)
|
||||
@@ -531,7 +532,7 @@ static void ieee80211_report_used_skb(st
|
||||
skb->dev = NULL;
|
||||
} else {
|
||||
unsigned int hdr_size =
|
||||
- ieee80211_hdrlen(hdr->frame_control);
|
||||
+ ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
||||
|
||||
/* Check to see if packet is a TDLS teardown packet */
|
||||
if (ieee80211_is_data(hdr->frame_control) &&
|
||||
@@ -655,9 +656,22 @@ void ieee80211_tx_monitor(struct ieee802
|
||||
struct sk_buff *skb2;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
+ struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct net_device *prev_dev = NULL;
|
||||
+ unsigned int hdrlen, padsize;
|
||||
int rtap_len;
|
||||
|
||||
+ /* Remove padding if was added */
|
||||
+ if (ieee80211_hw_check(&local->hw, TX_NEEDS_ALIGNED4_SKBS)) {
|
||||
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
|
||||
+
|
||||
+ if (padsize && skb->len > hdrlen + padsize) {
|
||||
+ memmove(skb->data + padsize, skb->data, hdrlen);
|
||||
+ skb_pull(skb, padsize);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* send frame to monitor interfaces now */
|
||||
rtap_len = ieee80211_tx_radiotap_len(info);
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
|
||||
--- a/net/mac80211/tkip.c
|
||||
+++ b/net/mac80211/tkip.c
|
||||
@@ -201,10 +201,12 @@ void ieee80211_get_tkip_p2k(struct ieee8
|
||||
{
|
||||
struct ieee80211_key *key = (struct ieee80211_key *)
|
||||
container_of(keyconf, struct ieee80211_key, conf);
|
||||
+ struct ieee80211_hw *hw = &key->local->hw;
|
||||
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
struct tkip_ctx *ctx = &key->u.tkip.tx;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
- const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
|
||||
+ const u8 *data = (u8 *)hdr + ieee80211_padded_hdrlen(hw,
|
||||
+ hdr->frame_control);
|
||||
u32 iv32 = get_unaligned_le32(&data[4]);
|
||||
u16 iv16 = data[2] | (data[0] << 8);
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1175,8 +1175,7 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
-
|
||||
- tx->hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ tx->hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
|
||||
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
@@ -2222,7 +2221,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
goto fail;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
||||
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
|
||||
|
||||
if (skb->len < len_rthdr + hdrlen)
|
||||
goto fail;
|
||||
@@ -2440,7 +2439,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_sub_if_data *ap_sdata;
|
||||
enum nl80211_band band;
|
||||
- int ret;
|
||||
+ int padsize, ret;
|
||||
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
@@ -2739,7 +2738,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
}
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
+ padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
|
||||
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
|
||||
+ head_need += padsize;
|
||||
|
||||
/*
|
||||
* So we need to modify the skb header and hence need a copy of
|
||||
@@ -2772,6 +2773,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
|
||||
#endif
|
||||
|
||||
+ if (padsize)
|
||||
+ memset(skb_push(skb, padsize), 0, padsize);
|
||||
+
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
__le16 *qos_control;
|
||||
|
||||
@@ -2947,6 +2951,8 @@ void ieee80211_check_fast_xmit(struct st
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
}
|
||||
|
||||
+ build.hdr_len += ieee80211_hdr_padsize(&local->hw, build.hdr_len);
|
||||
+
|
||||
/* We store the key here so there's no point in using rcu_dereference()
|
||||
* but that's fine because the code that changes the pointers will call
|
||||
* this function after doing so. For a single CPU that would be enough,
|
||||
@@ -3525,7 +3531,7 @@ begin:
|
||||
tx.local = local;
|
||||
tx.skb = skb;
|
||||
tx.sdata = vif_to_sdata(info->control.vif);
|
||||
- tx.hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ tx.hdrlen = ieee80211_padded_hdrlen(hw, hdr->frame_control);
|
||||
|
||||
if (txq->sta)
|
||||
tx.sta = container_of(txq->sta, struct sta_info, sta);
|
||||
@@ -4009,7 +4015,7 @@ ieee80211_build_data_template(struct iee
|
||||
hdr = (void *)skb->data;
|
||||
tx.sta = sta_info_get(sdata, hdr->addr1);
|
||||
tx.skb = skb;
|
||||
- tx.hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ tx.hdrlen = ieee80211_padded_hdrlen(&tx.local->hw, hdr->frame_control);
|
||||
|
||||
if (ieee80211_tx_h_select_key(&tx) != TX_CONTINUE) {
|
||||
rcu_read_unlock();
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -215,6 +215,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(DEAUTH_NEED_MGD_TX_PREP),
|
||||
FLAG(DOESNT_SUPPORT_QOS_NDP),
|
||||
FLAG(TX_STATUS_NO_AMPDU_LEN),
|
||||
+ FLAG(TX_NEEDS_ALIGNED4_SKBS),
|
||||
#undef FLAG
|
||||
};
|
||||
|
@ -0,0 +1,214 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Wed, 13 Mar 2019 19:09:22 +0100
|
||||
Subject: [PATCH] mac80211: rework locking for txq scheduling / airtime
|
||||
fairness
|
||||
|
||||
Holding the lock around the entire duration of tx scheduling can create
|
||||
some nasty lock contention, especially when processing airtime information
|
||||
from the tx status or the rx path.
|
||||
Improve locking by only holding the active_txq_lock for lookups / scheduling
|
||||
list modifications.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -6069,8 +6069,6 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
* @ac: AC number to return packets from.
|
||||
*
|
||||
- * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
- * and ieee80211_txq_schedule_end().
|
||||
* Returns the next txq if successful, %NULL if no queue is eligible. If a txq
|
||||
* is returned, it should be returned with ieee80211_return_txq() after the
|
||||
* driver has finished scheduling it.
|
||||
@@ -6078,51 +6076,41 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac);
|
||||
|
||||
/**
|
||||
- * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
|
||||
- *
|
||||
- * @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
- * @txq: pointer obtained from station or virtual interface
|
||||
- *
|
||||
- * Should only be called between calls to ieee80211_txq_schedule_start()
|
||||
- * and ieee80211_txq_schedule_end().
|
||||
- */
|
||||
-void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
|
||||
-
|
||||
-/**
|
||||
- * ieee80211_txq_schedule_start - acquire locks for safe scheduling of an AC
|
||||
+ * ieee80211_txq_schedule_start - start new scheduling round for TXQs
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
* @ac: AC number to acquire locks for
|
||||
*
|
||||
- * Acquire locks needed to schedule TXQs from the given AC. Should be called
|
||||
- * before ieee80211_next_txq() or ieee80211_return_txq().
|
||||
+ * Should be called before ieee80211_next_txq() or ieee80211_return_txq().
|
||||
*/
|
||||
-void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
- __acquires(txq_lock);
|
||||
+void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac);
|
||||
+
|
||||
+/* (deprecated) */
|
||||
+static inline void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
+{
|
||||
+}
|
||||
|
||||
/**
|
||||
- * ieee80211_txq_schedule_end - release locks for safe scheduling of an AC
|
||||
+ * ieee80211_schedule_txq - schedule a TXQ for transmission
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
- * @ac: AC number to acquire locks for
|
||||
+ * @txq: pointer obtained from station or virtual interface
|
||||
*
|
||||
- * Release locks previously acquired by ieee80211_txq_schedule_end().
|
||||
+ * Schedules a TXQ for transmission if it is not already scheduled.
|
||||
*/
|
||||
-void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
- __releases(txq_lock);
|
||||
+void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
|
||||
|
||||
/**
|
||||
- * ieee80211_schedule_txq - schedule a TXQ for transmission
|
||||
+ * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
|
||||
*
|
||||
* @hw: pointer as obtained from ieee80211_alloc_hw()
|
||||
* @txq: pointer obtained from station or virtual interface
|
||||
- *
|
||||
- * Schedules a TXQ for transmission if it is not already scheduled. Takes a
|
||||
- * lock, which means it must *not* be called between
|
||||
- * ieee80211_txq_schedule_start() and ieee80211_txq_schedule_end()
|
||||
*/
|
||||
-void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
- __acquires(txq_lock) __releases(txq_lock);
|
||||
+static inline void
|
||||
+ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
|
||||
+{
|
||||
+ ieee80211_schedule_txq(hw, txq);
|
||||
+}
|
||||
|
||||
/**
|
||||
* ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3619,16 +3619,17 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
|
||||
struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
+ struct ieee80211_txq *ret = NULL;
|
||||
struct txq_info *txqi = NULL;
|
||||
|
||||
- lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
begin:
|
||||
txqi = list_first_entry_or_null(&local->active_txqs[ac],
|
||||
struct txq_info,
|
||||
schedule_order);
|
||||
if (!txqi)
|
||||
- return NULL;
|
||||
+ goto out;
|
||||
|
||||
if (txqi->txq.sta) {
|
||||
struct sta_info *sta = container_of(txqi->txq.sta,
|
||||
@@ -3645,21 +3646,25 @@ struct ieee80211_txq *ieee80211_next_txq
|
||||
|
||||
|
||||
if (txqi->schedule_round == local->schedule_round[ac])
|
||||
- return NULL;
|
||||
+ goto out;
|
||||
|
||||
list_del_init(&txqi->schedule_order);
|
||||
txqi->schedule_round = local->schedule_round[ac];
|
||||
- return &txqi->txq;
|
||||
+ ret = &txqi->txq;
|
||||
+
|
||||
+out:
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
+ return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_next_txq);
|
||||
|
||||
-void ieee80211_return_txq(struct ieee80211_hw *hw,
|
||||
- struct ieee80211_txq *txq)
|
||||
+void ieee80211_schedule_txq(struct ieee80211_hw *hw,
|
||||
+ struct ieee80211_txq *txq)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
struct txq_info *txqi = to_txq_info(txq);
|
||||
|
||||
- lockdep_assert_held(&local->active_txq_lock[txq->ac]);
|
||||
+ spin_lock_bh(&local->active_txq_lock[txq->ac]);
|
||||
|
||||
if (list_empty(&txqi->schedule_order) &&
|
||||
(!skb_queue_empty(&txqi->frags) || txqi->tin.backlog_packets)) {
|
||||
@@ -3679,18 +3684,7 @@ void ieee80211_return_txq(struct ieee802
|
||||
list_add_tail(&txqi->schedule_order,
|
||||
&local->active_txqs[txq->ac]);
|
||||
}
|
||||
-}
|
||||
-EXPORT_SYMBOL(ieee80211_return_txq);
|
||||
|
||||
-void ieee80211_schedule_txq(struct ieee80211_hw *hw,
|
||||
- struct ieee80211_txq *txq)
|
||||
- __acquires(txq_lock) __releases(txq_lock)
|
||||
-{
|
||||
- struct ieee80211_local *local = hw_to_local(hw);
|
||||
- struct txq_info *txqi = to_txq_info(txq);
|
||||
-
|
||||
- spin_lock_bh(&local->active_txq_lock[txq->ac]);
|
||||
- ieee80211_return_txq(hw, txq);
|
||||
spin_unlock_bh(&local->active_txq_lock[txq->ac]);
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_schedule_txq);
|
||||
@@ -3703,7 +3697,7 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
struct sta_info *sta;
|
||||
u8 ac = txq->ac;
|
||||
|
||||
- lockdep_assert_held(&local->active_txq_lock[ac]);
|
||||
+ spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
if (!txqi->txq.sta)
|
||||
goto out;
|
||||
@@ -3733,34 +3727,27 @@ bool ieee80211_txq_may_transmit(struct i
|
||||
|
||||
sta->airtime[ac].deficit += sta->airtime_weight;
|
||||
list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
return false;
|
||||
out:
|
||||
if (!list_empty(&txqi->schedule_order))
|
||||
list_del_init(&txqi->schedule_order);
|
||||
+ spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
|
||||
return true;
|
||||
}
|
||||
EXPORT_SYMBOL(ieee80211_txq_may_transmit);
|
||||
|
||||
void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
|
||||
- __acquires(txq_lock)
|
||||
{
|
||||
struct ieee80211_local *local = hw_to_local(hw);
|
||||
|
||||
spin_lock_bh(&local->active_txq_lock[ac]);
|
||||
local->schedule_round[ac]++;
|
||||
-}
|
||||
-EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
||||
-
|
||||
-void ieee80211_txq_schedule_end(struct ieee80211_hw *hw, u8 ac)
|
||||
- __releases(txq_lock)
|
||||
-{
|
||||
- struct ieee80211_local *local = hw_to_local(hw);
|
||||
-
|
||||
spin_unlock_bh(&local->active_txq_lock[ac]);
|
||||
}
|
||||
-EXPORT_SYMBOL(ieee80211_txq_schedule_end);
|
||||
+EXPORT_SYMBOL(ieee80211_txq_schedule_start);
|
||||
|
||||
void __ieee80211_subif_start_xmit(struct sk_buff *skb,
|
||||
struct net_device *dev,
|
@ -0,0 +1,96 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 16 Mar 2019 17:43:58 +0100
|
||||
Subject: [PATCH] mac80211: mesh: drop redundant rcu_read_lock/unlock calls
|
||||
|
||||
The callers of these functions are all within RCU locked sections
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/mesh_hwmp.c
|
||||
+++ b/net/mac80211/mesh_hwmp.c
|
||||
@@ -1112,16 +1112,13 @@ int mesh_nexthop_resolve(struct ieee8021
|
||||
struct mesh_path *mpath;
|
||||
struct sk_buff *skb_to_free = NULL;
|
||||
u8 *target_addr = hdr->addr3;
|
||||
- int err = 0;
|
||||
|
||||
/* Nulls are only sent to peers for PS and should be pre-addressed */
|
||||
if (ieee80211_is_qos_nullfunc(hdr->frame_control))
|
||||
return 0;
|
||||
|
||||
- rcu_read_lock();
|
||||
- err = mesh_nexthop_lookup(sdata, skb);
|
||||
- if (!err)
|
||||
- goto endlookup;
|
||||
+ if (!mesh_nexthop_lookup(sdata, skb))
|
||||
+ return 0;
|
||||
|
||||
/* no nexthop found, start resolving */
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
@@ -1129,8 +1126,7 @@ int mesh_nexthop_resolve(struct ieee8021
|
||||
mpath = mesh_path_add(sdata, target_addr);
|
||||
if (IS_ERR(mpath)) {
|
||||
mesh_path_discard_frame(sdata, skb);
|
||||
- err = PTR_ERR(mpath);
|
||||
- goto endlookup;
|
||||
+ return PTR_ERR(mpath);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,13 +1139,10 @@ int mesh_nexthop_resolve(struct ieee8021
|
||||
info->flags |= IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
ieee80211_set_qos_hdr(sdata, skb);
|
||||
skb_queue_tail(&mpath->frame_queue, skb);
|
||||
- err = -ENOENT;
|
||||
if (skb_to_free)
|
||||
mesh_path_discard_frame(sdata, skb_to_free);
|
||||
|
||||
-endlookup:
|
||||
- rcu_read_unlock();
|
||||
- return err;
|
||||
+ return -ENOENT;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1169,13 +1162,10 @@ int mesh_nexthop_lookup(struct ieee80211
|
||||
struct sta_info *next_hop;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
|
||||
u8 *target_addr = hdr->addr3;
|
||||
- int err = -ENOENT;
|
||||
|
||||
- rcu_read_lock();
|
||||
mpath = mesh_path_lookup(sdata, target_addr);
|
||||
-
|
||||
if (!mpath || !(mpath->flags & MESH_PATH_ACTIVE))
|
||||
- goto endlookup;
|
||||
+ return -ENOENT;
|
||||
|
||||
if (time_after(jiffies,
|
||||
mpath->exp_time -
|
||||
@@ -1190,12 +1180,10 @@ int mesh_nexthop_lookup(struct ieee80211
|
||||
memcpy(hdr->addr1, next_hop->sta.addr, ETH_ALEN);
|
||||
memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
|
||||
ieee80211_mps_set_frame_flags(sdata, next_hop, hdr);
|
||||
- err = 0;
|
||||
+ return 0;
|
||||
}
|
||||
|
||||
-endlookup:
|
||||
- rcu_read_unlock();
|
||||
- return err;
|
||||
+ return -ENOENT;
|
||||
}
|
||||
|
||||
void mesh_path_timer(struct timer_list *t)
|
||||
--- a/net/mac80211/mesh_pathtbl.c
|
||||
+++ b/net/mac80211/mesh_pathtbl.c
|
||||
@@ -217,7 +217,7 @@ static struct mesh_path *mpath_lookup(st
|
||||
{
|
||||
struct mesh_path *mpath;
|
||||
|
||||
- mpath = rhashtable_lookup_fast(&tbl->rhead, dst, mesh_rht_params);
|
||||
+ mpath = rhashtable_lookup(&tbl->rhead, dst, mesh_rht_params);
|
||||
|
||||
if (mpath && mpath_expired(mpath)) {
|
||||
spin_lock_bh(&mpath->state_lock);
|
@ -0,0 +1,124 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 16 Mar 2019 17:57:38 +0100
|
||||
Subject: [PATCH] mac80211: calculate hash for fq without holding fq->lock
|
||||
in itxq enqueue
|
||||
|
||||
Reduces lock contention on enqueue/dequeue of iTXQ packets
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/include/net/fq_impl.h
|
||||
+++ b/include/net/fq_impl.h
|
||||
@@ -107,21 +107,23 @@ begin:
|
||||
return skb;
|
||||
}
|
||||
|
||||
+static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb)
|
||||
+{
|
||||
+ u32 hash = skb_get_hash_perturb(skb, fq->perturbation);
|
||||
+
|
||||
+ return reciprocal_scale(hash, fq->flows_cnt);
|
||||
+}
|
||||
+
|
||||
static struct fq_flow *fq_flow_classify(struct fq *fq,
|
||||
- struct fq_tin *tin,
|
||||
+ struct fq_tin *tin, u32 idx,
|
||||
struct sk_buff *skb,
|
||||
fq_flow_get_default_t get_default_func)
|
||||
{
|
||||
struct fq_flow *flow;
|
||||
- u32 hash;
|
||||
- u32 idx;
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
- hash = skb_get_hash_perturb(skb, fq->perturbation);
|
||||
- idx = reciprocal_scale(hash, fq->flows_cnt);
|
||||
flow = &fq->flows[idx];
|
||||
-
|
||||
if (flow->tin && flow->tin != tin) {
|
||||
flow = get_default_func(fq, tin, idx, skb);
|
||||
tin->collisions++;
|
||||
@@ -153,7 +155,7 @@ static void fq_recalc_backlog(struct fq
|
||||
}
|
||||
|
||||
static void fq_tin_enqueue(struct fq *fq,
|
||||
- struct fq_tin *tin,
|
||||
+ struct fq_tin *tin, u32 idx,
|
||||
struct sk_buff *skb,
|
||||
fq_skb_free_t free_func,
|
||||
fq_flow_get_default_t get_default_func)
|
||||
@@ -163,7 +165,7 @@ static void fq_tin_enqueue(struct fq *fq
|
||||
|
||||
lockdep_assert_held(&fq->lock);
|
||||
|
||||
- flow = fq_flow_classify(fq, tin, skb, get_default_func);
|
||||
+ flow = fq_flow_classify(fq, tin, idx, skb, get_default_func);
|
||||
|
||||
flow->tin = tin;
|
||||
flow->backlog += skb->len;
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1390,11 +1390,15 @@ static void ieee80211_txq_enqueue(struct
|
||||
{
|
||||
struct fq *fq = &local->fq;
|
||||
struct fq_tin *tin = &txqi->tin;
|
||||
+ u32 flow_idx = fq_flow_idx(fq, skb);
|
||||
|
||||
ieee80211_set_skb_enqueue_time(skb);
|
||||
- fq_tin_enqueue(fq, tin, skb,
|
||||
+
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
+ fq_tin_enqueue(fq, tin, flow_idx, skb,
|
||||
fq_skb_free_func,
|
||||
fq_flow_get_default_func);
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
}
|
||||
|
||||
static bool fq_vlan_filter_func(struct fq *fq, struct fq_tin *tin,
|
||||
@@ -1564,7 +1568,6 @@ static bool ieee80211_queue_skb(struct i
|
||||
struct sta_info *sta,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
- struct fq *fq = &local->fq;
|
||||
struct ieee80211_vif *vif;
|
||||
struct txq_info *txqi;
|
||||
|
||||
@@ -1582,9 +1585,7 @@ static bool ieee80211_queue_skb(struct i
|
||||
if (!txqi)
|
||||
return false;
|
||||
|
||||
- spin_lock_bh(&fq->lock);
|
||||
ieee80211_txq_enqueue(local, txqi, skb);
|
||||
- spin_unlock_bh(&fq->lock);
|
||||
|
||||
schedule_and_wake_txq(local, txqi);
|
||||
|
||||
@@ -3198,6 +3199,7 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
u8 max_subframes = sta->sta.max_amsdu_subframes;
|
||||
int max_frags = local->hw.max_tx_fragments;
|
||||
int max_amsdu_len = sta->sta.max_amsdu_len;
|
||||
+ u32 flow_idx;
|
||||
int orig_truesize;
|
||||
__be16 len;
|
||||
void *data;
|
||||
@@ -3220,6 +3222,8 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
max_amsdu_len = min_t(int, max_amsdu_len,
|
||||
sta->sta.max_rc_amsdu_len);
|
||||
|
||||
+ flow_idx = fq_flow_idx(fq, skb);
|
||||
+
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
/* TODO: Ideally aggregation should be done on dequeue to remain
|
||||
@@ -3227,7 +3231,8 @@ static bool ieee80211_amsdu_aggregate(st
|
||||
*/
|
||||
|
||||
tin = &txqi->tin;
|
||||
- flow = fq_flow_classify(fq, tin, skb, fq_flow_get_default_func);
|
||||
+ flow = fq_flow_classify(fq, tin, flow_idx, skb,
|
||||
+ fq_flow_get_default_func);
|
||||
head = skb_peek_tail(&flow->queue);
|
||||
if (!head)
|
||||
goto unlock;
|
@ -0,0 +1,55 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 16 Mar 2019 18:00:12 +0100
|
||||
Subject: [PATCH] mac80211: run late dequeue late tx handlers without
|
||||
holding fq->lock
|
||||
|
||||
Reduces lock contention on enqueue/dequeue of iTXQ packets
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -3507,6 +3507,7 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
ieee80211_tx_result r;
|
||||
struct ieee80211_vif *vif = txq->vif;
|
||||
|
||||
+begin:
|
||||
spin_lock_bh(&fq->lock);
|
||||
|
||||
if (test_bit(IEEE80211_TXQ_STOP, &txqi->flags) ||
|
||||
@@ -3523,11 +3524,12 @@ struct sk_buff *ieee80211_tx_dequeue(str
|
||||
if (skb)
|
||||
goto out;
|
||||
|
||||
-begin:
|
||||
skb = fq_tin_dequeue(fq, tin, fq_tin_dequeue_func);
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+
|
||||
hdr = (struct ieee80211_hdr *)skb->data;
|
||||
info = IEEE80211_SKB_CB(skb);
|
||||
|
||||
@@ -3573,8 +3575,11 @@ begin:
|
||||
|
||||
skb = __skb_dequeue(&tx.skbs);
|
||||
|
||||
- if (!skb_queue_empty(&tx.skbs))
|
||||
+ if (!skb_queue_empty(&tx.skbs)) {
|
||||
+ spin_lock_bh(&fq->lock);
|
||||
skb_queue_splice_tail(&tx.skbs, &txqi->frags);
|
||||
+ spin_unlock_bh(&fq->lock);
|
||||
+ }
|
||||
}
|
||||
|
||||
if (skb && skb_has_frag_list(skb) &&
|
||||
@@ -3613,6 +3618,7 @@ begin:
|
||||
}
|
||||
|
||||
IEEE80211_SKB_CB(skb)->control.vif = vif;
|
||||
+ return skb;
|
||||
|
||||
out:
|
||||
spin_unlock_bh(&fq->lock);
|
@ -0,0 +1,22 @@
|
||||
From: Felix Fietkau <nbd@nbd.name>
|
||||
Date: Sat, 16 Mar 2019 18:01:53 +0100
|
||||
Subject: [PATCH] mac80211: set NETIF_F_LLTX when using intermediate tx
|
||||
queues
|
||||
|
||||
When using iTXQ, tx sequence number allocation and statistics are run at
|
||||
dequeue time. Because of that, it is safe to enable NETIF_F_LLTX, which
|
||||
allows tx handlers to run on multiple CPUs in parallel.
|
||||
|
||||
Signed-off-by: Felix Fietkau <nbd@nbd.name>
|
||||
---
|
||||
|
||||
--- a/net/mac80211/iface.c
|
||||
+++ b/net/mac80211/iface.c
|
||||
@@ -1301,6 +1301,7 @@ static void ieee80211_if_setup(struct ne
|
||||
static void ieee80211_if_setup_no_queue(struct net_device *dev)
|
||||
{
|
||||
ieee80211_if_setup(dev);
|
||||
+ dev->features |= NETIF_F_LLTX;
|
||||
#if LINUX_VERSION_IS_GEQ(4,3,0)
|
||||
dev->priv_flags |= IFF_NO_QUEUE;
|
||||
#else
|
@ -1,233 +0,0 @@
|
||||
From: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
Date: Fri, 19 Feb 2016 11:01:50 +0100
|
||||
Subject: [PATCH] mac80211: add NEED_ALIGNED4_SKBS hw flag
|
||||
|
||||
HW/driver should set NEED_ALIGNED4_SKBS flag in case
|
||||
require aligned skbs to four-byte boundaries.
|
||||
This affect only TX direction.
|
||||
|
||||
Padding is added after ieee80211_hdr, before IV/LLC.
|
||||
|
||||
Before we have to do memmove(hdrlen) twice in the
|
||||
dirver. Once before we pass this to HW and next
|
||||
in tx completion (to be sure monitor will report
|
||||
this tx frame correctly).
|
||||
|
||||
With this patch we can skip this memmove() and save CPU.
|
||||
|
||||
Currently this was tested with ath9k, both hw/sw crypt for
|
||||
wep/tkip/ccmp.
|
||||
|
||||
Signed-off-by: Janusz Dziedzic <janusz.dziedzic@tieto.com>
|
||||
---
|
||||
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -2127,6 +2127,9 @@ struct ieee80211_txq {
|
||||
* @IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP: The driver (or firmware) doesn't
|
||||
* support QoS NDP for AP probing - that's most likely a driver bug.
|
||||
*
|
||||
+ * @IEEE80211_HW_NEEDS_ALIGNED4_SKBS: Driver need aligned skbs to four-byte.
|
||||
+ * Padding will be added after ieee80211_hdr, before IV/LLC.
|
||||
+ *
|
||||
* @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
|
||||
*/
|
||||
enum ieee80211_hw_flags {
|
||||
@@ -2172,6 +2175,7 @@ enum ieee80211_hw_flags {
|
||||
IEEE80211_HW_SUPPORTS_TDLS_BUFFER_STA,
|
||||
IEEE80211_HW_DEAUTH_NEED_MGD_TX_PREP,
|
||||
IEEE80211_HW_DOESNT_SUPPORT_QOS_NDP,
|
||||
+ IEEE80211_HW_NEEDS_ALIGNED4_SKBS,
|
||||
|
||||
/* keep last, obviously */
|
||||
NUM_IEEE80211_HW_FLAGS
|
||||
--- a/net/mac80211/debugfs.c
|
||||
+++ b/net/mac80211/debugfs.c
|
||||
@@ -214,6 +214,7 @@ static const char *hw_flag_names[] = {
|
||||
FLAG(SUPPORTS_TDLS_BUFFER_STA),
|
||||
FLAG(DEAUTH_NEED_MGD_TX_PREP),
|
||||
FLAG(DOESNT_SUPPORT_QOS_NDP),
|
||||
+ FLAG(NEEDS_ALIGNED4_SKBS),
|
||||
#undef FLAG
|
||||
};
|
||||
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1557,6 +1557,29 @@ ieee80211_vif_get_num_mcast_if(struct ie
|
||||
return -1;
|
||||
}
|
||||
|
||||
+static inline unsigned int
|
||||
+ieee80211_hdr_padsize(struct ieee80211_hw *hw, unsigned int hdrlen)
|
||||
+{
|
||||
+ /*
|
||||
+ * While hdrlen is already aligned to two-byte boundaries,
|
||||
+ * simple check with & 2 will return correct padsize.
|
||||
+ */
|
||||
+ if (ieee80211_hw_check(hw, NEEDS_ALIGNED4_SKBS))
|
||||
+ return hdrlen & 2;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static inline unsigned int
|
||||
+ieee80211_padded_hdrlen(struct ieee80211_hw *hw, __le16 fc)
|
||||
+{
|
||||
+ unsigned int hdrlen;
|
||||
+
|
||||
+ hdrlen = ieee80211_hdrlen(fc);
|
||||
+ hdrlen += ieee80211_hdr_padsize(hw, hdrlen);
|
||||
+
|
||||
+ return hdrlen;
|
||||
+}
|
||||
+
|
||||
u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
|
||||
struct ieee80211_rx_status *status,
|
||||
unsigned int mpdu_len,
|
||||
--- a/net/mac80211/sta_info.h
|
||||
+++ b/net/mac80211/sta_info.h
|
||||
@@ -301,7 +301,7 @@ struct ieee80211_fast_tx {
|
||||
u8 hdr_len;
|
||||
u8 sa_offs, da_offs, pn_offs;
|
||||
u8 band;
|
||||
- u8 hdr[30 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
|
||||
+ u8 hdr[30 + 2 + 2 + IEEE80211_FAST_XMIT_MAX_IV +
|
||||
sizeof(rfc1042_header)] __aligned(2);
|
||||
|
||||
struct rcu_head rcu_head;
|
||||
--- a/net/mac80211/status.c
|
||||
+++ b/net/mac80211/status.c
|
||||
@@ -655,9 +655,22 @@ void ieee80211_tx_monitor(struct ieee802
|
||||
struct sk_buff *skb2;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct ieee80211_sub_if_data *sdata;
|
||||
+ struct ieee80211_hdr *hdr = (void *)skb->data;
|
||||
struct net_device *prev_dev = NULL;
|
||||
+ unsigned int hdrlen, padsize;
|
||||
int rtap_len;
|
||||
|
||||
+ /* Remove padding if was added */
|
||||
+ if (ieee80211_hw_check(&local->hw, NEEDS_ALIGNED4_SKBS)) {
|
||||
+ hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ padsize = ieee80211_hdr_padsize(&local->hw, hdrlen);
|
||||
+
|
||||
+ if (padsize && skb->len > hdrlen + padsize) {
|
||||
+ memmove(skb->data + padsize, skb->data, hdrlen);
|
||||
+ skb_pull(skb, padsize);
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
/* send frame to monitor interfaces now */
|
||||
rtap_len = ieee80211_tx_radiotap_len(info);
|
||||
if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) {
|
||||
--- a/net/mac80211/tkip.c
|
||||
+++ b/net/mac80211/tkip.c
|
||||
@@ -201,10 +201,12 @@ void ieee80211_get_tkip_p2k(struct ieee8
|
||||
{
|
||||
struct ieee80211_key *key = (struct ieee80211_key *)
|
||||
container_of(keyconf, struct ieee80211_key, conf);
|
||||
+ struct ieee80211_hw *hw = &key->local->hw;
|
||||
const u8 *tk = &key->conf.key[NL80211_TKIP_DATA_OFFSET_ENCR_KEY];
|
||||
struct tkip_ctx *ctx = &key->u.tkip.tx;
|
||||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
- const u8 *data = (u8 *)hdr + ieee80211_hdrlen(hdr->frame_control);
|
||||
+ const u8 *data = (u8 *)hdr + ieee80211_padded_hdrlen(hw,
|
||||
+ hdr->frame_control);
|
||||
u32 iv32 = get_unaligned_le32(&data[4]);
|
||||
u16 iv16 = data[2] | (data[0] << 8);
|
||||
|
||||
--- a/net/mac80211/tx.c
|
||||
+++ b/net/mac80211/tx.c
|
||||
@@ -1175,8 +1175,7 @@ ieee80211_tx_prepare(struct ieee80211_su
|
||||
info->flags &= ~IEEE80211_TX_INTFL_NEED_TXPROCESSING;
|
||||
|
||||
hdr = (struct ieee80211_hdr *) skb->data;
|
||||
-
|
||||
- tx->hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ tx->hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
|
||||
|
||||
if (likely(sta)) {
|
||||
if (!IS_ERR(sta))
|
||||
@@ -2215,7 +2214,7 @@ netdev_tx_t ieee80211_monitor_start_xmit
|
||||
goto fail;
|
||||
|
||||
hdr = (struct ieee80211_hdr *)(skb->data + len_rthdr);
|
||||
- hdrlen = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ hdrlen = ieee80211_padded_hdrlen(&local->hw, hdr->frame_control);
|
||||
|
||||
if (skb->len < len_rthdr + hdrlen)
|
||||
goto fail;
|
||||
@@ -2433,7 +2432,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
struct ieee80211_chanctx_conf *chanctx_conf;
|
||||
struct ieee80211_sub_if_data *ap_sdata;
|
||||
enum nl80211_band band;
|
||||
- int ret;
|
||||
+ int padsize, ret;
|
||||
|
||||
if (IS_ERR(sta))
|
||||
sta = NULL;
|
||||
@@ -2653,6 +2652,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
hdrlen += 2;
|
||||
}
|
||||
|
||||
+ /* Check aligned4 skb required */
|
||||
+ padsize = ieee80211_hdr_padsize(&sdata->local->hw, hdrlen);
|
||||
+
|
||||
/*
|
||||
* Drop unicast frames to unauthorised stations unless they are
|
||||
* EAPOL frames from the local station.
|
||||
@@ -2733,6 +2735,7 @@ static struct sk_buff *ieee80211_build_h
|
||||
|
||||
skb_pull(skb, skip_header_bytes);
|
||||
head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb);
|
||||
+ head_need += padsize;
|
||||
|
||||
/*
|
||||
* So we need to modify the skb header and hence need a copy of
|
||||
@@ -2765,6 +2768,9 @@ static struct sk_buff *ieee80211_build_h
|
||||
memcpy(skb_push(skb, meshhdrlen), &mesh_hdr, meshhdrlen);
|
||||
#endif
|
||||
|
||||
+ if (padsize)
|
||||
+ memset(skb_push(skb, padsize), 0, padsize);
|
||||
+
|
||||
if (ieee80211_is_data_qos(fc)) {
|
||||
__le16 *qos_control;
|
||||
|
||||
@@ -2940,6 +2946,9 @@ void ieee80211_check_fast_xmit(struct st
|
||||
fc |= cpu_to_le16(IEEE80211_STYPE_QOS_DATA);
|
||||
}
|
||||
|
||||
+ /* Check aligned4 skb required */
|
||||
+ build.hdr_len += ieee80211_hdr_padsize(&local->hw, build.hdr_len);
|
||||
+
|
||||
/* We store the key here so there's no point in using rcu_dereference()
|
||||
* but that's fine because the code that changes the pointers will call
|
||||
* this function after doing so. For a single CPU that would be enough,
|
||||
@@ -3534,7 +3543,7 @@ begin:
|
||||
|
||||
if (tx.key &&
|
||||
(tx.key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV))
|
||||
- pn_offs = ieee80211_hdrlen(hdr->frame_control);
|
||||
+ pn_offs = tx.hdrlen;
|
||||
|
||||
ieee80211_xmit_fast_finish(sta->sdata, sta, pn_offs,
|
||||
tx.key, skb);
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -1288,6 +1288,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||
u32 tx_flags)
|
||||
{
|
||||
struct ieee80211_local *local = sdata->local;
|
||||
+ struct ieee80211_hw *hw = &local->hw;
|
||||
struct sk_buff *skb;
|
||||
struct ieee80211_mgmt *mgmt;
|
||||
unsigned int hdrlen;
|
||||
@@ -1314,7 +1315,7 @@ void ieee80211_send_auth(struct ieee8021
|
||||
skb_put_data(skb, extra, extra_len);
|
||||
|
||||
if (auth_alg == WLAN_AUTH_SHARED_KEY && transaction == 3) {
|
||||
- hdrlen = ieee80211_hdrlen(mgmt->frame_control);
|
||||
+ hdrlen = ieee80211_padded_hdrlen(hw, mgmt->frame_control);
|
||||
mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
|
||||
err = ieee80211_wep_encrypt(local, skb, hdrlen, key,
|
||||
key_len, key_idx);
|
@ -38,7 +38,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -3448,7 +3448,8 @@ struct cfg80211_ops {
|
||||
@@ -3457,7 +3457,8 @@ struct cfg80211_ops {
|
||||
* on wiphy_new(), but can be changed by the driver if it has a good
|
||||
* reason to override the default
|
||||
* @WIPHY_FLAG_4ADDR_AP: supports 4addr mode even on AP (with a single station
|
||||
@ -50,7 +50,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
* control port protocol ethertype. The device also honours the
|
||||
--- a/net/mac80211/util.c
|
||||
+++ b/net/mac80211/util.c
|
||||
@@ -3523,7 +3523,9 @@ int ieee80211_check_combinations(struct
|
||||
@@ -3622,7 +3622,9 @@ int ieee80211_check_combinations(struct
|
||||
}
|
||||
|
||||
/* Always allow software iftypes */
|
||||
@ -81,7 +81,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
break;
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -3193,8 +3193,7 @@ static int nl80211_new_interface(struct
|
||||
@@ -3194,8 +3194,7 @@ static int nl80211_new_interface(struct
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -91,7 +91,7 @@ Signed-off-by: Manikanta Pubbisetty <mpubbise@codeaurora.org>
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if ((type == NL80211_IFTYPE_P2P_DEVICE || type == NL80211_IFTYPE_NAN ||
|
||||
@@ -3213,6 +3212,13 @@ static int nl80211_new_interface(struct
|
||||
@@ -3214,6 +3213,13 @@ static int nl80211_new_interface(struct
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
--- a/include/net/cfg80211.h
|
||||
+++ b/include/net/cfg80211.h
|
||||
@@ -2959,6 +2959,7 @@ struct cfg80211_external_auth_params {
|
||||
@@ -2968,6 +2968,7 @@ struct cfg80211_external_auth_params {
|
||||
* (as advertised by the nl80211 feature flag.)
|
||||
* @get_tx_power: store the current TX power into the dbm variable;
|
||||
* return 0 if successful
|
||||
@ -8,7 +8,7 @@
|
||||
*
|
||||
* @set_wds_peer: set the WDS peer for a WDS interface
|
||||
*
|
||||
@@ -3259,6 +3260,7 @@ struct cfg80211_ops {
|
||||
@@ -3268,6 +3269,7 @@ struct cfg80211_ops {
|
||||
enum nl80211_tx_power_setting type, int mbm);
|
||||
int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
|
||||
int *dbm);
|
||||
@ -18,7 +18,7 @@
|
||||
const u8 *addr);
|
||||
--- a/include/net/mac80211.h
|
||||
+++ b/include/net/mac80211.h
|
||||
@@ -1389,6 +1389,7 @@ enum ieee80211_smps_mode {
|
||||
@@ -1395,6 +1395,7 @@ enum ieee80211_smps_mode {
|
||||
*
|
||||
* @power_level: requested transmit power (in dBm), backward compatibility
|
||||
* value only that is set to the minimum of all interfaces
|
||||
@ -26,7 +26,7 @@
|
||||
*
|
||||
* @chandef: the channel definition to tune to
|
||||
* @radar_enabled: whether radar detection is enabled
|
||||
@@ -1409,6 +1410,7 @@ enum ieee80211_smps_mode {
|
||||
@@ -1415,6 +1416,7 @@ enum ieee80211_smps_mode {
|
||||
struct ieee80211_conf {
|
||||
u32 flags;
|
||||
int power_level, dynamic_ps_timeout;
|
||||
@ -36,45 +36,20 @@
|
||||
u8 ps_dtim_period;
|
||||
--- a/include/uapi/linux/nl80211.h
|
||||
+++ b/include/uapi/linux/nl80211.h
|
||||
@@ -2241,6 +2241,26 @@ enum nl80211_commands {
|
||||
* association request when used with NL80211_CMD_NEW_STATION). Can be set
|
||||
* only if %NL80211_STA_FLAG_WME is set.
|
||||
@@ -2244,6 +2244,9 @@ enum nl80211_commands {
|
||||
* @NL80211_ATTR_AIRTIME_WEIGHT: Station's weight when scheduled by the airtime
|
||||
* scheduler.
|
||||
*
|
||||
+ * @NL80211_ATTR_FTM_RESPONDER: nested attribute which user-space can include
|
||||
+ * in %NL80211_CMD_START_AP or %NL80211_CMD_SET_BEACON for fine timing
|
||||
+ * measurement (FTM) responder functionality and containing parameters as
|
||||
+ * possible, see &enum nl80211_ftm_responder_attr
|
||||
+ *
|
||||
+ * @NL80211_ATTR_FTM_RESPONDER_STATS: Nested attribute with FTM responder
|
||||
+ * statistics, see &enum nl80211_ftm_responder_stats.
|
||||
+ *
|
||||
+ * @NL80211_ATTR_TIMEOUT: Timeout for the given operation in milliseconds (u32),
|
||||
+ * if the attribute is not given no timeout is requested. Note that 0 is an
|
||||
+ * invalid value.
|
||||
+ *
|
||||
+ * @NL80211_ATTR_PEER_MEASUREMENTS: peer measurements request (and result)
|
||||
+ * data, uses nested attributes specified in
|
||||
+ * &enum nl80211_peer_measurement_attrs.
|
||||
+ * This is also used for capability advertisement in the wiphy information,
|
||||
+ * with the appropriate sub-attributes.
|
||||
+ * @NL80211_ATTR_WIPHY_ANTENNA_GAIN: Configured antenna gain. Used to reduce
|
||||
+ * transmit power to stay within regulatory limits. u32, dBi.
|
||||
+ *
|
||||
* @NUM_NL80211_ATTR: total number of nl80211_attrs available
|
||||
* @NL80211_ATTR_MAX: highest attribute number currently defined
|
||||
* @__NL80211_ATTR_AFTER_LAST: internal use
|
||||
@@ -2682,6 +2702,16 @@ enum nl80211_attrs {
|
||||
@@ -2693,6 +2696,8 @@ enum nl80211_attrs {
|
||||
|
||||
NL80211_ATTR_HE_CAPABILITY,
|
||||
NL80211_ATTR_AIRTIME_WEIGHT,
|
||||
|
||||
+ NL80211_ATTR_FTM_RESPONDER,
|
||||
+
|
||||
+ NL80211_ATTR_FTM_RESPONDER_STATS,
|
||||
+
|
||||
+ NL80211_ATTR_TIMEOUT,
|
||||
+
|
||||
+ NL80211_ATTR_PEER_MEASUREMENTS,
|
||||
+
|
||||
+ NL80211_ATTR_WIPHY_ANTENNA_GAIN,
|
||||
+
|
||||
/* add attributes here, update the policy in nl80211.c */
|
||||
@ -82,7 +57,7 @@
|
||||
__NL80211_ATTR_AFTER_LAST,
|
||||
--- a/net/mac80211/cfg.c
|
||||
+++ b/net/mac80211/cfg.c
|
||||
@@ -2494,6 +2494,19 @@ static int ieee80211_get_tx_power(struct
|
||||
@@ -2497,6 +2497,19 @@ static int ieee80211_get_tx_power(struct
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -102,7 +77,7 @@
|
||||
static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev,
|
||||
const u8 *addr)
|
||||
{
|
||||
@@ -3861,6 +3874,7 @@ const struct cfg80211_ops mac80211_confi
|
||||
@@ -3864,6 +3877,7 @@ const struct cfg80211_ops mac80211_confi
|
||||
.set_wiphy_params = ieee80211_set_wiphy_params,
|
||||
.set_tx_power = ieee80211_set_tx_power,
|
||||
.get_tx_power = ieee80211_get_tx_power,
|
||||
@ -112,7 +87,7 @@
|
||||
CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
|
||||
--- a/net/mac80211/ieee80211_i.h
|
||||
+++ b/net/mac80211/ieee80211_i.h
|
||||
@@ -1352,6 +1352,7 @@ struct ieee80211_local {
|
||||
@@ -1365,6 +1365,7 @@ struct ieee80211_local {
|
||||
int dynamic_ps_forced_timeout;
|
||||
|
||||
int user_power_level; /* in dBm, for all interfaces */
|
||||
@ -154,15 +129,15 @@
|
||||
local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
|
||||
--- a/net/wireless/nl80211.c
|
||||
+++ b/net/wireless/nl80211.c
|
||||
@@ -430,6 +430,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_TXQ_QUANTUM] = { .type = NLA_U32 },
|
||||
@@ -431,6 +431,7 @@ static const struct nla_policy nl80211_p
|
||||
[NL80211_ATTR_HE_CAPABILITY] = { .type = NLA_BINARY,
|
||||
.len = NL80211_HE_MAX_CAPABILITY_LEN },
|
||||
[NL80211_ATTR_AIRTIME_WEIGHT] = NLA_POLICY_MIN(NLA_U16, 1),
|
||||
+ [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 },
|
||||
};
|
||||
|
||||
/* policy for the key attributes */
|
||||
@@ -2587,6 +2588,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||
@@ -2588,6 +2589,20 @@ static int nl80211_set_wiphy(struct sk_b
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
|
@ -90,7 +90,7 @@ endef
|
||||
|
||||
define KernelPackage/rt2800-lib
|
||||
$(call KernelPackage/rt2x00/Default)
|
||||
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT||TARGET_ramips) +kmod-rt2x00-lib +kmod-lib-crc-ccitt +@DRIVER_11N_SUPPORT
|
||||
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT||TARGET_ramips) +kmod-rt2x00-lib +kmod-lib-crc-ccitt +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
|
||||
HIDDEN:=1
|
||||
TITLE+= (rt2800 LIB)
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/ralink/rt2x00/rt2800lib.ko
|
||||
|
@ -57,7 +57,7 @@ endef
|
||||
define KernelPackage/rtlwifi
|
||||
$(call KernelPackage/mac80211/Default)
|
||||
TITLE:=Realtek common driver part
|
||||
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-mac80211 +@DRIVER_11N_SUPPORT
|
||||
DEPENDS+= @(PCI_SUPPORT||USB_SUPPORT) +kmod-mac80211 +@DRIVER_11N_SUPPORT +@DRIVER_11W_SUPPORT
|
||||
FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/realtek/rtlwifi/rtlwifi.ko
|
||||
HIDDEN:=1
|
||||
endef
|
||||
|
Loading…
Reference in New Issue
Block a user