From a062a33db51925d0cb288ffa7fb88e07be671b0d Mon Sep 17 00:00:00 2001 From: Patrick Walther Date: Fri, 26 Mar 2021 19:55:35 +0100 Subject: [PATCH] FIX: [mac80211] update to version v5.10.16-1 BugzId: 67915 --- ...ckport-of-build-patches-from-openwrt.patch | 59 +- ...kport-of-subsys-patches-from-openwrt.patch | 7282 +++++++++++------ ...backport-of-ath-patches-from-openwrt.patch | 494 +- ...kport-of-rt2x00-patches-from-openwrt.patch | 802 +- ...backport-of-mwl-patches-from-openwrt.patch | 10 +- ...ackport-of-brcm-patches-from-openwrt.patch | 970 +-- ...backport-of-rtl-patches-from-openwrt.patch | 811 ++ ...wrt.patch => 0008-netmodule-patches.patch} | 502 +- ...0211_5.4.27-1.bb => mac80211_5.10.16-1.bb} | 9 +- 9 files changed, 6969 insertions(+), 3970 deletions(-) create mode 100644 recipes-kernel/mac80211/mac80211/0007-backport-of-rtl-patches-from-openwrt.patch rename recipes-kernel/mac80211/mac80211/{0007-backport-of-netmodule-patches-from-openwrt.patch => 0008-netmodule-patches.patch} (57%) rename recipes-kernel/mac80211/{mac80211_5.4.27-1.bb => mac80211_5.10.16-1.bb} (88%) diff --git a/recipes-kernel/mac80211/mac80211/0001-backport-of-build-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0001-backport-of-build-patches-from-openwrt.patch index ce64818..0818f2b 100644 --- a/recipes-kernel/mac80211/mac80211/0001-backport-of-build-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0001-backport-of-build-patches-from-openwrt.patch @@ -1,7 +1,7 @@ -From 2ebe60c979204b804a5ea70e1dfb77331c7297ac Mon Sep 17 00:00:00 2001 +From 7e308692b72697003d08b900059579585b621b70 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:18:11 +0200 -Subject: [PATCH] FIX: [mac80211] backport of build patches from openwrt +Date: Mon, 22 Mar 2021 16:28:20 +0100 +Subject: [PATCH] 0001 backport of build patches from openwrt --- Kconfig.local | 111 -------------------- @@ -28,10 +28,10 @@ Subject: [PATCH] FIX: [mac80211] backport of build patches from openwrt 21 files changed, 114 insertions(+), 298 deletions(-) diff --git a/Kconfig.local b/Kconfig.local -index 0b3e89c..d5a218a 100644 +index a3935cc..dfd68d6 100644 --- a/Kconfig.local +++ b/Kconfig.local -@@ -1240,117 +1240,6 @@ config BACKPORTED_USB_NET_CH9200 +@@ -1315,117 +1315,6 @@ config BACKPORTED_USB_NET_CH9200 config BACKPORTED_USB_NET_AQC111 tristate default USB_NET_AQC111 @@ -314,7 +314,7 @@ index ee7df4b..79e5fab 100644 .PHONY: defconfig-help diff --git a/Makefile.kernel b/Makefile.kernel -index 5c96697..23b2688 100644 +index 62baa94..4212940 100644 --- a/Makefile.kernel +++ b/Makefile.kernel @@ -40,8 +40,6 @@ obj-y += compat/ @@ -437,7 +437,7 @@ index 0bf0420..740bf09 100644 { } diff --git a/drivers/net/wireless/broadcom/b43/Kconfig b/drivers/net/wireless/broadcom/b43/Kconfig -index 07e67e8..b8f1262 100644 +index 33ecdf1..ffdf951 100644 --- a/drivers/net/wireless/broadcom/b43/Kconfig +++ b/drivers/net/wireless/broadcom/b43/Kconfig @@ -63,21 +63,21 @@ endchoice @@ -463,7 +463,7 @@ index 07e67e8..b8f1262 100644 depends on B43 && B43_SSB && SSB_SDIOHOST_POSSIBLE - select SSB_SDIOHOST + depends on SSB_SDIOHOST - ---help--- + help Broadcom 43xx device support for Soft-MAC SDIO devices. @@ -96,13 +96,13 @@ config B43_SDIO @@ -483,10 +483,10 @@ index 07e67e8..b8f1262 100644 config B43_PHY_G diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c -index 0c96714..99d0b4a 100644 +index 1f2c46f..2ef3263 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c -@@ -2851,7 +2851,7 @@ static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev) +@@ -2853,7 +2853,7 @@ static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev) { struct ssb_bus *bus = dev->dev->sdev->bus; @@ -495,7 +495,7 @@ index 0c96714..99d0b4a 100644 return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev); #else return bus->chipco.dev; -@@ -4868,7 +4868,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) +@@ -4870,7 +4870,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev) } if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW) hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */ @@ -505,7 +505,7 @@ index 0c96714..99d0b4a 100644 dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI && dev->dev->sdev->bus->pcicore.dev->id.revision <= 10) diff --git a/drivers/net/wireless/broadcom/b43legacy/Kconfig b/drivers/net/wireless/broadcom/b43legacy/Kconfig -index 8205796..8a75208 100644 +index 6ba7eb7..b924f63 100644 --- a/drivers/net/wireless/broadcom/b43legacy/Kconfig +++ b/drivers/net/wireless/broadcom/b43legacy/Kconfig @@ -3,7 +3,7 @@ config B43LEGACY @@ -515,7 +515,7 @@ index 8205796..8a75208 100644 - select SSB + depends on SSB depends on FW_LOADER - ---help--- + help b43legacy is a driver for 802.11b devices from Broadcom (BCM4301 and @@ -25,15 +25,15 @@ config B43LEGACY config B43LEGACY_PCI_AUTOSELECT @@ -537,10 +537,10 @@ index 8205796..8a75208 100644 # LED support diff --git a/drivers/net/wireless/broadcom/b43legacy/main.c b/drivers/net/wireless/broadcom/b43legacy/main.c -index fef1686..cd8058b 100644 +index e3be1fe..503611f 100644 --- a/drivers/net/wireless/broadcom/b43legacy/main.c +++ b/drivers/net/wireless/broadcom/b43legacy/main.c -@@ -1906,7 +1906,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) +@@ -1907,7 +1907,7 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev) if (dev->dev->id.revision >= 2) mask |= 0x0010; /* FIXME: This is redundant. */ @@ -549,7 +549,7 @@ index fef1686..cd8058b 100644 pcidev = bus->pcicore.dev; #endif gpiodev = bus->chipco.dev ? : pcidev; -@@ -1925,7 +1925,7 @@ static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev) +@@ -1926,7 +1926,7 @@ static void b43legacy_gpio_cleanup(struct b43legacy_wldev *dev) struct ssb_bus *bus = dev->dev->bus; struct ssb_device *gpiodev, *pcidev = NULL; @@ -559,7 +559,7 @@ index fef1686..cd8058b 100644 #endif gpiodev = bus->chipco.dev ? : pcidev; diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig -index 9f99ad8..2c426b5 100644 +index 053e361..ae090a4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/Kconfig +++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig @@ -8,7 +8,7 @@ config BRCMSMAC @@ -572,7 +572,7 @@ index 9f99ad8..2c426b5 100644 select LEDS_CLASS if BCMA_DRIVER_GPIO select BRCMUTIL diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile -index 50239f6..e90b34e 100644 +index a1a5259..cb2fb8d 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/Makefile @@ -42,6 +42,6 @@ brcmsmac-y := \ @@ -584,11 +584,11 @@ index 50239f6..e90b34e 100644 obj-$(CPTCFG_BRCMSMAC) += brcmsmac.o diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h -index 09a5bc0..17a0b1f 100644 +index f58fd74..d65f5c2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/led.h -@@ -22,7 +22,7 @@ struct brcms_led { - bool active_low; +@@ -24,7 +24,7 @@ struct brcms_led { + struct gpio_desc *gpiod; }; -#ifdef CPTCFG_BCMA_DRIVER_GPIO @@ -597,10 +597,10 @@ index 09a5bc0..17a0b1f 100644 int brcms_led_register(struct brcms_info *wl); #else diff --git a/drivers/net/wireless/intel/ipw2x00/ipw2200.c b/drivers/net/wireless/intel/ipw2x00/ipw2200.c -index 9a99ede..03f7c2a 100644 +index 9ae7403..bb9f44f 100644 --- a/drivers/net/wireless/intel/ipw2x00/ipw2200.c +++ b/drivers/net/wireless/intel/ipw2x00/ipw2200.c -@@ -11482,6 +11482,15 @@ static const struct attribute_group ipw_attribute_group = { +@@ -11470,6 +11470,15 @@ static const struct attribute_group ipw_attribute_group = { .attrs = ipw_sysfs_entries, }; @@ -616,7 +616,7 @@ index 9a99ede..03f7c2a 100644 #ifdef CPTCFG_IPW2200_PROMISCUOUS static int ipw_prom_open(struct net_device *dev) { -@@ -11530,15 +11539,6 @@ static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb, +@@ -11518,15 +11527,6 @@ static netdev_tx_t ipw_prom_hard_start_xmit(struct sk_buff *skb, return NETDEV_TX_OK; } @@ -717,10 +717,10 @@ index df26c7b..1038c30 100644 * We have different type of choice blocks. * If curr.tri equals to mod then we can select several diff --git a/local-symbols b/local-symbols -index 33ee823..e7064fd 100644 +index a59d23e..d5a2bfd 100644 --- a/local-symbols +++ b/local-symbols -@@ -412,43 +412,6 @@ USB_SIERRA_NET= +@@ -437,43 +437,6 @@ USB_SIERRA_NET= USB_VL600= USB_NET_CH9200= USB_NET_AQC111= @@ -765,10 +765,10 @@ index 33ee823..e7064fd 100644 USB_PRINTER= USB_WDM= diff --git a/net/wireless/Kconfig b/net/wireless/Kconfig -index 3613e8e..0f9d708 100644 +index 2e6b1fc..1edfb29 100644 --- a/net/wireless/Kconfig +++ b/net/wireless/Kconfig -@@ -186,7 +186,7 @@ config CFG80211_WEXT_EXPORT +@@ -188,7 +188,7 @@ config CFG80211_WEXT_EXPORT endif # CFG80211 config LIB80211 @@ -777,7 +777,7 @@ index 3613e8e..0f9d708 100644 depends on m default n help -@@ -196,18 +196,18 @@ config LIB80211 +@@ -198,19 +198,19 @@ config LIB80211 Drivers should select this themselves if needed. config LIB80211_CRYPT_WEP @@ -790,6 +790,7 @@ index 3613e8e..0f9d708 100644 - tristate + tristate "lib80211 CCMP support" depends on m + depends on CRYPTO depends on CRYPTO_AES depends on CRYPTO_CCM diff --git a/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch index f4c7422..82c51f5 100644 --- a/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0002-backport-of-subsys-patches-from-openwrt.patch @@ -1,84 +1,68 @@ -From 9d247a8381fa8a1b8d960edf2f6a5f8f931791be Mon Sep 17 00:00:00 2001 +From 02ae47316099feb8f3634fc87005b064a1cd7379 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:18:57 +0200 -Subject: [PATCH] FIX: [wlan] backport of subsys patches from openwrt +Date: Mon, 22 Mar 2021 16:34:34 +0100 +Subject: [PATCH] 0002 backport of subsys patches from openwrt --- - drivers/net/wireless/ath/ath10k/mac.c | 1 + - include/net/cfg80211.h | 9 + - include/net/mac80211.h | 70 +++- - include/uapi/linux/nl80211.h | 11 + - net/mac80211/Kconfig | 3 - - net/mac80211/Makefile | 6 +- - net/mac80211/aead_api.h | 23 -- - net/mac80211/aes_ccm.c | 144 +++++++ - net/mac80211/aes_ccm.h | 46 +-- - net/mac80211/aes_cmac.c | 126 ++++-- - net/mac80211/aes_cmac.h | 11 +- - net/mac80211/{aead_api.c => aes_gcm.c} | 55 ++- - net/mac80211/aes_gcm.h | 30 +- - net/mac80211/aes_gmac.h | 22 +- - net/mac80211/airtime.c | 597 +++++++++++++++++++++++++++++ - net/mac80211/cfg.c | 19 +- - net/mac80211/debugfs.c | 85 ++++ - net/mac80211/debugfs_sta.c | 82 +++- - net/mac80211/fils_aead.c | 2 +- - net/mac80211/fils_aead.h | 2 +- - net/mac80211/ieee80211_i.h | 12 + - net/mac80211/key.c | 20 +- - net/mac80211/key.h | 4 +- - net/mac80211/main.c | 35 +- - net/mac80211/rc80211_minstrel.c | 48 +-- - net/mac80211/rc80211_minstrel.h | 57 ++- - net/mac80211/rc80211_minstrel_debugfs.c | 8 +- - net/mac80211/rc80211_minstrel_ht.c | 73 ++-- - net/mac80211/rc80211_minstrel_ht.h | 2 +- - net/mac80211/rc80211_minstrel_ht_debugfs.c | 8 +- - net/mac80211/sta_info.c | 56 +++ - net/mac80211/sta_info.h | 12 + - net/mac80211/status.c | 56 ++- - net/mac80211/tx.c | 234 +++++++---- - net/mac80211/wpa.c | 43 ++- - net/wireless/core.c | 15 - - net/wireless/nl80211.c | 15 + - net/wireless/sysfs.c | 27 +- - 38 files changed, 1679 insertions(+), 390 deletions(-) + include/net/cfg80211.h | 6 +- + include/net/fq.h | 11 +- + include/net/fq_impl.h | 171 ++-- + include/net/mac80211.h | 27 + + include/uapi/linux/nl80211.h | 11 + + net/mac80211/Kconfig | 3 - + net/mac80211/Makefile | 5 +- + net/mac80211/aead_api.c | 112 --- + net/mac80211/aead_api.h | 23 - + net/mac80211/aes_ccm.c | 144 ++++ + net/mac80211/aes_ccm.h | 46 +- + net/mac80211/aes_cmac.c | 148 +++- + net/mac80211/aes_cmac.h | 11 +- + net/mac80211/aes_gcm.c | 109 +++ + net/mac80211/aes_gcm.h | 30 +- + net/mac80211/aes_gmac.h | 22 +- + net/mac80211/cfg.c | 17 +- + net/mac80211/debugfs.c | 1 + + net/mac80211/debugfs_sta.c | 1 + + net/mac80211/driver-ops.h | 16 + + net/mac80211/fils_aead.c | 2 +- + net/mac80211/fils_aead.h | 2 +- + net/mac80211/ieee80211_i.h | 6 +- + net/mac80211/iface.c | 17 +- + net/mac80211/key.h | 4 +- + net/mac80211/main.c | 29 +- + net/mac80211/mlme.c | 72 +- + net/mac80211/rc80211_minstrel.c | 574 ------------- + net/mac80211/rc80211_minstrel.h | 184 ----- + net/mac80211/rc80211_minstrel_debugfs.c | 172 ---- + net/mac80211/rc80211_minstrel_ht.c | 1223 ++++++++++++++++------------ + net/mac80211/rc80211_minstrel_ht.h | 137 +++- + net/mac80211/rc80211_minstrel_ht_debugfs.c | 79 +- + net/mac80211/rx.c | 260 +++--- + net/mac80211/sta_info.c | 1 + + net/mac80211/sta_info.h | 2 + + net/mac80211/trace.h | 41 +- + net/mac80211/tx.c | 24 +- + net/mac80211/wpa.c | 43 +- + net/wireless/core.c | 15 - + net/wireless/mlme.c | 26 +- + net/wireless/nl80211.c | 38 +- + net/wireless/nl80211.h | 8 +- + net/wireless/sysfs.c | 27 +- + net/wireless/trace.h | 12 +- + 45 files changed, 1856 insertions(+), 2056 deletions(-) + delete mode 100644 net/mac80211/aead_api.c delete mode 100644 net/mac80211/aead_api.h create mode 100644 net/mac80211/aes_ccm.c - rename net/mac80211/{aead_api.c => aes_gcm.c} (50%) - create mode 100644 net/mac80211/airtime.c + create mode 100644 net/mac80211/aes_gcm.c + delete mode 100644 net/mac80211/rc80211_minstrel.c + delete mode 100644 net/mac80211/rc80211_minstrel.h + delete mode 100644 net/mac80211/rc80211_minstrel_debugfs.c -diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c -index 7f0d03a..aad1bda 100644 ---- a/drivers/net/wireless/ath/ath10k/mac.c -+++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -8870,6 +8870,7 @@ int ath10k_mac_register(struct ath10k *ar) - wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_VHT_IBSS); - wiphy_ext_feature_set(ar->hw->wiphy, - NL80211_EXT_FEATURE_SET_SCAN_DWELL); -+ wiphy_ext_feature_set(ar->hw->wiphy, NL80211_EXT_FEATURE_AQL); - - if (test_bit(WMI_SERVICE_TX_DATA_ACK_RSSI, ar->wmi.svc_map) || - test_bit(WMI_SERVICE_HTT_MGMT_TX_COMP_VALID_FLAGS, ar->wmi.svc_map)) diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h -index 9827613..8099b10 100644 +index 695bb73..449df09 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -2603,6 +2603,13 @@ enum wiphy_params_flags { - - #define IEEE80211_DEFAULT_AIRTIME_WEIGHT 256 - -+/* The per TXQ device queue limit in airtime */ -+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L 5000 -+#define IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H 12000 -+ -+/* The per interface airtime threshold to switch to lower queue limit */ -+#define IEEE80211_AQL_THRESHOLD 24000 -+ - /** - * struct cfg80211_pmksa - PMK Security Association - * -@@ -3447,6 +3454,7 @@ struct cfg80211_update_owe_info { +@@ -3736,6 +3736,7 @@ struct mgmt_frame_regs { * (as advertised by the nl80211 feature flag.) * @get_tx_power: store the current TX power into the dbm variable; * return 0 if successful @@ -86,7 +70,7 @@ index 9827613..8099b10 100644 * * @set_wds_peer: set the WDS peer for a WDS interface * -@@ -3762,6 +3770,7 @@ struct cfg80211_ops { +@@ -4058,6 +4059,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); @@ -94,59 +78,410 @@ index 9827613..8099b10 100644 int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, const u8 *addr); +@@ -6410,13 +6412,15 @@ void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss); + * @dev: network device + * @buf: 802.11 frame (header + body) + * @len: length of the frame data ++ * @reconnect: immediate reconnect is desired (include the nl80211 attribute) + * + * This function is called whenever deauthentication has been processed in + * station mode. This includes both received deauthentication frames and + * locally generated ones. This function may sleep. The caller must hold the + * corresponding wdev's mutex. + */ +-void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len); ++void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len, ++ bool reconnect); + + /** + * cfg80211_rx_unprot_mlme_mgmt - notification of unprotected mlme mgmt frame +diff --git a/include/net/fq.h b/include/net/fq.h +index e39f3f8..2eccbbd 100644 +--- a/include/net/fq.h ++++ b/include/net/fq.h +@@ -19,8 +19,6 @@ struct fq_tin; + * @flowchain: can be linked to fq_tin's new_flows or old_flows. Used for DRR++ + * (deficit round robin) based round robin queuing similar to the one + * found in net/sched/sch_fq_codel.c +- * @backlogchain: can be linked to other fq_flow and fq. Used to keep track of +- * fat flows and efficient head-dropping if packet limit is reached + * @queue: sk_buff queue to hold packets + * @backlog: number of bytes pending in the queue. The number of packets can be + * found in @queue.qlen +@@ -29,7 +27,6 @@ struct fq_tin; + struct fq_flow { + struct fq_tin *tin; + struct list_head flowchain; +- struct list_head backlogchain; + struct sk_buff_head queue; + u32 backlog; + int deficit; +@@ -47,6 +44,8 @@ struct fq_flow { + struct fq_tin { + struct list_head new_flows; + struct list_head old_flows; ++ struct list_head tin_list; ++ struct fq_flow default_flow; + u32 backlog_bytes; + u32 backlog_packets; + u32 overlimit; +@@ -59,14 +58,14 @@ struct fq_tin { + /** + * struct fq - main container for fair queuing purposes + * +- * @backlogs: linked to fq_flows. Used to maintain fat flows for efficient +- * head-dropping when @backlog reaches @limit + * @limit: max number of packets that can be queued across all flows + * @backlog: number of packets queued across all flows + */ + struct fq { + struct fq_flow *flows; +- struct list_head backlogs; ++ unsigned long *flows_bitmap; ++ ++ struct list_head tin_backlog; + spinlock_t lock; + u32 flows_cnt; + u32 limit; +diff --git a/include/net/fq_impl.h b/include/net/fq_impl.h +index e73d74d..a5f67a2 100644 +--- a/include/net/fq_impl.h ++++ b/include/net/fq_impl.h +@@ -11,35 +11,37 @@ + + /* functions that are embedded into includer */ + +-static void fq_adjust_removal(struct fq *fq, +- struct fq_flow *flow, +- struct sk_buff *skb) ++ ++static void ++__fq_adjust_removal(struct fq *fq, struct fq_flow *flow, unsigned int packets, ++ unsigned int bytes, unsigned int truesize) + { + struct fq_tin *tin = flow->tin; ++ int idx; + +- tin->backlog_bytes -= skb->len; +- tin->backlog_packets--; +- flow->backlog -= skb->len; +- fq->backlog--; +- fq->memory_usage -= skb->truesize; +-} ++ tin->backlog_bytes -= bytes; ++ tin->backlog_packets -= packets; ++ flow->backlog -= bytes; ++ fq->backlog -= packets; ++ fq->memory_usage -= truesize; + +-static void fq_rejigger_backlog(struct fq *fq, struct fq_flow *flow) +-{ +- struct fq_flow *i; ++ if (flow->backlog) ++ return; + +- if (flow->backlog == 0) { +- list_del_init(&flow->backlogchain); +- } else { +- i = flow; ++ if (flow == &tin->default_flow) { ++ list_del_init(&tin->tin_list); ++ return; ++ } + +- list_for_each_entry_continue(i, &fq->backlogs, backlogchain) +- if (i->backlog < flow->backlog) +- break; ++ idx = flow - fq->flows; ++ __clear_bit(idx, fq->flows_bitmap); ++} + +- list_move_tail(&flow->backlogchain, +- &i->backlogchain); +- } ++static void fq_adjust_removal(struct fq *fq, ++ struct fq_flow *flow, ++ struct sk_buff *skb) ++{ ++ __fq_adjust_removal(fq, flow, 1, skb->len, skb->truesize); + } + + static struct sk_buff *fq_flow_dequeue(struct fq *fq, +@@ -54,11 +56,37 @@ static struct sk_buff *fq_flow_dequeue(struct fq *fq, + return NULL; + + fq_adjust_removal(fq, flow, skb); +- fq_rejigger_backlog(fq, flow); + + return skb; + } + ++static int fq_flow_drop(struct fq *fq, struct fq_flow *flow, ++ fq_skb_free_t free_func) ++{ ++ unsigned int packets = 0, bytes = 0, truesize = 0; ++ struct fq_tin *tin = flow->tin; ++ struct sk_buff *skb; ++ int pending; ++ ++ lockdep_assert_held(&fq->lock); ++ ++ pending = min_t(int, 32, skb_queue_len(&flow->queue) / 2); ++ do { ++ skb = __skb_dequeue(&flow->queue); ++ if (!skb) ++ break; ++ ++ packets++; ++ bytes += skb->len; ++ truesize += skb->truesize; ++ free_func(fq, tin, flow, skb); ++ } while (packets < pending); ++ ++ __fq_adjust_removal(fq, flow, packets, bytes, truesize); ++ ++ return packets; ++} ++ + static struct sk_buff *fq_tin_dequeue(struct fq *fq, + struct fq_tin *tin, + fq_tin_dequeue_t dequeue_func) +@@ -115,8 +143,7 @@ static u32 fq_flow_idx(struct fq *fq, struct sk_buff *skb) + + static struct fq_flow *fq_flow_classify(struct fq *fq, + struct fq_tin *tin, u32 idx, +- struct sk_buff *skb, +- fq_flow_get_default_t get_default_func) ++ struct sk_buff *skb) + { + struct fq_flow *flow; + +@@ -124,7 +151,7 @@ static struct fq_flow *fq_flow_classify(struct fq *fq, + + flow = &fq->flows[idx]; + if (flow->tin && flow->tin != tin) { +- flow = get_default_func(fq, tin, idx, skb); ++ flow = &tin->default_flow; + tin->collisions++; + fq->collisions++; + } +@@ -135,36 +162,56 @@ static struct fq_flow *fq_flow_classify(struct fq *fq, + return flow; + } + +-static void fq_recalc_backlog(struct fq *fq, +- struct fq_tin *tin, +- struct fq_flow *flow) ++static struct fq_flow *fq_find_fattest_flow(struct fq *fq) + { +- struct fq_flow *i; ++ struct fq_tin *tin; ++ struct fq_flow *flow = NULL; ++ u32 len = 0; ++ int i; + +- if (list_empty(&flow->backlogchain)) +- list_add_tail(&flow->backlogchain, &fq->backlogs); ++ for_each_set_bit(i, fq->flows_bitmap, fq->flows_cnt) { ++ struct fq_flow *cur = &fq->flows[i]; ++ unsigned int cur_len; + +- i = flow; +- list_for_each_entry_continue_reverse(i, &fq->backlogs, +- backlogchain) +- if (i->backlog > flow->backlog) +- break; ++ cur_len = cur->backlog; ++ if (cur_len <= len) ++ continue; ++ ++ flow = cur; ++ len = cur_len; ++ } ++ ++ list_for_each_entry(tin, &fq->tin_backlog, tin_list) { ++ unsigned int cur_len = tin->default_flow.backlog; + +- list_move(&flow->backlogchain, &i->backlogchain); ++ if (cur_len <= len) ++ continue; ++ ++ flow = &tin->default_flow; ++ len = cur_len; ++ } ++ ++ return flow; + } + + static void fq_tin_enqueue(struct fq *fq, + struct fq_tin *tin, u32 idx, + struct sk_buff *skb, +- fq_skb_free_t free_func, +- fq_flow_get_default_t get_default_func) ++ fq_skb_free_t free_func) + { + struct fq_flow *flow; + bool oom; + + lockdep_assert_held(&fq->lock); + +- flow = fq_flow_classify(fq, tin, idx, skb, get_default_func); ++ flow = fq_flow_classify(fq, tin, idx, skb); ++ ++ if (!flow->backlog) { ++ if (flow != &tin->default_flow) ++ __set_bit(idx, fq->flows_bitmap); ++ else if (list_empty(&tin->tin_list)) ++ list_add(&tin->tin_list, &fq->tin_backlog); ++ } + + flow->tin = tin; + flow->backlog += skb->len; +@@ -173,8 +220,6 @@ static void fq_tin_enqueue(struct fq *fq, + fq->memory_usage += skb->truesize; + fq->backlog++; + +- fq_recalc_backlog(fq, tin, flow); +- + if (list_empty(&flow->flowchain)) { + flow->deficit = fq->quantum; + list_add_tail(&flow->flowchain, +@@ -184,18 +229,13 @@ static void fq_tin_enqueue(struct fq *fq, + __skb_queue_tail(&flow->queue, skb); + oom = (fq->memory_usage > fq->memory_limit); + while (fq->backlog > fq->limit || oom) { +- flow = list_first_entry_or_null(&fq->backlogs, +- struct fq_flow, +- backlogchain); ++ flow = fq_find_fattest_flow(fq); + if (!flow) + return; + +- skb = fq_flow_dequeue(fq, flow); +- if (!skb) ++ if (!fq_flow_drop(fq, flow, free_func)) + return; + +- free_func(fq, flow->tin, flow, skb); +- + flow->tin->overlimit++; + fq->overlimit++; + if (oom) { +@@ -224,8 +264,6 @@ static void fq_flow_filter(struct fq *fq, + fq_adjust_removal(fq, flow, skb); + free_func(fq, tin, flow, skb); + } +- +- fq_rejigger_backlog(fq, flow); + } + + static void fq_tin_filter(struct fq *fq, +@@ -248,16 +286,18 @@ static void fq_flow_reset(struct fq *fq, + struct fq_flow *flow, + fq_skb_free_t free_func) + { ++ struct fq_tin *tin = flow->tin; + struct sk_buff *skb; + + while ((skb = fq_flow_dequeue(fq, flow))) +- free_func(fq, flow->tin, flow, skb); ++ free_func(fq, tin, flow, skb); + +- if (!list_empty(&flow->flowchain)) ++ if (!list_empty(&flow->flowchain)) { + list_del_init(&flow->flowchain); +- +- if (!list_empty(&flow->backlogchain)) +- list_del_init(&flow->backlogchain); ++ if (list_empty(&tin->new_flows) && ++ list_empty(&tin->old_flows)) ++ list_del_init(&tin->tin_list); ++ } + + flow->tin = NULL; + +@@ -283,6 +323,7 @@ static void fq_tin_reset(struct fq *fq, + fq_flow_reset(fq, flow, free_func); + } + ++ WARN_ON_ONCE(!list_empty(&tin->tin_list)); + WARN_ON_ONCE(tin->backlog_bytes); + WARN_ON_ONCE(tin->backlog_packets); + } +@@ -290,7 +331,6 @@ static void fq_tin_reset(struct fq *fq, + static void fq_flow_init(struct fq_flow *flow) + { + INIT_LIST_HEAD(&flow->flowchain); +- INIT_LIST_HEAD(&flow->backlogchain); + __skb_queue_head_init(&flow->queue); + } + +@@ -298,6 +338,8 @@ static void fq_tin_init(struct fq_tin *tin) + { + INIT_LIST_HEAD(&tin->new_flows); + INIT_LIST_HEAD(&tin->old_flows); ++ INIT_LIST_HEAD(&tin->tin_list); ++ fq_flow_init(&tin->default_flow); + } + + static int fq_init(struct fq *fq, int flows_cnt) +@@ -305,8 +347,8 @@ static int fq_init(struct fq *fq, int flows_cnt) + int i; + + memset(fq, 0, sizeof(fq[0])); +- INIT_LIST_HEAD(&fq->backlogs); + spin_lock_init(&fq->lock); ++ INIT_LIST_HEAD(&fq->tin_backlog); + fq->flows_cnt = max_t(u32, flows_cnt, 1); + fq->quantum = 300; + fq->limit = 8192; +@@ -316,6 +358,14 @@ static int fq_init(struct fq *fq, int flows_cnt) + if (!fq->flows) + return -ENOMEM; + ++ fq->flows_bitmap = kcalloc(BITS_TO_LONGS(fq->flows_cnt), sizeof(long), ++ GFP_KERNEL); ++ if (!fq->flows_bitmap) { ++ kvfree(fq->flows); ++ fq->flows = NULL; ++ return -ENOMEM; ++ } ++ + for (i = 0; i < fq->flows_cnt; i++) + fq_flow_init(&fq->flows[i]); + +@@ -332,6 +382,9 @@ static void fq_reset(struct fq *fq, + + kvfree(fq->flows); + fq->flows = NULL; ++ ++ kfree(fq->flows_bitmap); ++ fq->flows_bitmap = NULL; + } + + #endif diff --git a/include/net/mac80211.h b/include/net/mac80211.h -index b2d7dad..bca141e 100644 +index 9840f6e..9f185ee 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h -@@ -967,6 +967,7 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) - * @band: the band to transmit on (use for checking for races) - * @hw_queue: HW queue to put the frame on, skb_get_queue_mapping() gives the AC - * @ack_frame_id: internal frame ID for TX status, used internally -+ * @tx_time_est: TX time estimate in units of 4us, used internally - * @control: union part for control data - * @control.rates: TX rates array to try - * @control.rts_cts_rate_idx: rate for RTS or CTS -@@ -1003,11 +1004,11 @@ ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate) - struct ieee80211_tx_info { - /* common information */ - u32 flags; -- u8 band; -- -- u8 hw_queue; -- -- u16 ack_frame_id; -+ u32 band:3, -+ ack_frame_id:13, -+ hw_queue:4, -+ tx_time_est:10; -+ /* 2 free bits */ - - union { - struct { -@@ -1058,6 +1059,22 @@ struct ieee80211_tx_info { - }; +@@ -1297,6 +1297,8 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info) + * the "0-length PSDU" field included there. The value for it is + * in &struct ieee80211_rx_status. Note that if this value isn't + * known the frame shouldn't be reported. ++ * @RX_FLAG_8023: the frame has an 802.3 header (decap offload performed by ++ * hardware or driver) + */ + enum mac80211_rx_flags { + RX_FLAG_MMIC_ERROR = BIT(0), +@@ -1329,6 +1331,7 @@ enum mac80211_rx_flags { + RX_FLAG_RADIOTAP_HE_MU = BIT(27), + RX_FLAG_RADIOTAP_LSIG = BIT(28), + RX_FLAG_NO_PSDU = BIT(29), ++ RX_FLAG_8023 = BIT(30), }; -+static inline u16 -+ieee80211_info_set_tx_time_est(struct ieee80211_tx_info *info, u16 tx_time_est) -+{ -+ /* We only have 10 bits in tx_time_est, so store airtime -+ * in increments of 4us and clamp the maximum to 2**12-1 -+ */ -+ info->tx_time_est = min_t(u16, tx_time_est, 4095) >> 2; -+ return info->tx_time_est << 2; -+} -+ -+static inline u16 -+ieee80211_info_get_tx_time_est(struct ieee80211_tx_info *info) -+{ -+ return info->tx_time_est << 2; -+} -+ /** - * struct ieee80211_tx_status - extended tx staus info for rate control - * -@@ -1484,6 +1501,7 @@ enum ieee80211_smps_mode { +@@ -1558,6 +1561,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 @@ -154,7 +489,7 @@ index b2d7dad..bca141e 100644 * * @chandef: the channel definition to tune to * @radar_enabled: whether radar detection is enabled -@@ -1504,6 +1522,7 @@ enum ieee80211_smps_mode { +@@ -1578,6 +1582,7 @@ enum ieee80211_smps_mode { struct ieee80211_conf { u32 flags; int power_level, dynamic_ps_timeout; @@ -162,104 +497,99 @@ index b2d7dad..bca141e 100644 u16 listen_interval; u8 ps_dtim_period; -@@ -5557,6 +5576,18 @@ void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, - u32 tx_airtime, u32 rx_airtime); +@@ -1650,11 +1655,15 @@ enum ieee80211_vif_flags { + * The driver supports sending frames passed as 802.3 frames by mac80211. + * It must also support sending 802.11 packets for the same interface. + * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload ++ * @IEEE80211_OFFLOAD_DECAP_ENABLED: rx encapsulation offload is enabled ++ * The driver supports passing received 802.11 frames as 802.3 frames to ++ * mac80211. + */ + + enum ieee80211_offload_flags { + IEEE80211_OFFLOAD_ENCAP_ENABLED = BIT(0), + IEEE80211_OFFLOAD_ENCAP_4ADDR = BIT(1), ++ IEEE80211_OFFLOAD_DECAP_ENABLED = BIT(2), + }; /** -+ * ieee80211_txq_airtime_check - check if a txq can send frame to device +@@ -2390,6 +2399,9 @@ struct ieee80211_txq { + * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation + * offload + * ++ * @IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD: Hardware supports rx decapsulation ++ * offload + * -+ * @hw: pointer obtained from ieee80211_alloc_hw() -+ * @txq: pointer obtained from station or virtual interface -+ * -+ * Return true if the AQL's airtime limit has not been reached and the txq can -+ * continue to send more packets to the device. Otherwise return false. -+ */ -+bool -+ieee80211_txq_airtime_check(struct ieee80211_hw *hw, struct ieee80211_txq *txq); -+ -+/** - * 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 -@@ -6415,4 +6446,33 @@ void ieee80211_nan_func_match(struct ieee80211_vif *vif, - struct cfg80211_nan_match_params *match, - gfp_t gfp); + * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays + */ + enum ieee80211_hw_flags { +@@ -2443,6 +2455,7 @@ enum ieee80211_hw_flags { + IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID, + IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT, + IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD, ++ IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD, -+/** -+ * ieee80211_calc_rx_airtime - calculate estimated transmission airtime for RX. + /* keep last, obviously */ + NUM_IEEE80211_HW_FLAGS +@@ -4196,6 +4209,9 @@ struct ieee80211_ops { + struct ieee80211_vif *vif); + void (*sta_set_4addr)(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + struct ieee80211_sta *sta, bool enabled); ++ void (*sta_set_decap_offload)(struct ieee80211_hw *hw, ++ struct ieee80211_vif *vif, ++ struct ieee80211_sta *sta, bool enabled); + }; + + /** +@@ -5885,6 +5901,17 @@ void ieee80211_beacon_loss(struct ieee80211_vif *vif); + void ieee80211_connection_loss(struct ieee80211_vif *vif); + + /** ++ * ieee80211_disconnect - request disconnection + * -+ * This function calculates the estimated airtime usage of a frame based on the -+ * rate information in the RX status struct and the frame length. ++ * @vif: &struct ieee80211_vif pointer from the add_interface callback. ++ * @reconnect: immediate reconnect is desired + * -+ * @hw: pointer as obtained from ieee80211_alloc_hw() -+ * @status: &struct ieee80211_rx_status containing the transmission rate -+ * information. -+ * @len: frame length in bytes ++ * Request disconnection from the current network and, if enabled, send a ++ * hint to the higher layers that immediate reconnect is desired. + */ -+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_rx_status *status, -+ int len); ++void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect); + +/** -+ * ieee80211_calc_tx_airtime - calculate estimated transmission airtime for TX. -+ * -+ * This function calculates the estimated airtime usage of a frame based on the -+ * rate information in the TX info struct and the frame length. -+ * -+ * @hw: pointer as obtained from ieee80211_alloc_hw() -+ * @info: &struct ieee80211_tx_info of the frame. -+ * @len: frame length in bytes -+ */ -+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_tx_info *info, -+ int len); -+ - #endif /* MAC80211_H */ + * ieee80211_resume_disconnect - disconnect from AP after resume + * + * @vif: &struct ieee80211_vif pointer from the add_interface callback. diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h -index beee59c..ef08258 100644 +index 47700a2..0d90183 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -2373,6 +2373,9 @@ enum nl80211_commands { - * the allowed channel bandwidth configurations. (u8 attribute) - * Defined by IEEE P802.11ay/D4.0 section 9.4.2.251, Table 13. +@@ -2527,6 +2527,13 @@ enum nl80211_commands { + * override mask. Used with NL80211_ATTR_S1G_CAPABILITY in + * NL80211_CMD_ASSOCIATE or NL80211_CMD_CONNECT. * ++ * @NL80211_ATTR_RECONNECT_REQUESTED: flag attribute, used with deauth and ++ * disassoc events to indicate that an immediate reconnect to the AP ++ * is desired. ++ * + * @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 -@@ -2835,6 +2838,8 @@ enum nl80211_attrs { - NL80211_ATTR_WIPHY_EDMG_CHANNELS, - NL80211_ATTR_WIPHY_EDMG_BW_CONFIG, +@@ -3016,6 +3023,10 @@ enum nl80211_attrs { + NL80211_ATTR_S1G_CAPABILITY, + NL80211_ATTR_S1G_CAPABILITY_MASK, ++ NL80211_ATTR_RECONNECT_REQUESTED, ++ + NL80211_ATTR_WIPHY_ANTENNA_GAIN, + /* add attributes here, update the policy in nl80211.c */ __NL80211_ATTR_AFTER_LAST, -@@ -5484,6 +5489,10 @@ enum nl80211_feature_flags { - * @NL80211_EXT_FEATURE_SAE_OFFLOAD: Device wants to do SAE authentication in - * station mode (SAE password is passed as part of the connect command). - * -+ * @NL80211_EXT_FEATURE_AQL: The driver supports the Airtime Queue Limit (AQL) -+ * feature, which prevents bufferbloat by using the expected transmission -+ * time to limit the amount of data buffered in the hardware. -+ * - * @NUM_NL80211_EXT_FEATURES: number of extended features. - * @MAX_NL80211_EXT_FEATURES: highest extended feature index. - */ -@@ -5529,6 +5538,8 @@ enum nl80211_ext_feature_index { - NL80211_EXT_FEATURE_EXT_KEY_ID, - NL80211_EXT_FEATURE_STA_TX_PWR, - NL80211_EXT_FEATURE_SAE_OFFLOAD, -+ NL80211_EXT_FEATURE_VLAN_OFFLOAD, -+ NL80211_EXT_FEATURE_AQL, - - /* add new features before the definition below */ - NUM_NL80211_EXT_FEATURES, diff --git a/net/mac80211/Kconfig b/net/mac80211/Kconfig -index dd981a0..f7f8247 100644 +index 329467a..0e07a82 100644 --- a/net/mac80211/Kconfig +++ b/net/mac80211/Kconfig @@ -6,9 +6,6 @@ config MAC80211 @@ -270,10 +600,10 @@ index dd981a0..f7f8247 100644 - depends on CRYPTO_GCM - depends on CRYPTO_CMAC depends on CRC32 - ---help--- + help This option enables the hardware independent IEEE 802.11 diff --git a/net/mac80211/Makefile b/net/mac80211/Makefile -index 7bb0a16..910982f 100644 +index 8a8f265..6a2ce73 100644 --- a/net/mac80211/Makefile +++ b/net/mac80211/Makefile @@ -7,7 +7,6 @@ mac80211-y := \ @@ -284,7 +614,7 @@ index 7bb0a16..910982f 100644 wpa.o \ scan.o offchannel.o \ ht.o agg-tx.o agg-rx.o \ -@@ -18,8 +17,8 @@ mac80211-y := \ +@@ -19,8 +18,8 @@ mac80211-y := \ rate.o \ michael.o \ tkip.o \ @@ -294,16 +624,136 @@ index 7bb0a16..910982f 100644 fils_aead.o \ cfg.o \ ethtool.o \ -@@ -32,7 +31,8 @@ mac80211-y := \ - chan.o \ - trace.o mlme.o \ - tdls.o \ -- ocb.o -+ ocb.o \ -+ airtime.o +@@ -56,11 +55,9 @@ mac80211-$(CONFIG_PM) += pm.o + CFLAGS_trace.o := -I$(src) - mac80211-$(CPTCFG_MAC80211_LEDS) += led.o - mac80211-$(CPTCFG_MAC80211_DEBUGFS) += \ + rc80211_minstrel-y := \ +- rc80211_minstrel.o \ + rc80211_minstrel_ht.o + + rc80211_minstrel-$(CPTCFG_MAC80211_DEBUGFS) += \ +- rc80211_minstrel_debugfs.o \ + rc80211_minstrel_ht_debugfs.o + + mac80211-$(CPTCFG_MAC80211_RC_MINSTREL) += $(rc80211_minstrel-y) +diff --git a/net/mac80211/aead_api.c b/net/mac80211/aead_api.c +deleted file mode 100644 +index d7b3d90..0000000 +--- a/net/mac80211/aead_api.c ++++ /dev/null +@@ -1,112 +0,0 @@ +-// SPDX-License-Identifier: GPL-2.0-only +-/* +- * Copyright 2003-2004, Instant802 Networks, Inc. +- * Copyright 2005-2006, Devicescape Software, Inc. +- * Copyright 2014-2015, Qualcomm Atheros, Inc. +- * +- * Rewrite: Copyright (C) 2013 Linaro Ltd +- */ +- +-#include +-#include +-#include +-#include +-#include +- +-#include "aead_api.h" +- +-int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, +- u8 *data, size_t data_len, u8 *mic) +-{ +- size_t mic_len = crypto_aead_authsize(tfm); +- struct scatterlist sg[3]; +- struct aead_request *aead_req; +- int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); +- u8 *__aad; +- +- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); +- if (!aead_req) +- return -ENOMEM; +- +- __aad = (u8 *)aead_req + reqsize; +- memcpy(__aad, aad, aad_len); +- +- sg_init_table(sg, 3); +- sg_set_buf(&sg[0], __aad, aad_len); +- sg_set_buf(&sg[1], data, data_len); +- sg_set_buf(&sg[2], mic, mic_len); +- +- aead_request_set_tfm(aead_req, tfm); +- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0); +- aead_request_set_ad(aead_req, sg[0].length); +- +- crypto_aead_encrypt(aead_req); +- kfree_sensitive(aead_req); +- +- return 0; +-} +- +-int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, +- u8 *data, size_t data_len, u8 *mic) +-{ +- size_t mic_len = crypto_aead_authsize(tfm); +- struct scatterlist sg[3]; +- struct aead_request *aead_req; +- int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); +- u8 *__aad; +- int err; +- +- if (data_len == 0) +- return -EINVAL; +- +- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); +- if (!aead_req) +- return -ENOMEM; +- +- __aad = (u8 *)aead_req + reqsize; +- memcpy(__aad, aad, aad_len); +- +- sg_init_table(sg, 3); +- sg_set_buf(&sg[0], __aad, aad_len); +- sg_set_buf(&sg[1], data, data_len); +- sg_set_buf(&sg[2], mic, mic_len); +- +- aead_request_set_tfm(aead_req, tfm); +- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); +- aead_request_set_ad(aead_req, sg[0].length); +- +- err = crypto_aead_decrypt(aead_req); +- kfree_sensitive(aead_req); +- +- return err; +-} +- +-struct crypto_aead * +-aead_key_setup_encrypt(const char *alg, const u8 key[], +- size_t key_len, size_t mic_len) +-{ +- struct crypto_aead *tfm; +- int err; +- +- tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC); +- if (IS_ERR(tfm)) +- return tfm; +- +- err = crypto_aead_setkey(tfm, key, key_len); +- if (err) +- goto free_aead; +- err = crypto_aead_setauthsize(tfm, mic_len); +- if (err) +- goto free_aead; +- +- return tfm; +- +-free_aead: +- crypto_free_aead(tfm); +- return ERR_PTR(err); +-} +- +-void aead_key_free(struct crypto_aead *tfm) +-{ +- crypto_free_aead(tfm); +-} diff --git a/net/mac80211/aead_api.h b/net/mac80211/aead_api.h deleted file mode 100644 index 7d463b8..0000000 @@ -540,17 +990,16 @@ index 9625619..7e99852 100644 #endif /* AES_CCM_H */ diff --git a/net/mac80211/aes_cmac.c b/net/mac80211/aes_cmac.c -index 57748ca..6568a97 100644 +index b31f102..f06086c 100644 --- a/net/mac80211/aes_cmac.c +++ b/net/mac80211/aes_cmac.c -@@ -19,50 +19,126 @@ +@@ -19,67 +19,151 @@ #define CMAC_TLEN_256 16 /* CMAC TLen = 128 bits (16 octets) */ #define AAD_LEN 20 -static const u8 zero[CMAC_TLEN_256]; -void ieee80211_aes_cmac(struct crypto_shash *tfm, const u8 *aad, -- const u8 *data, size_t data_len, u8 *mic) +void gf_mulx(u8 *pad) +{ + int i, carry; @@ -566,9 +1015,7 @@ index 57748ca..6568a97 100644 +void aes_cmac_vector(struct crypto_cipher *tfm, size_t num_elem, + const u8 *addr[], const size_t *len, u8 *mac, + size_t mac_len) - { -- SHASH_DESC_ON_STACK(desc, tfm); -- u8 out[AES_BLOCK_SIZE]; ++{ + u8 cbc[AES_BLOCK_SIZE], pad[AES_BLOCK_SIZE]; + const u8 *pos, *end; + size_t i, e, left, total_len; @@ -597,16 +1044,11 @@ index 57748ca..6568a97 100644 + crypto_cipher_encrypt_one(tfm, cbc, cbc); + left -= AES_BLOCK_SIZE; + } - -- desc->tfm = tfm; ++ + memset(pad, 0, AES_BLOCK_SIZE); + crypto_cipher_encrypt_one(tfm, pad, pad); + gf_mulx(pad); - -- crypto_shash_init(desc); -- crypto_shash_update(desc, aad, AAD_LEN); -- crypto_shash_update(desc, data, data_len - CMAC_TLEN); -- crypto_shash_finup(desc, zero, CMAC_TLEN, out); ++ + if (left || total_len == 0) { + for (i = 0; i < left; i++) { + cbc[i] ^= *pos++; @@ -619,56 +1061,96 @@ index 57748ca..6568a97 100644 + cbc[left] ^= 0x80; + gf_mulx(pad); + } - -- memcpy(mic, out, CMAC_TLEN); ++ + for (i = 0; i < AES_BLOCK_SIZE; i++) + pad[i] ^= cbc[i]; + crypto_cipher_encrypt_one(tfm, pad, pad); + memcpy(mac, pad, mac_len); - } - --void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, ++} ++ + +void ieee80211_aes_cmac(struct crypto_cipher *tfm, const u8 *aad, -+ const u8 *data, size_t data_len, u8 *mic) -+{ -+ const u8 *addr[3]; -+ size_t len[3]; + const u8 *data, size_t data_len, u8 *mic) + { +- SHASH_DESC_ON_STACK(desc, tfm); +- u8 out[AES_BLOCK_SIZE]; ++ const u8 *addr[4]; ++ size_t len[4]; + u8 zero[CMAC_TLEN]; -+ + const __le16 *fc; + +- desc->tfm = tfm; +- +- crypto_shash_init(desc); +- crypto_shash_update(desc, aad, AAD_LEN); + memset(zero, 0, CMAC_TLEN); + addr[0] = aad; + len[0] = AAD_LEN; -+ addr[1] = data; -+ len[1] = data_len - CMAC_TLEN; -+ addr[2] = zero; -+ len[2] = CMAC_TLEN; -+ -+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN); -+} -+ + fc = (const __le16 *)aad; + if (ieee80211_is_beacon(*fc)) { + /* mask Timestamp field to zero */ +- crypto_shash_update(desc, zero, 8); +- crypto_shash_update(desc, data + 8, data_len - 8 - CMAC_TLEN); ++ addr[1] = zero; ++ len[1] = 8; ++ addr[2] = data + 8; ++ len[2] = data_len - 8 - CMAC_TLEN; ++ addr[3] = zero; ++ len[3] = CMAC_TLEN; ++ aes_cmac_vector(tfm, 4, addr, len, mic, CMAC_TLEN); + } else { +- crypto_shash_update(desc, data, data_len - CMAC_TLEN); ++ addr[1] = data; ++ len[1] = data_len - CMAC_TLEN; ++ addr[2] = zero; ++ len[2] = CMAC_TLEN; ++ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN); + } +- crypto_shash_finup(desc, zero, CMAC_TLEN, out); +- +- memcpy(mic, out, CMAC_TLEN); + } + +-void ieee80211_aes_cmac_256(struct crypto_shash *tfm, const u8 *aad, +void ieee80211_aes_cmac_256(struct crypto_cipher *tfm, const u8 *aad, const u8 *data, size_t data_len, u8 *mic) { - SHASH_DESC_ON_STACK(desc, tfm); -+ const u8 *addr[3]; -+ size_t len[3]; ++ const u8 *addr[4]; ++ size_t len[4]; + u8 zero[CMAC_TLEN_256]; + const __le16 *fc; - desc->tfm = tfm; +- +- crypto_shash_init(desc); +- crypto_shash_update(desc, aad, AAD_LEN); + memset(zero, 0, CMAC_TLEN_256); + addr[0] = aad; + len[0] = AAD_LEN; + addr[1] = data; -+ len[1] = data_len - CMAC_TLEN_256; -+ addr[2] = zero; -+ len[2] = CMAC_TLEN_256; - -- crypto_shash_init(desc); -- crypto_shash_update(desc, aad, AAD_LEN); -- crypto_shash_update(desc, data, data_len - CMAC_TLEN_256); + fc = (const __le16 *)aad; + if (ieee80211_is_beacon(*fc)) { + /* mask Timestamp field to zero */ +- crypto_shash_update(desc, zero, 8); +- crypto_shash_update(desc, data + 8, +- data_len - 8 - CMAC_TLEN_256); ++ addr[1] = zero; ++ len[1] = 8; ++ addr[2] = data + 8; ++ len[2] = data_len - 8 - CMAC_TLEN_256; ++ addr[3] = zero; ++ len[3] = CMAC_TLEN_256; ++ aes_cmac_vector(tfm, 4, addr, len, mic, CMAC_TLEN_256); + } else { +- crypto_shash_update(desc, data, data_len - CMAC_TLEN_256); ++ addr[1] = data; ++ len[1] = data_len - CMAC_TLEN_256; ++ addr[2] = zero; ++ len[2] = CMAC_TLEN_256; ++ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256); + } - crypto_shash_finup(desc, zero, CMAC_TLEN_256, mic); -+ aes_cmac_vector(tfm, 3, addr, len, mic, CMAC_TLEN_256); } -struct crypto_shash *ieee80211_aes_cmac_key_setup(const u8 key[], @@ -719,146 +1201,121 @@ index 7681744..430616c 100644 +void ieee80211_aes_cmac_key_free(struct crypto_cipher *tfm); #endif /* AES_CMAC_H */ -diff --git a/net/mac80211/aead_api.c b/net/mac80211/aes_gcm.c -similarity index 50% -rename from net/mac80211/aead_api.c -rename to net/mac80211/aes_gcm.c -index c5fe95e..8a4397c 100644 ---- a/net/mac80211/aead_api.c +diff --git a/net/mac80211/aes_gcm.c b/net/mac80211/aes_gcm.c +new file mode 100644 +index 0000000..8a4397c +--- /dev/null +++ b/net/mac80211/aes_gcm.c -@@ -1,55 +1,52 @@ --// SPDX-License-Identifier: GPL-2.0-only - /* -- * Copyright 2003-2004, Instant802 Networks, Inc. -- * Copyright 2005-2006, Devicescape Software, Inc. - * Copyright 2014-2015, Qualcomm Atheros, Inc. - * -- * Rewrite: Copyright (C) 2013 Linaro Ltd +@@ -0,0 +1,109 @@ ++/* ++ * Copyright 2014-2015, Qualcomm Atheros, Inc. ++ * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. - */ - - #include - #include - #include --#include - #include - --#include "aead_api.h" ++ */ ++ ++#include ++#include ++#include ++#include ++ +#include +#include "key.h" +#include "aes_gcm.h" - --int aead_encrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, -- u8 *data, size_t data_len, u8 *mic) ++ +int ieee80211_aes_gcm_encrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic) - { -- size_t mic_len = crypto_aead_authsize(tfm); - struct scatterlist sg[3]; - struct aead_request *aead_req; - int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); - u8 *__aad; - -- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); ++{ ++ struct scatterlist sg[3]; ++ struct aead_request *aead_req; ++ int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); ++ u8 *__aad; ++ + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); - if (!aead_req) - return -ENOMEM; - - __aad = (u8 *)aead_req + reqsize; -- memcpy(__aad, aad, aad_len); ++ if (!aead_req) ++ return -ENOMEM; ++ ++ __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, GCM_AAD_LEN); - - sg_init_table(sg, 3); -- sg_set_buf(&sg[0], __aad, aad_len); ++ ++ sg_init_table(sg, 3); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); - sg_set_buf(&sg[1], data, data_len); -- sg_set_buf(&sg[2], mic, mic_len); ++ sg_set_buf(&sg[1], data, data_len); + sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); - - aead_request_set_tfm(aead_req, tfm); -- aead_request_set_crypt(aead_req, sg, sg, data_len, b_0); ++ ++ aead_request_set_tfm(aead_req, tfm); + aead_request_set_crypt(aead_req, sg, sg, data_len, j_0); - aead_request_set_ad(aead_req, sg[0].length); - - crypto_aead_encrypt(aead_req); - kzfree(aead_req); -- - return 0; - } - --int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, -- u8 *data, size_t data_len, u8 *mic) ++ aead_request_set_ad(aead_req, sg[0].length); ++ ++ crypto_aead_encrypt(aead_req); ++ kzfree(aead_req); ++ return 0; ++} ++ +int ieee80211_aes_gcm_decrypt(struct crypto_aead *tfm, u8 *j_0, u8 *aad, + u8 *data, size_t data_len, u8 *mic) - { -- size_t mic_len = crypto_aead_authsize(tfm); - struct scatterlist sg[3]; - struct aead_request *aead_req; - int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); -@@ -59,20 +56,21 @@ int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, - if (data_len == 0) - return -EINVAL; - -- aead_req = kzalloc(reqsize + aad_len, GFP_ATOMIC); ++{ ++ struct scatterlist sg[3]; ++ struct aead_request *aead_req; ++ int reqsize = sizeof(*aead_req) + crypto_aead_reqsize(tfm); ++ u8 *__aad; ++ int err; ++ ++ if (data_len == 0) ++ return -EINVAL; ++ + aead_req = kzalloc(reqsize + GCM_AAD_LEN, GFP_ATOMIC); - if (!aead_req) - return -ENOMEM; - - __aad = (u8 *)aead_req + reqsize; -- memcpy(__aad, aad, aad_len); ++ if (!aead_req) ++ return -ENOMEM; ++ ++ __aad = (u8 *)aead_req + reqsize; + memcpy(__aad, aad, GCM_AAD_LEN); - - sg_init_table(sg, 3); -- sg_set_buf(&sg[0], __aad, aad_len); ++ ++ sg_init_table(sg, 3); + sg_set_buf(&sg[0], &__aad[2], be16_to_cpup((__be16 *)__aad)); - sg_set_buf(&sg[1], data, data_len); -- sg_set_buf(&sg[2], mic, mic_len); ++ sg_set_buf(&sg[1], data, data_len); + sg_set_buf(&sg[2], mic, IEEE80211_GCMP_MIC_LEN); - - aead_request_set_tfm(aead_req, tfm); -- aead_request_set_crypt(aead_req, sg, sg, data_len + mic_len, b_0); ++ ++ aead_request_set_tfm(aead_req, tfm); + aead_request_set_crypt(aead_req, sg, sg, + data_len + IEEE80211_GCMP_MIC_LEN, j_0); - aead_request_set_ad(aead_req, sg[0].length); - - err = crypto_aead_decrypt(aead_req); -@@ -81,21 +79,20 @@ int aead_decrypt(struct crypto_aead *tfm, u8 *b_0, u8 *aad, size_t aad_len, - return err; - } - --struct crypto_aead * --aead_key_setup_encrypt(const char *alg, const u8 key[], -- size_t key_len, size_t mic_len) ++ aead_request_set_ad(aead_req, sg[0].length); ++ ++ err = crypto_aead_decrypt(aead_req); ++ kzfree(aead_req); ++ ++ return err; ++} ++ +struct crypto_aead *ieee80211_aes_gcm_key_setup_encrypt(const u8 key[], + size_t key_len) - { - struct crypto_aead *tfm; - int err; - -- tfm = crypto_alloc_aead(alg, 0, CRYPTO_ALG_ASYNC); ++{ ++ struct crypto_aead *tfm; ++ int err; ++ + tfm = crypto_alloc_aead("gcm(aes)", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) - return tfm; - - err = crypto_aead_setkey(tfm, key, key_len); - if (err) - goto free_aead; -- err = crypto_aead_setauthsize(tfm, mic_len); ++ if (IS_ERR(tfm)) ++ return tfm; ++ ++ err = crypto_aead_setkey(tfm, key, key_len); ++ if (err) ++ goto free_aead; + err = crypto_aead_setauthsize(tfm, IEEE80211_GCMP_MIC_LEN); - if (err) - goto free_aead; - -@@ -106,7 +103,7 @@ free_aead: - return ERR_PTR(err); - } - --void aead_key_free(struct crypto_aead *tfm) ++ if (err) ++ goto free_aead; ++ ++ return tfm; ++ ++free_aead: ++ crypto_free_aead(tfm); ++ return ERR_PTR(err); ++} ++ +void ieee80211_aes_gcm_key_free(struct crypto_aead *tfm) - { - crypto_free_aead(tfm); - } ++{ ++ crypto_free_aead(tfm); ++} diff --git a/net/mac80211/aes_gcm.h b/net/mac80211/aes_gcm.h index b14093b..7c3d78d 100644 --- a/net/mac80211/aes_gcm.h @@ -945,622 +1402,19 @@ index c739356..f0e649f 100644 +} #endif /* AES_GMAC_H */ -diff --git a/net/mac80211/airtime.c b/net/mac80211/airtime.c -new file mode 100644 -index 0000000..9fc2968 ---- /dev/null -+++ b/net/mac80211/airtime.c -@@ -0,0 +1,597 @@ -+// SPDX-License-Identifier: ISC -+/* -+ * Copyright (C) 2019 Felix Fietkau -+ */ -+ -+#include -+#include "ieee80211_i.h" -+#include "sta_info.h" -+ -+#define AVG_PKT_SIZE 1024 -+ -+/* Number of bits for an average sized packet */ -+#define MCS_NBITS (AVG_PKT_SIZE << 3) -+ -+/* Number of kilo-symbols (symbols * 1024) for a packet with (bps) bits per -+ * symbol. We use k-symbols to avoid rounding in the _TIME macros below. -+ */ -+#define MCS_N_KSYMS(bps) DIV_ROUND_UP(MCS_NBITS << 10, (bps)) -+ -+/* Transmission time (in 1024 * usec) for a packet containing (ksyms) * 1024 -+ * symbols. -+ */ -+#define MCS_SYMBOL_TIME(sgi, ksyms) \ -+ (sgi ? \ -+ ((ksyms) * 4 * 18) / 20 : /* 3.6 us per sym */ \ -+ ((ksyms) * 4) /* 4.0 us per sym */ \ -+ ) -+ -+/* Transmit duration for the raw data part of an average sized packet */ -+#define MCS_DURATION(streams, sgi, bps) \ -+ ((u32)MCS_SYMBOL_TIME(sgi, MCS_N_KSYMS((streams) * (bps)))) -+ -+#define MCS_DURATION_S(shift, streams, sgi, bps) \ -+ ((u16)((MCS_DURATION(streams, sgi, bps) >> shift))) -+ -+/* These should match the values in enum nl80211_he_gi */ -+#define HE_GI_08 0 -+#define HE_GI_16 1 -+#define HE_GI_32 2 -+ -+/* Transmission time (1024 usec) for a packet containing (ksyms) * k-symbols */ -+#define HE_SYMBOL_TIME(gi, ksyms) \ -+ (gi == HE_GI_08 ? \ -+ ((ksyms) * 16 * 17) / 20 : /* 13.6 us per sym */ \ -+ (gi == HE_GI_16 ? \ -+ ((ksyms) * 16 * 18) / 20 : /* 14.4 us per sym */ \ -+ ((ksyms) * 16) /* 16.0 us per sym */ \ -+ )) -+ -+/* Transmit duration for the raw data part of an average sized packet */ -+#define HE_DURATION(streams, gi, bps) \ -+ ((u32)HE_SYMBOL_TIME(gi, MCS_N_KSYMS((streams) * (bps)))) -+ -+#define HE_DURATION_S(shift, streams, gi, bps) \ -+ (HE_DURATION(streams, gi, bps) >> shift) -+ -+#define BW_20 0 -+#define BW_40 1 -+#define BW_80 2 -+#define BW_160 3 -+ -+/* -+ * Define group sort order: HT40 -> SGI -> #streams -+ */ -+#define IEEE80211_MAX_STREAMS 4 -+#define IEEE80211_HT_STREAM_GROUPS 4 /* BW(=2) * SGI(=2) */ -+#define IEEE80211_VHT_STREAM_GROUPS 8 /* BW(=4) * SGI(=2) */ -+ -+#define IEEE80211_HE_MAX_STREAMS 8 -+#define IEEE80211_HE_STREAM_GROUPS 12 /* BW(=4) * GI(=3) */ -+ -+#define IEEE80211_HT_GROUPS_NB (IEEE80211_MAX_STREAMS * \ -+ IEEE80211_HT_STREAM_GROUPS) -+#define IEEE80211_VHT_GROUPS_NB (IEEE80211_MAX_STREAMS * \ -+ IEEE80211_VHT_STREAM_GROUPS) -+#define IEEE80211_HE_GROUPS_NB (IEEE80211_HE_MAX_STREAMS * \ -+ IEEE80211_HE_STREAM_GROUPS) -+#define IEEE80211_GROUPS_NB (IEEE80211_HT_GROUPS_NB + \ -+ IEEE80211_VHT_GROUPS_NB + \ -+ IEEE80211_HE_GROUPS_NB) -+ -+#define IEEE80211_HT_GROUP_0 0 -+#define IEEE80211_VHT_GROUP_0 (IEEE80211_HT_GROUP_0 + IEEE80211_HT_GROUPS_NB) -+#define IEEE80211_HE_GROUP_0 (IEEE80211_VHT_GROUP_0 + IEEE80211_VHT_GROUPS_NB) -+ -+#define MCS_GROUP_RATES 12 -+ -+#define HT_GROUP_IDX(_streams, _sgi, _ht40) \ -+ IEEE80211_HT_GROUP_0 + \ -+ IEEE80211_MAX_STREAMS * 2 * _ht40 + \ -+ IEEE80211_MAX_STREAMS * _sgi + \ -+ _streams - 1 -+ -+#define _MAX(a, b) (((a)>(b))?(a):(b)) -+ -+#define GROUP_SHIFT(duration) \ -+ _MAX(0, 16 - __builtin_clz(duration)) -+ -+/* MCS rate information for an MCS group */ -+#define __MCS_GROUP(_streams, _sgi, _ht40, _s) \ -+ [HT_GROUP_IDX(_streams, _sgi, _ht40)] = { \ -+ .shift = _s, \ -+ .duration = { \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 54 : 26), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 108 : 52), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 162 : 78), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 216 : 104), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 324 : 156), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 432 : 208), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 486 : 234), \ -+ MCS_DURATION_S(_s, _streams, _sgi, _ht40 ? 540 : 260) \ -+ } \ -+} -+ -+#define MCS_GROUP_SHIFT(_streams, _sgi, _ht40) \ -+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, _ht40 ? 54 : 26)) -+ -+#define MCS_GROUP(_streams, _sgi, _ht40) \ -+ __MCS_GROUP(_streams, _sgi, _ht40, \ -+ MCS_GROUP_SHIFT(_streams, _sgi, _ht40)) -+ -+#define VHT_GROUP_IDX(_streams, _sgi, _bw) \ -+ (IEEE80211_VHT_GROUP_0 + \ -+ IEEE80211_MAX_STREAMS * 2 * (_bw) + \ -+ IEEE80211_MAX_STREAMS * (_sgi) + \ -+ (_streams) - 1) -+ -+#define BW2VBPS(_bw, r4, r3, r2, r1) \ -+ (_bw == BW_160 ? r4 : _bw == BW_80 ? r3 : _bw == BW_40 ? r2 : r1) -+ -+#define __VHT_GROUP(_streams, _sgi, _bw, _s) \ -+ [VHT_GROUP_IDX(_streams, _sgi, _bw)] = { \ -+ .shift = _s, \ -+ .duration = { \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 234, 117, 54, 26)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 468, 234, 108, 52)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 702, 351, 162, 78)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 936, 468, 216, 104)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 1404, 702, 324, 156)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 1872, 936, 432, 208)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 2106, 1053, 486, 234)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 2340, 1170, 540, 260)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 2808, 1404, 648, 312)), \ -+ MCS_DURATION_S(_s, _streams, _sgi, \ -+ BW2VBPS(_bw, 3120, 1560, 720, 346)) \ -+ } \ -+} -+ -+#define VHT_GROUP_SHIFT(_streams, _sgi, _bw) \ -+ GROUP_SHIFT(MCS_DURATION(_streams, _sgi, \ -+ BW2VBPS(_bw, 243, 117, 54, 26))) -+ -+#define VHT_GROUP(_streams, _sgi, _bw) \ -+ __VHT_GROUP(_streams, _sgi, _bw, \ -+ VHT_GROUP_SHIFT(_streams, _sgi, _bw)) -+ -+ -+#define HE_GROUP_IDX(_streams, _gi, _bw) \ -+ (IEEE80211_HE_GROUP_0 + \ -+ IEEE80211_HE_MAX_STREAMS * 3 * (_bw) + \ -+ IEEE80211_HE_MAX_STREAMS * (_gi) + \ -+ (_streams) - 1) -+ -+#define __HE_GROUP(_streams, _gi, _bw, _s) \ -+ [HE_GROUP_IDX(_streams, _gi, _bw)] = { \ -+ .shift = _s, \ -+ .duration = { \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 979, 489, 230, 115)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 1958, 979, 475, 230)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 2937, 1468, 705, 345)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 3916, 1958, 936, 475)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 5875, 2937, 1411, 705)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 7833, 3916, 1872, 936)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 8827, 4406, 2102, 1051)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 9806, 4896, 2347, 1166)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 11764, 5875, 2808, 1411)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 13060, 6523, 3124, 1555)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 14702, 7344, 3513, 1756)), \ -+ HE_DURATION_S(_s, _streams, _gi, \ -+ BW2VBPS(_bw, 16329, 8164, 3902, 1944)) \ -+ } \ -+} -+ -+#define HE_GROUP_SHIFT(_streams, _gi, _bw) \ -+ GROUP_SHIFT(HE_DURATION(_streams, _gi, \ -+ BW2VBPS(_bw, 979, 489, 230, 115))) -+ -+#define HE_GROUP(_streams, _gi, _bw) \ -+ __HE_GROUP(_streams, _gi, _bw, \ -+ HE_GROUP_SHIFT(_streams, _gi, _bw)) -+struct mcs_group { -+ u8 shift; -+ u16 duration[MCS_GROUP_RATES]; -+}; -+ -+static const struct mcs_group airtime_mcs_groups[] = { -+ MCS_GROUP(1, 0, BW_20), -+ MCS_GROUP(2, 0, BW_20), -+ MCS_GROUP(3, 0, BW_20), -+ MCS_GROUP(4, 0, BW_20), -+ -+ MCS_GROUP(1, 1, BW_20), -+ MCS_GROUP(2, 1, BW_20), -+ MCS_GROUP(3, 1, BW_20), -+ MCS_GROUP(4, 1, BW_20), -+ -+ MCS_GROUP(1, 0, BW_40), -+ MCS_GROUP(2, 0, BW_40), -+ MCS_GROUP(3, 0, BW_40), -+ MCS_GROUP(4, 0, BW_40), -+ -+ MCS_GROUP(1, 1, BW_40), -+ MCS_GROUP(2, 1, BW_40), -+ MCS_GROUP(3, 1, BW_40), -+ MCS_GROUP(4, 1, BW_40), -+ -+ VHT_GROUP(1, 0, BW_20), -+ VHT_GROUP(2, 0, BW_20), -+ VHT_GROUP(3, 0, BW_20), -+ VHT_GROUP(4, 0, BW_20), -+ -+ VHT_GROUP(1, 1, BW_20), -+ VHT_GROUP(2, 1, BW_20), -+ VHT_GROUP(3, 1, BW_20), -+ VHT_GROUP(4, 1, BW_20), -+ -+ VHT_GROUP(1, 0, BW_40), -+ VHT_GROUP(2, 0, BW_40), -+ VHT_GROUP(3, 0, BW_40), -+ VHT_GROUP(4, 0, BW_40), -+ -+ VHT_GROUP(1, 1, BW_40), -+ VHT_GROUP(2, 1, BW_40), -+ VHT_GROUP(3, 1, BW_40), -+ VHT_GROUP(4, 1, BW_40), -+ -+ VHT_GROUP(1, 0, BW_80), -+ VHT_GROUP(2, 0, BW_80), -+ VHT_GROUP(3, 0, BW_80), -+ VHT_GROUP(4, 0, BW_80), -+ -+ VHT_GROUP(1, 1, BW_80), -+ VHT_GROUP(2, 1, BW_80), -+ VHT_GROUP(3, 1, BW_80), -+ VHT_GROUP(4, 1, BW_80), -+ -+ VHT_GROUP(1, 0, BW_160), -+ VHT_GROUP(2, 0, BW_160), -+ VHT_GROUP(3, 0, BW_160), -+ VHT_GROUP(4, 0, BW_160), -+ -+ VHT_GROUP(1, 1, BW_160), -+ VHT_GROUP(2, 1, BW_160), -+ VHT_GROUP(3, 1, BW_160), -+ VHT_GROUP(4, 1, BW_160), -+ -+ HE_GROUP(1, HE_GI_08, BW_20), -+ HE_GROUP(2, HE_GI_08, BW_20), -+ HE_GROUP(3, HE_GI_08, BW_20), -+ HE_GROUP(4, HE_GI_08, BW_20), -+ HE_GROUP(5, HE_GI_08, BW_20), -+ HE_GROUP(6, HE_GI_08, BW_20), -+ HE_GROUP(7, HE_GI_08, BW_20), -+ HE_GROUP(8, HE_GI_08, BW_20), -+ -+ HE_GROUP(1, HE_GI_16, BW_20), -+ HE_GROUP(2, HE_GI_16, BW_20), -+ HE_GROUP(3, HE_GI_16, BW_20), -+ HE_GROUP(4, HE_GI_16, BW_20), -+ HE_GROUP(5, HE_GI_16, BW_20), -+ HE_GROUP(6, HE_GI_16, BW_20), -+ HE_GROUP(7, HE_GI_16, BW_20), -+ HE_GROUP(8, HE_GI_16, BW_20), -+ -+ HE_GROUP(1, HE_GI_32, BW_20), -+ HE_GROUP(2, HE_GI_32, BW_20), -+ HE_GROUP(3, HE_GI_32, BW_20), -+ HE_GROUP(4, HE_GI_32, BW_20), -+ HE_GROUP(5, HE_GI_32, BW_20), -+ HE_GROUP(6, HE_GI_32, BW_20), -+ HE_GROUP(7, HE_GI_32, BW_20), -+ HE_GROUP(8, HE_GI_32, BW_20), -+ -+ HE_GROUP(1, HE_GI_08, BW_40), -+ HE_GROUP(2, HE_GI_08, BW_40), -+ HE_GROUP(3, HE_GI_08, BW_40), -+ HE_GROUP(4, HE_GI_08, BW_40), -+ HE_GROUP(5, HE_GI_08, BW_40), -+ HE_GROUP(6, HE_GI_08, BW_40), -+ HE_GROUP(7, HE_GI_08, BW_40), -+ HE_GROUP(8, HE_GI_08, BW_40), -+ -+ HE_GROUP(1, HE_GI_16, BW_40), -+ HE_GROUP(2, HE_GI_16, BW_40), -+ HE_GROUP(3, HE_GI_16, BW_40), -+ HE_GROUP(4, HE_GI_16, BW_40), -+ HE_GROUP(5, HE_GI_16, BW_40), -+ HE_GROUP(6, HE_GI_16, BW_40), -+ HE_GROUP(7, HE_GI_16, BW_40), -+ HE_GROUP(8, HE_GI_16, BW_40), -+ -+ HE_GROUP(1, HE_GI_32, BW_40), -+ HE_GROUP(2, HE_GI_32, BW_40), -+ HE_GROUP(3, HE_GI_32, BW_40), -+ HE_GROUP(4, HE_GI_32, BW_40), -+ HE_GROUP(5, HE_GI_32, BW_40), -+ HE_GROUP(6, HE_GI_32, BW_40), -+ HE_GROUP(7, HE_GI_32, BW_40), -+ HE_GROUP(8, HE_GI_32, BW_40), -+ -+ HE_GROUP(1, HE_GI_08, BW_80), -+ HE_GROUP(2, HE_GI_08, BW_80), -+ HE_GROUP(3, HE_GI_08, BW_80), -+ HE_GROUP(4, HE_GI_08, BW_80), -+ HE_GROUP(5, HE_GI_08, BW_80), -+ HE_GROUP(6, HE_GI_08, BW_80), -+ HE_GROUP(7, HE_GI_08, BW_80), -+ HE_GROUP(8, HE_GI_08, BW_80), -+ -+ HE_GROUP(1, HE_GI_16, BW_80), -+ HE_GROUP(2, HE_GI_16, BW_80), -+ HE_GROUP(3, HE_GI_16, BW_80), -+ HE_GROUP(4, HE_GI_16, BW_80), -+ HE_GROUP(5, HE_GI_16, BW_80), -+ HE_GROUP(6, HE_GI_16, BW_80), -+ HE_GROUP(7, HE_GI_16, BW_80), -+ HE_GROUP(8, HE_GI_16, BW_80), -+ -+ HE_GROUP(1, HE_GI_32, BW_80), -+ HE_GROUP(2, HE_GI_32, BW_80), -+ HE_GROUP(3, HE_GI_32, BW_80), -+ HE_GROUP(4, HE_GI_32, BW_80), -+ HE_GROUP(5, HE_GI_32, BW_80), -+ HE_GROUP(6, HE_GI_32, BW_80), -+ HE_GROUP(7, HE_GI_32, BW_80), -+ HE_GROUP(8, HE_GI_32, BW_80), -+ -+ HE_GROUP(1, HE_GI_08, BW_160), -+ HE_GROUP(2, HE_GI_08, BW_160), -+ HE_GROUP(3, HE_GI_08, BW_160), -+ HE_GROUP(4, HE_GI_08, BW_160), -+ HE_GROUP(5, HE_GI_08, BW_160), -+ HE_GROUP(6, HE_GI_08, BW_160), -+ HE_GROUP(7, HE_GI_08, BW_160), -+ HE_GROUP(8, HE_GI_08, BW_160), -+ -+ HE_GROUP(1, HE_GI_16, BW_160), -+ HE_GROUP(2, HE_GI_16, BW_160), -+ HE_GROUP(3, HE_GI_16, BW_160), -+ HE_GROUP(4, HE_GI_16, BW_160), -+ HE_GROUP(5, HE_GI_16, BW_160), -+ HE_GROUP(6, HE_GI_16, BW_160), -+ HE_GROUP(7, HE_GI_16, BW_160), -+ HE_GROUP(8, HE_GI_16, BW_160), -+ -+ HE_GROUP(1, HE_GI_32, BW_160), -+ HE_GROUP(2, HE_GI_32, BW_160), -+ HE_GROUP(3, HE_GI_32, BW_160), -+ HE_GROUP(4, HE_GI_32, BW_160), -+ HE_GROUP(5, HE_GI_32, BW_160), -+ HE_GROUP(6, HE_GI_32, BW_160), -+ HE_GROUP(7, HE_GI_32, BW_160), -+ HE_GROUP(8, HE_GI_32, BW_160), -+}; -+ -+static u32 -+ieee80211_calc_legacy_rate_duration(u16 bitrate, bool short_pre, -+ bool cck, int len) -+{ -+ u32 duration; -+ -+ if (cck) { -+ duration = 144 + 48; /* preamble + PLCP */ -+ if (short_pre) -+ duration >>= 1; -+ -+ duration += 10; /* SIFS */ -+ } else { -+ duration = 20 + 16; /* premable + SIFS */ -+ } -+ -+ len <<= 3; -+ duration += (len * 10) / bitrate; -+ -+ return duration; -+} -+ -+u32 ieee80211_calc_rx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_rx_status *status, -+ int len) -+{ -+ struct ieee80211_supported_band *sband; -+ const struct ieee80211_rate *rate; -+ bool sgi = status->enc_flags & RX_ENC_FLAG_SHORT_GI; -+ bool sp = status->enc_flags & RX_ENC_FLAG_SHORTPRE; -+ int bw, streams; -+ int group, idx; -+ u32 duration; -+ bool cck; -+ -+ switch (status->bw) { -+ case RATE_INFO_BW_20: -+ bw = BW_20; -+ break; -+ case RATE_INFO_BW_40: -+ bw = BW_40; -+ break; -+ case RATE_INFO_BW_80: -+ bw = BW_80; -+ break; -+ case RATE_INFO_BW_160: -+ bw = BW_160; -+ break; -+ default: -+ WARN_ON_ONCE(1); -+ return 0; -+ } -+ -+ switch (status->encoding) { -+ case RX_ENC_LEGACY: -+ if (WARN_ON_ONCE(status->band > NL80211_BAND_5GHZ)) -+ return 0; -+ -+ sband = hw->wiphy->bands[status->band]; -+ if (!sband || status->rate_idx >= sband->n_bitrates) -+ return 0; -+ -+ rate = &sband->bitrates[status->rate_idx]; -+ cck = rate->flags & IEEE80211_RATE_MANDATORY_B; -+ -+ return ieee80211_calc_legacy_rate_duration(rate->bitrate, sp, -+ cck, len); -+ -+ case RX_ENC_VHT: -+ streams = status->nss; -+ idx = status->rate_idx; -+ group = VHT_GROUP_IDX(streams, sgi, bw); -+ break; -+ case RX_ENC_HT: -+ streams = ((status->rate_idx >> 3) & 3) + 1; -+ idx = status->rate_idx & 7; -+ group = HT_GROUP_IDX(streams, sgi, bw); -+ break; -+ case RX_ENC_HE: -+ streams = status->nss; -+ idx = status->rate_idx; -+ group = HE_GROUP_IDX(streams, status->he_gi, bw); -+ break; -+ default: -+ WARN_ON_ONCE(1); -+ return 0; -+ } -+ -+ if (WARN_ON_ONCE((status->encoding != RX_ENC_HE && streams > 4) || -+ (status->encoding == RX_ENC_HE && streams > 8))) -+ return 0; -+ -+ duration = airtime_mcs_groups[group].duration[idx]; -+ duration <<= airtime_mcs_groups[group].shift; -+ duration *= len; -+ duration /= AVG_PKT_SIZE; -+ duration /= 1024; -+ -+ duration += 36 + (streams << 2); -+ -+ return duration; -+} -+EXPORT_SYMBOL_GPL(ieee80211_calc_rx_airtime); -+ -+static u32 ieee80211_calc_tx_airtime_rate(struct ieee80211_hw *hw, -+ struct ieee80211_tx_rate *rate, -+ u8 band, int len) -+{ -+ struct ieee80211_rx_status stat = { -+ .band = band, -+ }; -+ -+ if (rate->idx < 0 || !rate->count) -+ return 0; -+ -+ if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH) -+ stat.bw = RATE_INFO_BW_80; -+ else if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH) -+ stat.bw = RATE_INFO_BW_40; -+ else -+ stat.bw = RATE_INFO_BW_20; -+ -+ stat.enc_flags = 0; -+ if (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE) -+ stat.enc_flags |= RX_ENC_FLAG_SHORTPRE; -+ if (rate->flags & IEEE80211_TX_RC_SHORT_GI) -+ stat.enc_flags |= RX_ENC_FLAG_SHORT_GI; -+ -+ stat.rate_idx = rate->idx; -+ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { -+ stat.encoding = RX_ENC_VHT; -+ stat.rate_idx = ieee80211_rate_get_vht_mcs(rate); -+ stat.nss = ieee80211_rate_get_vht_nss(rate); -+ } else if (rate->flags & IEEE80211_TX_RC_MCS) { -+ stat.encoding = RX_ENC_HT; -+ } else { -+ stat.encoding = RX_ENC_LEGACY; -+ } -+ -+ return ieee80211_calc_rx_airtime(hw, &stat, len); -+} -+ -+u32 ieee80211_calc_tx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_tx_info *info, -+ int len) -+{ -+ u32 duration = 0; -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(info->status.rates); i++) { -+ struct ieee80211_tx_rate *rate = &info->status.rates[i]; -+ u32 cur_duration; -+ -+ cur_duration = ieee80211_calc_tx_airtime_rate(hw, rate, -+ info->band, len); -+ if (!cur_duration) -+ break; -+ -+ duration += cur_duration * rate->count; -+ } -+ -+ return duration; -+} -+EXPORT_SYMBOL_GPL(ieee80211_calc_tx_airtime); -+ -+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *pubsta, -+ int len) -+{ -+ struct ieee80211_supported_band *sband; -+ struct ieee80211_chanctx_conf *conf; -+ int rateidx, shift = 0; -+ bool cck, short_pream; -+ u32 basic_rates; -+ u8 band = 0; -+ u16 rate; -+ -+ len += 38; /* Ethernet header length */ -+ -+ conf = rcu_dereference(vif->chanctx_conf); -+ if (conf) { -+ band = conf->def.chan->band; -+ shift = ieee80211_chandef_get_shift(&conf->def); -+ } -+ -+ if (pubsta) { -+ struct sta_info *sta = container_of(pubsta, struct sta_info, -+ sta); -+ -+ return ieee80211_calc_tx_airtime_rate(hw, -+ &sta->tx_stats.last_rate, -+ band, len); -+ } -+ -+ if (!conf) -+ return 0; -+ -+ /* No station to get latest rate from, so calculate the worst-case -+ * duration using the lowest configured basic rate. -+ */ -+ sband = hw->wiphy->bands[band]; -+ -+ basic_rates = vif->bss_conf.basic_rates; -+ short_pream = vif->bss_conf.use_short_preamble; -+ -+ rateidx = basic_rates ? ffs(basic_rates) - 1 : 0; -+ rate = sband->bitrates[rateidx].bitrate << shift; -+ cck = sband->bitrates[rateidx].flags & IEEE80211_RATE_MANDATORY_B; -+ -+ return ieee80211_calc_legacy_rate_duration(rate, short_pream, cck, len); -+} diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c -index f0e0d9e..993ee7b 100644 +index 97ea630..272b433 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -1172,7 +1172,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) +@@ -1288,7 +1288,6 @@ static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev) sdata->vif.bss_conf.ftmr_params = NULL; __sta_info_flush(sdata, true); - ieee80211_free_keys(sdata, true); sdata->vif.bss_conf.enable_beacon = false; - sdata->vif.bss_conf.ssid_len = 0; -@@ -2318,7 +2317,7 @@ static int ieee80211_scan(struct wiphy *wiphy, + sdata->beacon_rate_set = false; +@@ -2443,7 +2442,7 @@ static int ieee80211_scan(struct wiphy *wiphy, * the frames sent while scanning on other channel will be * lost) */ @@ -1569,7 +1423,7 @@ index f0e0d9e..993ee7b 100644 (!(wiphy->features & NL80211_FEATURE_AP_SCAN) || !(req->flags & NL80211_SCAN_FLAG_AP))) return -EOPNOTSUPP; -@@ -2583,6 +2582,19 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, +@@ -2708,6 +2707,19 @@ static int ieee80211_get_tx_power(struct wiphy *wiphy, return 0; } @@ -1589,16 +1443,7 @@ index f0e0d9e..993ee7b 100644 static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, const u8 *addr) { -@@ -3450,7 +3462,7 @@ int ieee80211_attach_ack_skb(struct ieee80211_local *local, struct sk_buff *skb, - - spin_lock_irqsave(&local->ack_status_lock, spin_flags); - id = idr_alloc(&local->ack_status_frames, ack_skb, -- 1, 0x10000, GFP_ATOMIC); -+ 1, 0x2000, GFP_ATOMIC); - spin_unlock_irqrestore(&local->ack_status_lock, spin_flags); - - if (id < 0) { -@@ -4018,6 +4030,7 @@ const struct cfg80211_ops mac80211_config_ops = { +@@ -4138,6 +4150,7 @@ const struct cfg80211_ops mac80211_config_ops = { .set_wiphy_params = ieee80211_set_wiphy_params, .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, @@ -1607,236 +1452,54 @@ index f0e0d9e..993ee7b 100644 .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) diff --git a/net/mac80211/debugfs.c b/net/mac80211/debugfs.c -index c20c6a6..30876d1 100644 +index 2cd52fc..44305e7 100644 --- a/net/mac80211/debugfs.c +++ b/net/mac80211/debugfs.c -@@ -148,6 +148,87 @@ static const struct file_operations aqm_ops = { - .llseek = default_llseek, - }; - -+static ssize_t aql_txq_limit_read(struct file *file, -+ char __user *user_buf, -+ size_t count, -+ loff_t *ppos) -+{ -+ struct ieee80211_local *local = file->private_data; -+ char buf[400]; -+ int len = 0; -+ -+ len = scnprintf(buf, sizeof(buf), -+ "AC AQL limit low AQL limit high\n" -+ "VO %u %u\n" -+ "VI %u %u\n" -+ "BE %u %u\n" -+ "BK %u %u\n", -+ local->aql_txq_limit_low[IEEE80211_AC_VO], -+ local->aql_txq_limit_high[IEEE80211_AC_VO], -+ local->aql_txq_limit_low[IEEE80211_AC_VI], -+ local->aql_txq_limit_high[IEEE80211_AC_VI], -+ local->aql_txq_limit_low[IEEE80211_AC_BE], -+ local->aql_txq_limit_high[IEEE80211_AC_BE], -+ local->aql_txq_limit_low[IEEE80211_AC_BK], -+ local->aql_txq_limit_high[IEEE80211_AC_BK]); -+ return simple_read_from_buffer(user_buf, count, ppos, -+ buf, len); -+} -+ -+static ssize_t aql_txq_limit_write(struct file *file, -+ const char __user *user_buf, -+ size_t count, -+ loff_t *ppos) -+{ -+ struct ieee80211_local *local = file->private_data; -+ char buf[100]; -+ size_t len; -+ u32 ac, q_limit_low, q_limit_high, q_limit_low_old, q_limit_high_old; -+ struct sta_info *sta; -+ -+ if (count > sizeof(buf)) -+ return -EINVAL; -+ -+ if (copy_from_user(buf, user_buf, count)) -+ return -EFAULT; -+ -+ buf[sizeof(buf) - 1] = 0; -+ len = strlen(buf); -+ if (len > 0 && buf[len - 1] == '\n') -+ buf[len - 1] = 0; -+ -+ if (sscanf(buf, "%u %u %u", &ac, &q_limit_low, &q_limit_high) != 3) -+ return -EINVAL; -+ -+ if (ac >= IEEE80211_NUM_ACS) -+ return -EINVAL; -+ -+ q_limit_low_old = local->aql_txq_limit_low[ac]; -+ q_limit_high_old = local->aql_txq_limit_high[ac]; -+ -+ local->aql_txq_limit_low[ac] = q_limit_low; -+ local->aql_txq_limit_high[ac] = q_limit_high; -+ -+ mutex_lock(&local->sta_mtx); -+ list_for_each_entry(sta, &local->sta_list, list) { -+ /* If a sta has customized queue limits, keep it */ -+ if (sta->airtime[ac].aql_limit_low == q_limit_low_old && -+ sta->airtime[ac].aql_limit_high == q_limit_high_old) { -+ sta->airtime[ac].aql_limit_low = q_limit_low; -+ sta->airtime[ac].aql_limit_high = q_limit_high; -+ } -+ } -+ mutex_unlock(&local->sta_mtx); -+ return count; -+} -+ -+static const struct file_operations aql_txq_limit_ops = { -+ .write = aql_txq_limit_write, -+ .read = aql_txq_limit_read, -+ .open = simple_open, -+ .llseek = default_llseek, -+}; -+ - static ssize_t force_tx_status_read(struct file *file, - char __user *user_buf, - size_t count, -@@ -441,6 +522,10 @@ void debugfs_hw_add(struct ieee80211_local *local) - debugfs_create_u16("airtime_flags", 0600, - phyd, &local->airtime_flags); - -+ DEBUGFS_ADD(aql_txq_limit); -+ debugfs_create_u32("aql_threshold", 0600, -+ phyd, &local->aql_threshold); -+ - statsd = debugfs_create_dir("statistics", phyd); - - /* if the dir failed, don't put all the other things into the root! */ -diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c -index c8ad20c..e887d04 100644 ---- a/net/mac80211/debugfs_sta.c -+++ b/net/mac80211/debugfs_sta.c -@@ -5,7 +5,7 @@ - * Copyright 2007 Johannes Berg - * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright(c) 2016 Intel Deutschland GmbH -- * Copyright (C) 2018 - 2019 Intel Corporation -+ * Copyright (C) 2018 - 2020 Intel Corporation - */ - - #include -@@ -78,6 +78,7 @@ static const char * const sta_flag_names[] = { - FLAG(MPSP_OWNER), - FLAG(MPSP_RECIPIENT), - FLAG(PS_DELIVER), -+ FLAG(USES_ENCRYPTION), +@@ -405,6 +405,7 @@ static const char *hw_flag_names[] = { + FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID), + FLAG(AMPDU_KEYBORDER_SUPPORT), + FLAG(SUPPORTS_TX_ENCAP_OFFLOAD), ++ FLAG(SUPPORTS_RX_DECAP_OFFLOAD), #undef FLAG }; -@@ -197,7 +198,7 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf, - { - struct sta_info *sta = file->private_data; - struct ieee80211_local *local = sta->sdata->local; -- size_t bufsz = 200; -+ size_t bufsz = 400; - char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; - u64 rx_airtime = 0, tx_airtime = 0; - s64 deficit[IEEE80211_NUM_ACS]; -@@ -218,13 +219,8 @@ static ssize_t sta_airtime_read(struct file *file, char __user *userbuf, - 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]); -+ rx_airtime, tx_airtime, sta->airtime_weight, -+ deficit[0], deficit[1], deficit[2], deficit[3]); +diff --git a/net/mac80211/debugfs_sta.c b/net/mac80211/debugfs_sta.c +index 829dcad..2e4392e 100644 +--- a/net/mac80211/debugfs_sta.c ++++ b/net/mac80211/debugfs_sta.c +@@ -79,6 +79,7 @@ static const char * const sta_flag_names[] = { + FLAG(MPSP_RECIPIENT), + FLAG(PS_DELIVER), + FLAG(USES_ENCRYPTION), ++ FLAG(DECAP_OFFLOAD), + #undef FLAG + }; - rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); - kfree(buf); -@@ -250,6 +246,70 @@ static ssize_t sta_airtime_write(struct file *file, const char __user *userbuf, +diff --git a/net/mac80211/driver-ops.h b/net/mac80211/driver-ops.h +index 37dbabd..a1ef2b9 100644 +--- a/net/mac80211/driver-ops.h ++++ b/net/mac80211/driver-ops.h +@@ -1413,4 +1413,20 @@ static inline void drv_sta_set_4addr(struct ieee80211_local *local, + trace_drv_return_void(local); } - STA_OPS_RW(airtime); -+static ssize_t sta_aql_read(struct file *file, char __user *userbuf, -+ size_t count, loff_t *ppos) ++static inline void drv_sta_set_decap_offload(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, ++ bool enabled) +{ -+ struct sta_info *sta = file->private_data; -+ struct ieee80211_local *local = sta->sdata->local; -+ size_t bufsz = 400; -+ char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf; -+ u32 q_depth[IEEE80211_NUM_ACS]; -+ u32 q_limit_l[IEEE80211_NUM_ACS], q_limit_h[IEEE80211_NUM_ACS]; -+ ssize_t rv; -+ int ac; ++ sdata = get_bss_sdata(sdata); ++ if (!check_sdata_in_driver(sdata)) ++ return; + -+ if (!buf) -+ return -ENOMEM; -+ -+ for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) { -+ spin_lock_bh(&local->active_txq_lock[ac]); -+ q_limit_l[ac] = sta->airtime[ac].aql_limit_low; -+ q_limit_h[ac] = sta->airtime[ac].aql_limit_high; -+ spin_unlock_bh(&local->active_txq_lock[ac]); -+ q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending); -+ } -+ -+ p += scnprintf(p, bufsz + buf - p, -+ "Q depth: VO: %u us VI: %u us BE: %u us BK: %u us\n" -+ "Q limit[low/high]: VO: %u/%u VI: %u/%u BE: %u/%u BK: %u/%u\n", -+ q_depth[0], q_depth[1], q_depth[2], q_depth[3], -+ q_limit_l[0], q_limit_h[0], q_limit_l[1], q_limit_h[1], -+ q_limit_l[2], q_limit_h[2], q_limit_l[3], q_limit_h[3]), -+ -+ rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf); -+ kfree(buf); -+ return rv; ++ trace_drv_sta_set_decap_offload(local, sdata, sta, enabled); ++ if (local->ops->sta_set_decap_offload) ++ local->ops->sta_set_decap_offload(&local->hw, &sdata->vif, sta, ++ enabled); ++ trace_drv_return_void(local); +} + -+static ssize_t sta_aql_write(struct file *file, const char __user *userbuf, -+ size_t count, loff_t *ppos) -+{ -+ struct sta_info *sta = file->private_data; -+ u32 ac, q_limit_l, q_limit_h; -+ char _buf[100] = {}, *buf = _buf; -+ -+ if (count > sizeof(_buf)) -+ return -EINVAL; -+ -+ if (copy_from_user(buf, userbuf, count)) -+ return -EFAULT; -+ -+ buf[sizeof(_buf) - 1] = '\0'; -+ if (sscanf(buf, "limit %u %u %u", &ac, &q_limit_l, &q_limit_h) -+ != 3) -+ return -EINVAL; -+ -+ if (ac >= IEEE80211_NUM_ACS) -+ return -EINVAL; -+ -+ sta->airtime[ac].aql_limit_low = q_limit_l; -+ sta->airtime[ac].aql_limit_high = q_limit_h; -+ -+ return count; -+} -+STA_OPS_RW(aql); -+ -+ - static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf, - size_t count, loff_t *ppos) - { -@@ -978,6 +1038,10 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta) - NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) - DEBUGFS_ADD(airtime); - -+ if (wiphy_ext_feature_isset(local->hw.wiphy, -+ NL80211_EXT_FEATURE_AQL)) -+ DEBUGFS_ADD(aql); -+ - if (sizeof(sta->driver_buffered_tids) == sizeof(u32)) - debugfs_create_x32("driver_buffered_tids", 0400, - sta->debugfs_dir, + #endif /* __MAC80211_DRIVER_OPS */ diff --git a/net/mac80211/fils_aead.c b/net/mac80211/fils_aead.c index 87e34f6..744664c 100644 --- a/net/mac80211/fils_aead.c @@ -1861,21 +1524,29 @@ index 017bd7a..a6b59d7 100644 struct ieee80211_mgd_assoc_data *assoc_data); int fils_decrypt_assoc_resp(struct ieee80211_sub_if_data *sdata, diff --git a/net/mac80211/ieee80211_i.h b/net/mac80211/ieee80211_i.h -index bacedb1..f75fb7d 100644 +index da88464..d588fb5 100644 --- a/net/mac80211/ieee80211_i.h +++ b/net/mac80211/ieee80211_i.h -@@ -1142,6 +1142,10 @@ struct ieee80211_local { - u16 schedule_round[IEEE80211_NUM_ACS]; +@@ -461,7 +461,9 @@ struct ieee80211_if_managed { + unsigned long probe_timeout; + int probe_send_count; + bool nullfunc_failed; +- bool connection_loss; ++ u8 connection_loss:1, ++ driver_disconnect:1, ++ reconnect:1; - u16 airtime_flags; -+ u32 aql_txq_limit_low[IEEE80211_NUM_ACS]; -+ u32 aql_txq_limit_high[IEEE80211_NUM_ACS]; -+ u32 aql_threshold; -+ atomic_t aql_total_pending_airtime; - - const struct ieee80211_ops *ops; - -@@ -1372,6 +1376,7 @@ struct ieee80211_local { + struct cfg80211_bss *associated; + struct ieee80211_mgd_auth_data *auth_data; +@@ -855,7 +857,6 @@ enum txq_info_flags { + */ + struct txq_info { + struct fq_tin tin; +- struct fq_flow def_flow; + struct codel_vars def_cvars; + struct codel_stats cstats; + struct sk_buff_head frags; +@@ -1402,6 +1403,7 @@ struct ieee80211_local { int dynamic_ps_forced_timeout; int user_power_level; /* in dBm, for all interfaces */ @@ -1883,91 +1554,64 @@ index bacedb1..f75fb7d 100644 enum ieee80211_smps_mode smps_mode; -@@ -1782,6 +1787,9 @@ int ieee80211_tx_control_port(struct wiphy *wiphy, struct net_device *dev, - const u8 *dest, __be16 proto, bool unencrypted); - int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev, - const u8 *buf, size_t len); -+int ieee80211_skb_resize(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb, int hdrlen, int hdr_add); +diff --git a/net/mac80211/iface.c b/net/mac80211/iface.c +index 68665bc..bf17fa9 100644 +--- a/net/mac80211/iface.c ++++ b/net/mac80211/iface.c +@@ -839,7 +839,7 @@ static const struct net_device_ops ieee80211_dataif_8023_ops = { - /* HT */ - void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata, -@@ -2250,6 +2258,10 @@ const char *ieee80211_get_reason_code_string(u16 reason_code); + }; - extern const struct ethtool_ops ieee80211_ethtool_ops; +-static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype) ++static bool ieee80211_iftype_supports_hdr_offload(enum nl80211_iftype iftype) + { + switch (iftype) { + /* P2P GO and client are mapped to AP/STATION types */ +@@ -859,7 +859,7 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat + flags = sdata->vif.offload_flags; -+u32 ieee80211_calc_expected_tx_airtime(struct ieee80211_hw *hw, -+ struct ieee80211_vif *vif, -+ struct ieee80211_sta *pubsta, -+ int len); - #ifdef CPTCFG_MAC80211_NOINLINE - #define debug_noinline noinline - #else -diff --git a/net/mac80211/key.c b/net/mac80211/key.c -index 0f889b9..efc1acc 100644 ---- a/net/mac80211/key.c -+++ b/net/mac80211/key.c -@@ -6,7 +6,7 @@ - * Copyright 2007-2008 Johannes Berg - * Copyright 2013-2014 Intel Mobile Communications GmbH - * Copyright 2015-2017 Intel Deutschland GmbH -- * Copyright 2018-2019 Intel Corporation -+ * Copyright 2018-2020 Intel Corporation - */ + if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) && +- ieee80211_iftype_supports_encap_offload(sdata->vif.type)) { ++ ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { + flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED; - #include -@@ -262,22 +262,29 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key) - sta ? sta->sta.addr : bcast_addr, ret); + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) && +@@ -872,10 +872,21 @@ static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdat + flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED; + } + ++ if (ieee80211_hw_check(&local->hw, SUPPORTS_RX_DECAP_OFFLOAD) && ++ ieee80211_iftype_supports_hdr_offload(sdata->vif.type)) { ++ flags |= IEEE80211_OFFLOAD_DECAP_ENABLED; ++ ++ if (local->monitors) ++ flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; ++ } else { ++ flags &= ~IEEE80211_OFFLOAD_DECAP_ENABLED; ++ } ++ + if (sdata->vif.offload_flags == flags) + return false; + + sdata->vif.offload_flags = flags; ++ ieee80211_check_fast_rx_iface(sdata); + return true; } --int ieee80211_set_tx_key(struct ieee80211_key *key) -+static int _ieee80211_set_tx_key(struct ieee80211_key *key, bool force) - { - struct sta_info *sta = key->sta; - struct ieee80211_local *local = key->local; +@@ -893,7 +904,7 @@ static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata) + } - assert_key_lock(local); + if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) || +- !ieee80211_iftype_supports_encap_offload(bss->vif.type)) ++ !ieee80211_iftype_supports_hdr_offload(bss->vif.type)) + return; -+ set_sta_flag(sta, WLAN_STA_USES_ENCRYPTION); -+ - sta->ptk_idx = key->conf.keyidx; - -- if (!ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) -+ if (force || !ieee80211_hw_check(&local->hw, AMPDU_KEYBORDER_SUPPORT)) - clear_sta_flag(sta, WLAN_STA_BLOCK_BA); - ieee80211_check_fast_xmit(sta); - - return 0; - } - -+int ieee80211_set_tx_key(struct ieee80211_key *key) -+{ -+ return _ieee80211_set_tx_key(key, false); -+} -+ - static void ieee80211_pairwise_rekey(struct ieee80211_key *old, - struct ieee80211_key *new) - { -@@ -441,11 +448,8 @@ static int ieee80211_key_replace(struct ieee80211_sub_if_data *sdata, - if (pairwise) { - rcu_assign_pointer(sta->ptk[idx], new); - if (new && -- !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) { -- sta->ptk_idx = idx; -- clear_sta_flag(sta, WLAN_STA_BLOCK_BA); -- ieee80211_check_fast_xmit(sta); -- } -+ !(new->conf.flags & IEEE80211_KEY_FLAG_NO_AUTO_TX)) -+ _ieee80211_set_tx_key(new, true); - } else { - rcu_assign_pointer(sta->gtk[idx], new); - } + enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED; diff --git a/net/mac80211/key.h b/net/mac80211/key.h -index a84465f..cbc219d 100644 +index 00f3d1b..81d3370 100644 --- a/net/mac80211/key.h +++ b/net/mac80211/key.h -@@ -88,12 +88,12 @@ struct ieee80211_key { +@@ -89,12 +89,12 @@ struct ieee80211_key { * Management frames. */ u8 rx_pn[IEEE80211_NUM_TIDS + 1][IEEE80211_CCMP_PN_LEN]; @@ -1983,10 +1627,10 @@ index a84465f..cbc219d 100644 u32 icverrors; /* dot11RSNAStatsCMACICVErrors */ } aes_cmac; diff --git a/net/mac80211/main.c b/net/mac80211/main.c -index 3028e1f..71dada6 100644 +index bca1a02..44076fb 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c -@@ -93,7 +93,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) +@@ -96,7 +96,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) struct ieee80211_sub_if_data *sdata; struct cfg80211_chan_def chandef = {}; u32 changed = 0; @@ -1995,7 +1639,7 @@ index 3028e1f..71dada6 100644 u32 offchannel_flag; offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL; -@@ -150,6 +150,12 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) +@@ -157,6 +157,12 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local) } rcu_read_unlock(); @@ -2008,7 +1652,7 @@ index 3028e1f..71dada6 100644 if (local->hw.conf.power_level != power) { changed |= IEEE80211_CONF_CHANGE_POWER; local->hw.conf.power_level = power; -@@ -314,7 +320,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) +@@ -321,7 +327,7 @@ void ieee80211_restart_hw(struct ieee80211_hw *hw) } EXPORT_SYMBOL(ieee80211_restart_hw); @@ -2017,7 +1661,7 @@ index 3028e1f..71dada6 100644 static int ieee80211_ifa_changed(struct notifier_block *nb, unsigned long data, void *arg) { -@@ -373,7 +379,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, +@@ -380,7 +386,7 @@ static int ieee80211_ifa_changed(struct notifier_block *nb, } #endif @@ -2026,7 +1670,7 @@ index 3028e1f..71dada6 100644 static int ieee80211_ifa6_changed(struct notifier_block *nb, unsigned long data, void *arg) { -@@ -571,7 +577,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, +@@ -591,7 +597,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, NL80211_FEATURE_MAC_ON_CREATE | NL80211_FEATURE_USERSPACE_MPM | NL80211_FEATURE_FULL_AP_CLIENT_STATE; @@ -2035,30 +1679,15 @@ index 3028e1f..71dada6 100644 wiphy_ext_feature_set(wiphy, NL80211_EXT_FEATURE_FILS_STA); #endif wiphy_ext_feature_set(wiphy, -@@ -639,6 +645,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, +@@ -665,6 +671,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, IEEE80211_RADIOTAP_MCS_HAVE_BW; local->hw.radiotap_vht_details = IEEE80211_RADIOTAP_VHT_KNOWN_GI | IEEE80211_RADIOTAP_VHT_KNOWN_BANDWIDTH; -+ local->user_antenna_gain = 3; ++ local->user_antenna_gain = 0; local->hw.uapsd_queues = IEEE80211_DEFAULT_UAPSD_QUEUES; local->hw.uapsd_max_sp_len = IEEE80211_DEFAULT_MAX_SP_LEN; local->hw.max_mtu = IEEE80211_MAX_DATA_LEN; -@@ -669,8 +676,14 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, - for (i = 0; i < IEEE80211_NUM_ACS; i++) { - INIT_LIST_HEAD(&local->active_txqs[i]); - spin_lock_init(&local->active_txq_lock[i]); -+ local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L; -+ local->aql_txq_limit_high[i] = -+ IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H; - } -+ - local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX; -+ local->aql_threshold = IEEE80211_AQL_THRESHOLD; -+ atomic_set(&local->aql_total_pending_airtime, 0); - - INIT_LIST_HEAD(&local->chanctx_list); - mutex_init(&local->chanctx_mtx); -@@ -1264,14 +1277,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) +@@ -1301,14 +1308,14 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) rtnl_unlock(); @@ -2075,7 +1704,7 @@ index 3028e1f..71dada6 100644 local->ifa6_notifier.notifier_call = ieee80211_ifa6_changed; result = register_inet6addr_notifier(&local->ifa6_notifier); if (result) -@@ -1280,13 +1293,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) +@@ -1317,13 +1324,13 @@ int ieee80211_register_hw(struct ieee80211_hw *hw) return 0; @@ -2091,8 +1720,8 @@ index 3028e1f..71dada6 100644 +#if defined(__disabled__CONFIG_INET) || defined(__disabled__CONFIG_IPV6) fail_ifa: #endif - rtnl_lock(); -@@ -1314,10 +1327,10 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) + wiphy_unregister(local->hw.wiphy); +@@ -1351,10 +1358,10 @@ void ieee80211_unregister_hw(struct ieee80211_hw *hw) tasklet_kill(&local->tx_pending_tasklet); tasklet_kill(&local->tasklet); @@ -2105,184 +1734,1610 @@ index 3028e1f..71dada6 100644 unregister_inet6addr_notifier(&local->ifa6_notifier); #endif -diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c -index ceda2e9..9a0dc3b 100644 ---- a/net/mac80211/rc80211_minstrel.c -+++ b/net/mac80211/rc80211_minstrel.c -@@ -70,7 +70,7 @@ rix_to_ndx(struct minstrel_sta_info *mi, int rix) - } +diff --git a/net/mac80211/mlme.c b/net/mac80211/mlme.c +index 6adfcb9..1c9cc65 100644 +--- a/net/mac80211/mlme.c ++++ b/net/mac80211/mlme.c +@@ -2720,7 +2720,7 @@ EXPORT_SYMBOL(ieee80211_ap_probereq_get); - /* return current EMWA throughput */ --int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) -+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg) + static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, + const u8 *buf, size_t len, bool tx, +- u16 reason) ++ u16 reason, bool reconnect) { - int usecs; + struct ieee80211_event event = { + .type = MLME_EVENT, +@@ -2729,7 +2729,7 @@ static void ieee80211_report_disconnect(struct ieee80211_sub_if_data *sdata, + }; -@@ -79,13 +79,13 @@ int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma) - usecs = 1000000; - - /* reset thr. below 10% success */ -- if (mr->stats.prob_ewma < MINSTREL_FRAC(10, 100)) -+ if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100)) - return 0; - -- if (prob_ewma > MINSTREL_FRAC(90, 100)) -+ if (prob_avg > MINSTREL_FRAC(90, 100)) - return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); + if (tx) +- cfg80211_tx_mlme_mgmt(sdata->dev, buf, len); ++ cfg80211_tx_mlme_mgmt(sdata->dev, buf, len, reconnect); else -- return MINSTREL_TRUNC(100000 * (prob_ewma / usecs)); -+ return MINSTREL_TRUNC(100000 * (prob_avg / usecs)); + cfg80211_rx_mlme_mgmt(sdata->dev, buf, len); + +@@ -2751,13 +2751,18 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) + + tx = !sdata->csa_block_tx; + +- /* AP is probably out of range (or not reachable for another reason) so +- * remove the bss struct for that AP. +- */ +- cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); ++ if (!ifmgd->driver_disconnect) { ++ /* ++ * AP is probably out of range (or not reachable for another ++ * reason) so remove the bss struct for that AP. ++ */ ++ cfg80211_unlink_bss(local->hw.wiphy, ifmgd->associated); ++ } + + ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH, +- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, ++ ifmgd->driver_disconnect ? ++ WLAN_REASON_DEAUTH_LEAVING : ++ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, + tx, frame_buf); + mutex_lock(&local->mtx); + sdata->vif.csa_active = false; +@@ -2770,7 +2775,9 @@ static void __ieee80211_disconnect(struct ieee80211_sub_if_data *sdata) + mutex_unlock(&local->mtx); + + ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), tx, +- WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY); ++ WLAN_REASON_DISASSOC_DUE_TO_INACTIVITY, ++ ifmgd->reconnect); ++ ifmgd->reconnect = false; + + sdata_unlock(sdata); } - - /* find & sort topmost throughput rates */ -@@ -98,8 +98,8 @@ minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) - - for (j = MAX_THR_RATES; j > 0; --j) { - tmp_mrs = &mi->r[tp_list[j - 1]].stats; -- if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_ewma) <= -- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_ewma)) -+ if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <= -+ minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg)) - break; +@@ -2789,6 +2796,13 @@ static void ieee80211_beacon_connection_loss_work(struct work_struct *work) + sdata_info(sdata, "Connection to AP %pM lost\n", + ifmgd->bssid); + __ieee80211_disconnect(sdata); ++ ifmgd->connection_loss = false; ++ } else if (ifmgd->driver_disconnect) { ++ sdata_info(sdata, ++ "Driver requested disconnection from AP %pM\n", ++ ifmgd->bssid); ++ __ieee80211_disconnect(sdata); ++ ifmgd->driver_disconnect = false; + } else { + ieee80211_mgd_probe_ap(sdata, true); } - -@@ -157,20 +157,24 @@ minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi) - * Recalculate statistics and counters of a given rate - */ - void --minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs) -+minstrel_calc_rate_stats(struct minstrel_priv *mp, -+ struct minstrel_rate_stats *mrs) - { - unsigned int cur_prob; - - if (unlikely(mrs->attempts > 0)) { - mrs->sample_skipped = 0; - cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); -- if (unlikely(!mrs->att_hist)) { -- mrs->prob_ewma = cur_prob; -+ if (mp->new_avg) { -+ minstrel_filter_avg_add(&mrs->prob_avg, -+ &mrs->prob_avg_1, cur_prob); -+ } else if (unlikely(!mrs->att_hist)) { -+ mrs->prob_avg = cur_prob; - } else { - /*update exponential weighted moving avarage */ -- mrs->prob_ewma = minstrel_ewma(mrs->prob_ewma, -- cur_prob, -- EWMA_LEVEL); -+ mrs->prob_avg = minstrel_ewma(mrs->prob_avg, -+ cur_prob, -+ EWMA_LEVEL); - } - mrs->att_hist += mrs->attempts; - mrs->succ_hist += mrs->success; -@@ -200,12 +204,12 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) - struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; - - /* Update statistics of success probability per rate */ -- minstrel_calc_rate_stats(mrs); -+ minstrel_calc_rate_stats(mp, mrs); - - /* Sample less often below the 10% chance of success. - * Sample less often above the 95% chance of success. */ -- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) || -- mrs->prob_ewma < MINSTREL_FRAC(10, 100)) { -+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || -+ mrs->prob_avg < MINSTREL_FRAC(10, 100)) { - mr->adjusted_retry_count = mrs->retry_count >> 1; - if (mr->adjusted_retry_count > 2) - mr->adjusted_retry_count = 2; -@@ -225,14 +229,14 @@ minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) - * choose the maximum throughput rate as max_prob_rate - * (2) if all success probabilities < 95%, the rate with - * highest success probability is chosen as max_prob_rate */ -- if (mrs->prob_ewma >= MINSTREL_FRAC(95, 100)) { -- tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_ewma); -+ if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) { -+ tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg); - tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], -- tmp_mrs->prob_ewma); -+ tmp_mrs->prob_avg); - if (tmp_cur_tp >= tmp_prob_tp) - tmp_prob_rate = i; - } else { -- if (mrs->prob_ewma >= tmp_mrs->prob_ewma) -+ if (mrs->prob_avg >= tmp_mrs->prob_avg) - tmp_prob_rate = i; - } - } -@@ -290,7 +294,7 @@ minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, - mi->sample_deferred--; - - if (time_after(jiffies, mi->last_stats_update + -- (mp->update_interval * HZ) / 1000)) -+ mp->update_interval / (mp->new_avg ? 2 : 1))) - minstrel_update_stats(mp, mi); +@@ -2827,6 +2841,21 @@ void ieee80211_connection_loss(struct ieee80211_vif *vif) } + EXPORT_SYMBOL(ieee80211_connection_loss); -@@ -422,7 +426,7 @@ minstrel_get_rate(void *priv, struct ieee80211_sta *sta, - * has a probability of >95%, we shouldn't be attempting - * to use it, as this only wastes precious airtime */ - if (!mrr_capable && -- (mi->r[ndx].stats.prob_ewma > MINSTREL_FRAC(95, 100))) -+ (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100))) ++void ieee80211_disconnect(struct ieee80211_vif *vif, bool reconnect) ++{ ++ struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif); ++ struct ieee80211_hw *hw = &sdata->local->hw; ++ ++ trace_api_disconnect(sdata, reconnect); ++ ++ if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION)) ++ return; ++ ++ sdata->u.mgd.driver_disconnect = true; ++ sdata->u.mgd.reconnect = reconnect; ++ ieee80211_queue_work(hw, &sdata->u.mgd.beacon_connection_loss_work); ++} ++EXPORT_SYMBOL(ieee80211_disconnect); + + static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata, + bool assoc) +@@ -3130,7 +3159,7 @@ static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata, + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + + ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, +- reason_code); ++ reason_code, false); return; + } - mi->prev_sample = true; -@@ -573,7 +577,7 @@ static u32 minstrel_get_expected_throughput(void *priv_sta) - * computing cur_tp - */ - tmp_mrs = &mi->r[idx].stats; -- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_ewma) * 10; -+ tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10; - tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; +@@ -3179,7 +3208,8 @@ static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata, - return tmp_cur_tp; + ieee80211_set_disassoc(sdata, 0, 0, false, NULL); + +- ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code); ++ ieee80211_report_disconnect(sdata, (u8 *)mgmt, len, false, reason_code, ++ false); + } + + static void ieee80211_get_rates(struct ieee80211_supported_band *sband, +@@ -4199,7 +4229,8 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata, + true, deauth_buf); + ieee80211_report_disconnect(sdata, deauth_buf, + sizeof(deauth_buf), true, +- WLAN_REASON_DEAUTH_LEAVING); ++ WLAN_REASON_DEAUTH_LEAVING, ++ false); + return; + } + +@@ -4344,7 +4375,7 @@ static void ieee80211_sta_connection_lost(struct ieee80211_sub_if_data *sdata, + tx, frame_buf); + + ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, +- reason); ++ reason, false); + } + + static int ieee80211_auth(struct ieee80211_sub_if_data *sdata) +@@ -4716,7 +4747,8 @@ void ieee80211_mgd_quiesce(struct ieee80211_sub_if_data *sdata) + if (ifmgd->auth_data) + ieee80211_destroy_auth_data(sdata, false); + cfg80211_tx_mlme_mgmt(sdata->dev, frame_buf, +- IEEE80211_DEAUTH_FRAME_LEN); ++ IEEE80211_DEAUTH_FRAME_LEN, ++ false); + } + + /* This is a bit of a hack - we should find a better and more generic +@@ -5430,7 +5462,8 @@ int ieee80211_mgd_auth(struct ieee80211_sub_if_data *sdata, + + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, +- WLAN_REASON_UNSPECIFIED); ++ WLAN_REASON_UNSPECIFIED, ++ false); + } + + sdata_info(sdata, "authenticate with %pM\n", req->bss->bssid); +@@ -5502,7 +5535,8 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata, + + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, +- WLAN_REASON_UNSPECIFIED); ++ WLAN_REASON_UNSPECIFIED, ++ false); + } + + if (ifmgd->auth_data && !ifmgd->auth_data->done) { +@@ -5801,7 +5835,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + ieee80211_destroy_auth_data(sdata, false); + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, +- req->reason_code); ++ req->reason_code, false); + + return 0; + } +@@ -5821,7 +5855,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + ieee80211_destroy_assoc_data(sdata, false, true); + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, +- req->reason_code); ++ req->reason_code, false); + return 0; + } + +@@ -5836,7 +5870,7 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata, + req->reason_code, tx, frame_buf); + ieee80211_report_disconnect(sdata, frame_buf, + sizeof(frame_buf), true, +- req->reason_code); ++ req->reason_code, false); + return 0; + } + +@@ -5869,7 +5903,7 @@ int ieee80211_mgd_disassoc(struct ieee80211_sub_if_data *sdata, + frame_buf); + + ieee80211_report_disconnect(sdata, frame_buf, sizeof(frame_buf), true, +- req->reason_code); ++ req->reason_code, false); + + return 0; + } +diff --git a/net/mac80211/rc80211_minstrel.c b/net/mac80211/rc80211_minstrel.c +deleted file mode 100644 +index 4e96d6d..0000000 +--- a/net/mac80211/rc80211_minstrel.c ++++ /dev/null +@@ -1,574 +0,0 @@ +-/* +- * Copyright (C) 2008 Felix Fietkau +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- * Based on minstrel.c: +- * Copyright (C) 2005-2007 Derek Smithies +- * Sponsored by Indranet Technologies Ltd +- * +- * Based on sample.c: +- * Copyright (c) 2005 John Bicket +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer, +- * without modification. +- * 2. Redistributions in binary form must reproduce at minimum a disclaimer +- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any +- * redistribution must be conditioned upon including a substantially +- * similar Disclaimer requirement for further binary redistribution. +- * 3. Neither the names of the above-listed copyright holders nor the names +- * of any contributors may be used to endorse or promote products derived +- * from this software without specific prior written permission. +- * +- * Alternatively, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") version 2 as published by the Free +- * Software Foundation. +- * +- * NO WARRANTY +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY +- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, +- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +- * THE POSSIBILITY OF SUCH DAMAGES. +- */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "rate.h" +-#include "rc80211_minstrel.h" +- +-#define SAMPLE_TBL(_mi, _idx, _col) \ +- _mi->sample_table[(_idx * SAMPLE_COLUMNS) + _col] +- +-/* convert mac80211 rate index to local array index */ +-static inline int +-rix_to_ndx(struct minstrel_sta_info *mi, int rix) +-{ +- int i = rix; +- for (i = rix; i >= 0; i--) +- if (mi->r[i].rix == rix) +- break; +- return i; +-} +- +-/* return current EMWA throughput */ +-int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg) +-{ +- int usecs; +- +- usecs = mr->perfect_tx_time; +- if (!usecs) +- usecs = 1000000; +- +- /* reset thr. below 10% success */ +- if (mr->stats.prob_avg < MINSTREL_FRAC(10, 100)) +- return 0; +- +- if (prob_avg > MINSTREL_FRAC(90, 100)) +- return MINSTREL_TRUNC(100000 * (MINSTREL_FRAC(90, 100) / usecs)); +- else +- return MINSTREL_TRUNC(100000 * (prob_avg / usecs)); +-} +- +-/* find & sort topmost throughput rates */ +-static inline void +-minstrel_sort_best_tp_rates(struct minstrel_sta_info *mi, int i, u8 *tp_list) +-{ +- int j; +- struct minstrel_rate_stats *tmp_mrs; +- struct minstrel_rate_stats *cur_mrs = &mi->r[i].stats; +- +- for (j = MAX_THR_RATES; j > 0; --j) { +- tmp_mrs = &mi->r[tp_list[j - 1]].stats; +- if (minstrel_get_tp_avg(&mi->r[i], cur_mrs->prob_avg) <= +- minstrel_get_tp_avg(&mi->r[tp_list[j - 1]], tmp_mrs->prob_avg)) +- break; +- } +- +- if (j < MAX_THR_RATES - 1) +- memmove(&tp_list[j + 1], &tp_list[j], MAX_THR_RATES - (j + 1)); +- if (j < MAX_THR_RATES) +- tp_list[j] = i; +-} +- +-static void +-minstrel_set_rate(struct minstrel_sta_info *mi, struct ieee80211_sta_rates *ratetbl, +- int offset, int idx) +-{ +- struct minstrel_rate *r = &mi->r[idx]; +- +- ratetbl->rate[offset].idx = r->rix; +- ratetbl->rate[offset].count = r->adjusted_retry_count; +- ratetbl->rate[offset].count_cts = r->retry_count_cts; +- ratetbl->rate[offset].count_rts = r->stats.retry_count_rtscts; +-} +- +-static void +-minstrel_update_rates(struct minstrel_priv *mp, struct minstrel_sta_info *mi) +-{ +- struct ieee80211_sta_rates *ratetbl; +- int i = 0; +- +- ratetbl = kzalloc(sizeof(*ratetbl), GFP_ATOMIC); +- if (!ratetbl) +- return; +- +- /* Start with max_tp_rate */ +- minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[0]); +- +- if (mp->hw->max_rates >= 3) { +- /* At least 3 tx rates supported, use max_tp_rate2 next */ +- minstrel_set_rate(mi, ratetbl, i++, mi->max_tp_rate[1]); +- } +- +- if (mp->hw->max_rates >= 2) { +- /* At least 2 tx rates supported, use max_prob_rate next */ +- minstrel_set_rate(mi, ratetbl, i++, mi->max_prob_rate); +- } +- +- /* Use lowest rate last */ +- ratetbl->rate[i].idx = mi->lowest_rix; +- ratetbl->rate[i].count = mp->max_retry; +- ratetbl->rate[i].count_cts = mp->max_retry; +- ratetbl->rate[i].count_rts = mp->max_retry; +- +- rate_control_set_rates(mp->hw, mi->sta, ratetbl); +-} +- +-/* +-* Recalculate statistics and counters of a given rate +-*/ +-void +-minstrel_calc_rate_stats(struct minstrel_priv *mp, +- struct minstrel_rate_stats *mrs) +-{ +- unsigned int cur_prob; +- +- if (unlikely(mrs->attempts > 0)) { +- mrs->sample_skipped = 0; +- cur_prob = MINSTREL_FRAC(mrs->success, mrs->attempts); +- if (mp->new_avg) { +- minstrel_filter_avg_add(&mrs->prob_avg, +- &mrs->prob_avg_1, cur_prob); +- } else if (unlikely(!mrs->att_hist)) { +- mrs->prob_avg = cur_prob; +- } else { +- /*update exponential weighted moving avarage */ +- mrs->prob_avg = minstrel_ewma(mrs->prob_avg, +- cur_prob, +- EWMA_LEVEL); +- } +- mrs->att_hist += mrs->attempts; +- mrs->succ_hist += mrs->success; +- } else { +- mrs->sample_skipped++; +- } +- +- mrs->last_success = mrs->success; +- mrs->last_attempts = mrs->attempts; +- mrs->success = 0; +- mrs->attempts = 0; +-} +- +-static void +-minstrel_update_stats(struct minstrel_priv *mp, struct minstrel_sta_info *mi) +-{ +- u8 tmp_tp_rate[MAX_THR_RATES]; +- u8 tmp_prob_rate = 0; +- int i, tmp_cur_tp, tmp_prob_tp; +- +- for (i = 0; i < MAX_THR_RATES; i++) +- tmp_tp_rate[i] = 0; +- +- for (i = 0; i < mi->n_rates; i++) { +- struct minstrel_rate *mr = &mi->r[i]; +- struct minstrel_rate_stats *mrs = &mi->r[i].stats; +- struct minstrel_rate_stats *tmp_mrs = &mi->r[tmp_prob_rate].stats; +- +- /* Update statistics of success probability per rate */ +- minstrel_calc_rate_stats(mp, mrs); +- +- /* Sample less often below the 10% chance of success. +- * Sample less often above the 95% chance of success. */ +- if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || +- mrs->prob_avg < MINSTREL_FRAC(10, 100)) { +- mr->adjusted_retry_count = mrs->retry_count >> 1; +- if (mr->adjusted_retry_count > 2) +- mr->adjusted_retry_count = 2; +- mr->sample_limit = 4; +- } else { +- mr->sample_limit = -1; +- mr->adjusted_retry_count = mrs->retry_count; +- } +- if (!mr->adjusted_retry_count) +- mr->adjusted_retry_count = 2; +- +- minstrel_sort_best_tp_rates(mi, i, tmp_tp_rate); +- +- /* To determine the most robust rate (max_prob_rate) used at +- * 3rd mmr stage we distinct between two cases: +- * (1) if any success probabilitiy >= 95%, out of those rates +- * choose the maximum throughput rate as max_prob_rate +- * (2) if all success probabilities < 95%, the rate with +- * highest success probability is chosen as max_prob_rate */ +- if (mrs->prob_avg >= MINSTREL_FRAC(95, 100)) { +- tmp_cur_tp = minstrel_get_tp_avg(mr, mrs->prob_avg); +- tmp_prob_tp = minstrel_get_tp_avg(&mi->r[tmp_prob_rate], +- tmp_mrs->prob_avg); +- if (tmp_cur_tp >= tmp_prob_tp) +- tmp_prob_rate = i; +- } else { +- if (mrs->prob_avg >= tmp_mrs->prob_avg) +- tmp_prob_rate = i; +- } +- } +- +- /* Assign the new rate set */ +- memcpy(mi->max_tp_rate, tmp_tp_rate, sizeof(mi->max_tp_rate)); +- mi->max_prob_rate = tmp_prob_rate; +- +-#ifdef CPTCFG_MAC80211_DEBUGFS +- /* use fixed index if set */ +- if (mp->fixed_rate_idx != -1) { +- mi->max_tp_rate[0] = mp->fixed_rate_idx; +- mi->max_tp_rate[1] = mp->fixed_rate_idx; +- mi->max_prob_rate = mp->fixed_rate_idx; +- } +-#endif +- +- /* Reset update timer */ +- mi->last_stats_update = jiffies; +- +- minstrel_update_rates(mp, mi); +-} +- +-static void +-minstrel_tx_status(void *priv, struct ieee80211_supported_band *sband, +- void *priv_sta, struct ieee80211_tx_status *st) +-{ +- struct ieee80211_tx_info *info = st->info; +- struct minstrel_priv *mp = priv; +- struct minstrel_sta_info *mi = priv_sta; +- struct ieee80211_tx_rate *ar = info->status.rates; +- int i, ndx; +- int success; +- +- success = !!(info->flags & IEEE80211_TX_STAT_ACK); +- +- for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) { +- if (ar[i].idx < 0 || !ar[i].count) +- break; +- +- ndx = rix_to_ndx(mi, ar[i].idx); +- if (ndx < 0) +- continue; +- +- mi->r[ndx].stats.attempts += ar[i].count; +- +- if ((i != IEEE80211_TX_MAX_RATES - 1) && (ar[i + 1].idx < 0)) +- mi->r[ndx].stats.success += success; +- } +- +- if (time_after(jiffies, mi->last_stats_update + +- mp->update_interval / (mp->new_avg ? 2 : 1))) +- minstrel_update_stats(mp, mi); +-} +- +- +-static inline unsigned int +-minstrel_get_retry_count(struct minstrel_rate *mr, +- struct ieee80211_tx_info *info) +-{ +- u8 retry = mr->adjusted_retry_count; +- +- if (info->control.use_rts) +- retry = max_t(u8, 2, min(mr->stats.retry_count_rtscts, retry)); +- else if (info->control.use_cts_prot) +- retry = max_t(u8, 2, min(mr->retry_count_cts, retry)); +- return retry; +-} +- +- +-static int +-minstrel_get_next_sample(struct minstrel_sta_info *mi) +-{ +- unsigned int sample_ndx; +- sample_ndx = SAMPLE_TBL(mi, mi->sample_row, mi->sample_column); +- mi->sample_row++; +- if ((int) mi->sample_row >= mi->n_rates) { +- mi->sample_row = 0; +- mi->sample_column++; +- if (mi->sample_column >= SAMPLE_COLUMNS) +- mi->sample_column = 0; +- } +- return sample_ndx; +-} +- +-static void +-minstrel_get_rate(void *priv, struct ieee80211_sta *sta, +- void *priv_sta, struct ieee80211_tx_rate_control *txrc) +-{ +- struct sk_buff *skb = txrc->skb; +- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); +- struct minstrel_sta_info *mi = priv_sta; +- struct minstrel_priv *mp = priv; +- struct ieee80211_tx_rate *rate = &info->control.rates[0]; +- struct minstrel_rate *msr, *mr; +- unsigned int ndx; +- bool mrr_capable; +- bool prev_sample; +- int delta; +- int sampling_ratio; +- +- /* check multi-rate-retry capabilities & adjust lookaround_rate */ +- mrr_capable = mp->has_mrr && +- !txrc->rts && +- !txrc->bss_conf->use_cts_prot; +- if (mrr_capable) +- sampling_ratio = mp->lookaround_rate_mrr; +- else +- sampling_ratio = mp->lookaround_rate; +- +- /* increase sum packet counter */ +- mi->total_packets++; +- +-#ifdef CPTCFG_MAC80211_DEBUGFS +- if (mp->fixed_rate_idx != -1) +- return; +-#endif +- +- /* Don't use EAPOL frames for sampling on non-mrr hw */ +- if (mp->hw->max_rates == 1 && +- (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) +- return; +- +- delta = (mi->total_packets * sampling_ratio / 100) - +- mi->sample_packets; +- +- /* delta < 0: no sampling required */ +- prev_sample = mi->prev_sample; +- mi->prev_sample = false; +- if (delta < 0 || (!mrr_capable && prev_sample)) +- return; +- +- if (mi->total_packets >= 10000) { +- mi->sample_packets = 0; +- mi->total_packets = 0; +- } else if (delta > mi->n_rates * 2) { +- /* With multi-rate retry, not every planned sample +- * attempt actually gets used, due to the way the retry +- * chain is set up - [max_tp,sample,prob,lowest] for +- * sample_rate < max_tp. +- * +- * If there's too much sampling backlog and the link +- * starts getting worse, minstrel would start bursting +- * out lots of sampling frames, which would result +- * in a large throughput loss. */ +- mi->sample_packets += (delta - mi->n_rates * 2); +- } +- +- /* get next random rate sample */ +- ndx = minstrel_get_next_sample(mi); +- msr = &mi->r[ndx]; +- mr = &mi->r[mi->max_tp_rate[0]]; +- +- /* Decide if direct ( 1st mrr stage) or indirect (2nd mrr stage) +- * rate sampling method should be used. +- * Respect such rates that are not sampled for 20 interations. +- */ +- if (msr->perfect_tx_time < mr->perfect_tx_time || +- msr->stats.sample_skipped >= 20) { +- if (!msr->sample_limit) +- return; +- +- mi->sample_packets++; +- if (msr->sample_limit > 0) +- msr->sample_limit--; +- } +- +- /* If we're not using MRR and the sampling rate already +- * has a probability of >95%, we shouldn't be attempting +- * to use it, as this only wastes precious airtime */ +- if (!mrr_capable && +- (mi->r[ndx].stats.prob_avg > MINSTREL_FRAC(95, 100))) +- return; +- +- mi->prev_sample = true; +- +- rate->idx = mi->r[ndx].rix; +- rate->count = minstrel_get_retry_count(&mi->r[ndx], info); +- info->flags |= IEEE80211_TX_CTL_RATE_CTRL_PROBE; +-} +- +- +-static void +-calc_rate_durations(enum nl80211_band band, +- struct minstrel_rate *d, +- struct ieee80211_rate *rate, +- struct cfg80211_chan_def *chandef) +-{ +- int erp = !!(rate->flags & IEEE80211_RATE_ERP_G); +- int shift = ieee80211_chandef_get_shift(chandef); +- +- d->perfect_tx_time = ieee80211_frame_duration(band, 1200, +- DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, +- shift); +- d->ack_time = ieee80211_frame_duration(band, 10, +- DIV_ROUND_UP(rate->bitrate, 1 << shift), erp, 1, +- shift); +-} +- +-static void +-init_sample_table(struct minstrel_sta_info *mi) +-{ +- unsigned int i, col, new_idx; +- u8 rnd[8]; +- +- mi->sample_column = 0; +- mi->sample_row = 0; +- memset(mi->sample_table, 0xff, SAMPLE_COLUMNS * mi->n_rates); +- +- for (col = 0; col < SAMPLE_COLUMNS; col++) { +- prandom_bytes(rnd, sizeof(rnd)); +- for (i = 0; i < mi->n_rates; i++) { +- new_idx = (i + rnd[i & 7]) % mi->n_rates; +- while (SAMPLE_TBL(mi, new_idx, col) != 0xff) +- new_idx = (new_idx + 1) % mi->n_rates; +- +- SAMPLE_TBL(mi, new_idx, col) = i; +- } +- } +-} +- +-static void +-minstrel_rate_init(void *priv, struct ieee80211_supported_band *sband, +- struct cfg80211_chan_def *chandef, +- struct ieee80211_sta *sta, void *priv_sta) +-{ +- struct minstrel_sta_info *mi = priv_sta; +- struct minstrel_priv *mp = priv; +- struct ieee80211_rate *ctl_rate; +- unsigned int i, n = 0; +- unsigned int t_slot = 9; /* FIXME: get real slot time */ +- u32 rate_flags; +- +- mi->sta = sta; +- mi->lowest_rix = rate_lowest_index(sband, sta); +- ctl_rate = &sband->bitrates[mi->lowest_rix]; +- mi->sp_ack_dur = ieee80211_frame_duration(sband->band, 10, +- ctl_rate->bitrate, +- !!(ctl_rate->flags & IEEE80211_RATE_ERP_G), 1, +- ieee80211_chandef_get_shift(chandef)); +- +- rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); +- memset(mi->max_tp_rate, 0, sizeof(mi->max_tp_rate)); +- mi->max_prob_rate = 0; +- +- for (i = 0; i < sband->n_bitrates; i++) { +- struct minstrel_rate *mr = &mi->r[n]; +- struct minstrel_rate_stats *mrs = &mi->r[n].stats; +- unsigned int tx_time = 0, tx_time_cts = 0, tx_time_rtscts = 0; +- unsigned int tx_time_single; +- unsigned int cw = mp->cw_min; +- int shift; +- +- if (!rate_supported(sta, sband->band, i)) +- continue; +- if ((rate_flags & sband->bitrates[i].flags) != rate_flags) +- continue; +- +- n++; +- memset(mr, 0, sizeof(*mr)); +- memset(mrs, 0, sizeof(*mrs)); +- +- mr->rix = i; +- shift = ieee80211_chandef_get_shift(chandef); +- mr->bitrate = DIV_ROUND_UP(sband->bitrates[i].bitrate, +- (1 << shift) * 5); +- calc_rate_durations(sband->band, mr, &sband->bitrates[i], +- chandef); +- +- /* calculate maximum number of retransmissions before +- * fallback (based on maximum segment size) */ +- mr->sample_limit = -1; +- mrs->retry_count = 1; +- mr->retry_count_cts = 1; +- mrs->retry_count_rtscts = 1; +- tx_time = mr->perfect_tx_time + mi->sp_ack_dur; +- do { +- /* add one retransmission */ +- tx_time_single = mr->ack_time + mr->perfect_tx_time; +- +- /* contention window */ +- tx_time_single += (t_slot * cw) >> 1; +- cw = min((cw << 1) | 1, mp->cw_max); +- +- tx_time += tx_time_single; +- tx_time_cts += tx_time_single + mi->sp_ack_dur; +- tx_time_rtscts += tx_time_single + 2 * mi->sp_ack_dur; +- if ((tx_time_cts < mp->segment_size) && +- (mr->retry_count_cts < mp->max_retry)) +- mr->retry_count_cts++; +- if ((tx_time_rtscts < mp->segment_size) && +- (mrs->retry_count_rtscts < mp->max_retry)) +- mrs->retry_count_rtscts++; +- } while ((tx_time < mp->segment_size) && +- (++mr->stats.retry_count < mp->max_retry)); +- mr->adjusted_retry_count = mrs->retry_count; +- if (!(sband->bitrates[i].flags & IEEE80211_RATE_ERP_G)) +- mr->retry_count_cts = mrs->retry_count; +- } +- +- for (i = n; i < sband->n_bitrates; i++) { +- struct minstrel_rate *mr = &mi->r[i]; +- mr->rix = -1; +- } +- +- mi->n_rates = n; +- mi->last_stats_update = jiffies; +- +- init_sample_table(mi); +- minstrel_update_rates(mp, mi); +-} +- +-static u32 minstrel_get_expected_throughput(void *priv_sta) +-{ +- struct minstrel_sta_info *mi = priv_sta; +- struct minstrel_rate_stats *tmp_mrs; +- int idx = mi->max_tp_rate[0]; +- int tmp_cur_tp; +- +- /* convert pkt per sec in kbps (1200 is the average pkt size used for +- * computing cur_tp +- */ +- tmp_mrs = &mi->r[idx].stats; +- tmp_cur_tp = minstrel_get_tp_avg(&mi->r[idx], tmp_mrs->prob_avg) * 10; +- tmp_cur_tp = tmp_cur_tp * 1200 * 8 / 1024; +- +- return tmp_cur_tp; +-} +- +-const struct rate_control_ops mac80211_minstrel = { +- .tx_status_ext = minstrel_tx_status, +- .get_rate = minstrel_get_rate, +- .rate_init = minstrel_rate_init, +- .get_expected_throughput = minstrel_get_expected_throughput, +-}; diff --git a/net/mac80211/rc80211_minstrel.h b/net/mac80211/rc80211_minstrel.h -index 9b6c433..f3fbea2 100644 +deleted file mode 100644 +index 302d090..0000000 --- a/net/mac80211/rc80211_minstrel.h -+++ b/net/mac80211/rc80211_minstrel.h -@@ -19,6 +19,21 @@ - #define MAX_THR_RATES 4 ++++ /dev/null +@@ -1,184 +0,0 @@ +-/* SPDX-License-Identifier: GPL-2.0-only */ +-/* +- * Copyright (C) 2008 Felix Fietkau +- */ +- +-#ifndef __RC_MINSTREL_H +-#define __RC_MINSTREL_H +- +-#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ +-#define EWMA_DIV 128 +-#define SAMPLE_COLUMNS 10 /* number of columns in sample table */ +- +-/* scaled fraction values */ +-#define MINSTREL_SCALE 12 +-#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) +-#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) +- +-/* number of highest throughput rates to consider*/ +-#define MAX_THR_RATES 4 +- +-/* +- * Coefficients for moving average with noise filter (period=16), +- * scaled by 10 bits +- * +- * a1 = exp(-pi * sqrt(2) / period) +- * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) +- * coeff3 = -sqr(a1) +- * coeff1 = 1 - coeff2 - coeff3 +- */ +-#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ +- MINSTREL_AVG_COEFF2 - \ +- MINSTREL_AVG_COEFF3) +-#define MINSTREL_AVG_COEFF2 0x00001499 +-#define MINSTREL_AVG_COEFF3 -0x0000092e +- +-/* +- * Perform EWMA (Exponentially Weighted Moving Average) calculation +- */ +-static inline int +-minstrel_ewma(int old, int new, int weight) +-{ +- int diff, incr; +- +- diff = new - old; +- incr = (EWMA_DIV - weight) * diff / EWMA_DIV; +- +- return old + incr; +-} +- +-static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) +-{ +- s32 out_1 = *prev_1; +- s32 out_2 = *prev_2; +- s32 val; +- +- if (!in) +- in += 1; +- +- if (!out_1) { +- val = out_1 = in; +- goto out; +- } +- +- val = MINSTREL_AVG_COEFF1 * in; +- val += MINSTREL_AVG_COEFF2 * out_1; +- val += MINSTREL_AVG_COEFF3 * out_2; +- val >>= MINSTREL_SCALE; +- +- if (val > 1 << MINSTREL_SCALE) +- val = 1 << MINSTREL_SCALE; +- if (val < 0) +- val = 1; +- +-out: +- *prev_2 = out_1; +- *prev_1 = val; +- +- return val; +-} +- +-struct minstrel_rate_stats { +- /* current / last sampling period attempts/success counters */ +- u16 attempts, last_attempts; +- u16 success, last_success; +- +- /* total attempts/success counters */ +- u32 att_hist, succ_hist; +- +- /* prob_avg - moving average of prob */ +- u16 prob_avg; +- u16 prob_avg_1; +- +- /* maximum retry counts */ +- u8 retry_count; +- u8 retry_count_rtscts; +- +- u8 sample_skipped; +- bool retry_updated; +-}; +- +-struct minstrel_rate { +- int bitrate; +- +- s8 rix; +- u8 retry_count_cts; +- u8 adjusted_retry_count; +- +- unsigned int perfect_tx_time; +- unsigned int ack_time; +- +- int sample_limit; +- +- struct minstrel_rate_stats stats; +-}; +- +-struct minstrel_sta_info { +- struct ieee80211_sta *sta; +- +- unsigned long last_stats_update; +- unsigned int sp_ack_dur; +- unsigned int rate_avg; +- +- unsigned int lowest_rix; +- +- u8 max_tp_rate[MAX_THR_RATES]; +- u8 max_prob_rate; +- unsigned int total_packets; +- unsigned int sample_packets; +- +- unsigned int sample_row; +- unsigned int sample_column; +- +- int n_rates; +- struct minstrel_rate *r; +- bool prev_sample; +- +- /* sampling table */ +- u8 *sample_table; +-}; +- +-struct minstrel_priv { +- struct ieee80211_hw *hw; +- bool has_mrr; +- bool new_avg; +- u32 sample_switch; +- unsigned int cw_min; +- unsigned int cw_max; +- unsigned int max_retry; +- unsigned int segment_size; +- unsigned int update_interval; +- unsigned int lookaround_rate; +- unsigned int lookaround_rate_mrr; +- +- u8 cck_rates[4]; +- +-#ifdef CPTCFG_MAC80211_DEBUGFS +- /* +- * enable fixed rate processing per RC +- * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx +- * - write -1 to enable RC processing again +- * - setting will be applied on next update +- */ +- u32 fixed_rate_idx; +-#endif +-}; +- +-struct minstrel_debugfs_info { +- size_t len; +- char buf[]; +-}; +- +-extern const struct rate_control_ops mac80211_minstrel; +-void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); +- +-/* Recalculate success probabilities and counters for a given rate using EWMA */ +-void minstrel_calc_rate_stats(struct minstrel_priv *mp, +- struct minstrel_rate_stats *mrs); +-int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg); +- +-/* debugfs */ +-int minstrel_stats_open(struct inode *inode, struct file *file); +-int minstrel_stats_csv_open(struct inode *inode, struct file *file); +- +-#endif +diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c +deleted file mode 100644 +index 9b8e0da..0000000 +--- a/net/mac80211/rc80211_minstrel_debugfs.c ++++ /dev/null +@@ -1,172 +0,0 @@ +-/* +- * Copyright (C) 2008 Felix Fietkau +- * +- * This program is free software; you can redistribute it and/or modify +- * it under the terms of the GNU General Public License version 2 as +- * published by the Free Software Foundation. +- * +- * Based on minstrel.c: +- * Copyright (C) 2005-2007 Derek Smithies +- * Sponsored by Indranet Technologies Ltd +- * +- * Based on sample.c: +- * Copyright (c) 2005 John Bicket +- * All rights reserved. +- * +- * Redistribution and use in source and binary forms, with or without +- * modification, are permitted provided that the following conditions +- * are met: +- * 1. Redistributions of source code must retain the above copyright +- * notice, this list of conditions and the following disclaimer, +- * without modification. +- * 2. Redistributions in binary form must reproduce at minimum a disclaimer +- * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any +- * redistribution must be conditioned upon including a substantially +- * similar Disclaimer requirement for further binary redistribution. +- * 3. Neither the names of the above-listed copyright holders nor the names +- * of any contributors may be used to endorse or promote products derived +- * from this software without specific prior written permission. +- * +- * Alternatively, this software may be distributed under the terms of the +- * GNU General Public License ("GPL") version 2 as published by the Free +- * Software Foundation. +- * +- * NO WARRANTY +- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +- * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +- * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY +- * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +- * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, +- * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +- * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +- * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +- * THE POSSIBILITY OF SUCH DAMAGES. +- */ +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include +-#include "rc80211_minstrel.h" +- +-int +-minstrel_stats_open(struct inode *inode, struct file *file) +-{ +- struct minstrel_sta_info *mi = inode->i_private; +- struct minstrel_debugfs_info *ms; +- unsigned int i, tp_max, tp_avg, eprob; +- char *p; +- +- ms = kmalloc(2048, GFP_KERNEL); +- if (!ms) +- return -ENOMEM; +- +- file->private_data = ms; +- p = ms->buf; +- p += sprintf(p, "\n"); +- p += sprintf(p, +- "best __________rate_________ ____statistics___ ____last_____ ______sum-of________\n"); +- p += sprintf(p, +- "rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); +- +- for (i = 0; i < mi->n_rates; i++) { +- struct minstrel_rate *mr = &mi->r[i]; +- struct minstrel_rate_stats *mrs = &mi->r[i].stats; +- +- *(p++) = (i == mi->max_tp_rate[0]) ? 'A' : ' '; +- *(p++) = (i == mi->max_tp_rate[1]) ? 'B' : ' '; +- *(p++) = (i == mi->max_tp_rate[2]) ? 'C' : ' '; +- *(p++) = (i == mi->max_tp_rate[3]) ? 'D' : ' '; +- *(p++) = (i == mi->max_prob_rate) ? 'P' : ' '; +- +- p += sprintf(p, " %3u%s ", mr->bitrate / 2, +- (mr->bitrate & 1 ? ".5" : " ")); +- p += sprintf(p, "%3u ", i); +- p += sprintf(p, "%6u ", mr->perfect_tx_time); +- +- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); +- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); +- eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); +- +- p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" +- " %3u %3u %-3u " +- "%9llu %-9llu\n", +- tp_max / 10, tp_max % 10, +- tp_avg / 10, tp_avg % 10, +- eprob / 10, eprob % 10, +- mrs->retry_count, +- mrs->last_success, +- mrs->last_attempts, +- (unsigned long long)mrs->succ_hist, +- (unsigned long long)mrs->att_hist); +- } +- p += sprintf(p, "\nTotal packet count:: ideal %d " +- "lookaround %d\n\n", +- mi->total_packets - mi->sample_packets, +- mi->sample_packets); +- ms->len = p - ms->buf; +- +- WARN_ON(ms->len + sizeof(*ms) > 2048); +- +- return 0; +-} +- +-int +-minstrel_stats_csv_open(struct inode *inode, struct file *file) +-{ +- struct minstrel_sta_info *mi = inode->i_private; +- struct minstrel_debugfs_info *ms; +- unsigned int i, tp_max, tp_avg, eprob; +- char *p; +- +- ms = kmalloc(2048, GFP_KERNEL); +- if (!ms) +- return -ENOMEM; +- +- file->private_data = ms; +- p = ms->buf; +- +- for (i = 0; i < mi->n_rates; i++) { +- struct minstrel_rate *mr = &mi->r[i]; +- struct minstrel_rate_stats *mrs = &mi->r[i].stats; +- +- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[0]) ? "A" : "")); +- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[1]) ? "B" : "")); +- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[2]) ? "C" : "")); +- p += sprintf(p, "%s" ,((i == mi->max_tp_rate[3]) ? "D" : "")); +- p += sprintf(p, "%s" ,((i == mi->max_prob_rate) ? "P" : "")); +- +- p += sprintf(p, ",%u%s", mr->bitrate / 2, +- (mr->bitrate & 1 ? ".5," : ",")); +- p += sprintf(p, "%u,", i); +- p += sprintf(p, "%u,",mr->perfect_tx_time); +- +- tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); +- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); +- eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); +- +- p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," +- "%llu,%llu,%d,%d\n", +- tp_max / 10, tp_max % 10, +- tp_avg / 10, tp_avg % 10, +- eprob / 10, eprob % 10, +- mrs->retry_count, +- mrs->last_success, +- mrs->last_attempts, +- (unsigned long long)mrs->succ_hist, +- (unsigned long long)mrs->att_hist, +- mi->total_packets - mi->sample_packets, +- mi->sample_packets); +- +- } +- ms->len = p - ms->buf; +- +- WARN_ON(ms->len + sizeof(*ms) > 2048); +- +- return 0; +-} +diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c +index 53d7c74..af4358e 100644 +--- a/net/mac80211/rc80211_minstrel_ht.c ++++ b/net/mac80211/rc80211_minstrel_ht.c +@@ -13,7 +13,6 @@ + #include + #include "rate.h" + #include "sta_info.h" +-#include "rc80211_minstrel.h" + #include "rc80211_minstrel_ht.h" + + #define AVG_AMPDU_SIZE 16 +@@ -136,20 +135,16 @@ + __VHT_GROUP(_streams, _sgi, _bw, \ + VHT_GROUP_SHIFT(_streams, _sgi, _bw)) + +-#define CCK_DURATION(_bitrate, _short, _len) \ ++#define CCK_DURATION(_bitrate, _short) \ + (1000 * (10 /* SIFS */ + \ + (_short ? 72 + 24 : 144 + 48) + \ +- (8 * (_len + 4) * 10) / (_bitrate))) +- +-#define CCK_ACK_DURATION(_bitrate, _short) \ +- (CCK_DURATION((_bitrate > 10 ? 20 : 10), false, 60) + \ +- CCK_DURATION(_bitrate, _short, AVG_PKT_SIZE)) ++ (8 * (AVG_PKT_SIZE + 4) * 10) / (_bitrate))) + + #define CCK_DURATION_LIST(_short, _s) \ +- CCK_ACK_DURATION(10, _short) >> _s, \ +- CCK_ACK_DURATION(20, _short) >> _s, \ +- CCK_ACK_DURATION(55, _short) >> _s, \ +- CCK_ACK_DURATION(110, _short) >> _s ++ CCK_DURATION(10, _short) >> _s, \ ++ CCK_DURATION(20, _short) >> _s, \ ++ CCK_DURATION(55, _short) >> _s, \ ++ CCK_DURATION(110, _short) >> _s + + #define __CCK_GROUP(_s) \ + [MINSTREL_CCK_GROUP] = { \ +@@ -163,10 +158,42 @@ + } + + #define CCK_GROUP_SHIFT \ +- GROUP_SHIFT(CCK_ACK_DURATION(10, false)) ++ GROUP_SHIFT(CCK_DURATION(10, false)) + + #define CCK_GROUP __CCK_GROUP(CCK_GROUP_SHIFT) + ++#define OFDM_DURATION(_bitrate) \ ++ (1000 * (16 /* SIFS + signal ext */ + \ ++ 16 /* T_PREAMBLE */ + \ ++ 4 /* T_SIGNAL */ + \ ++ 4 * (((16 + 80 * (AVG_PKT_SIZE + 4) + 6) / \ ++ ((_bitrate) * 4))))) ++ ++#define OFDM_DURATION_LIST(_s) \ ++ OFDM_DURATION(60) >> _s, \ ++ OFDM_DURATION(90) >> _s, \ ++ OFDM_DURATION(120) >> _s, \ ++ OFDM_DURATION(180) >> _s, \ ++ OFDM_DURATION(240) >> _s, \ ++ OFDM_DURATION(360) >> _s, \ ++ OFDM_DURATION(480) >> _s, \ ++ OFDM_DURATION(540) >> _s ++ ++#define __OFDM_GROUP(_s) \ ++ [MINSTREL_OFDM_GROUP] = { \ ++ .streams = 1, \ ++ .flags = 0, \ ++ .shift = _s, \ ++ .duration = { \ ++ OFDM_DURATION_LIST(_s), \ ++ } \ ++ } ++ ++#define OFDM_GROUP_SHIFT \ ++ GROUP_SHIFT(OFDM_DURATION(60)) ++ ++#define OFDM_GROUP __OFDM_GROUP(OFDM_GROUP_SHIFT) ++ + + static bool minstrel_vht_only = true; + module_param(minstrel_vht_only, bool, 0644); +@@ -203,6 +230,7 @@ const struct mcs_group minstrel_mcs_groups[] = { + MCS_GROUP(4, 1, BW_40), + + CCK_GROUP, ++ OFDM_GROUP, + + VHT_GROUP(1, 0, BW_20), + VHT_GROUP(2, 0, BW_20), +@@ -235,7 +263,17 @@ const struct mcs_group minstrel_mcs_groups[] = { + VHT_GROUP(4, 1, BW_80), + }; + ++const s16 minstrel_cck_bitrates[4] = { 10, 20, 55, 110 }; ++const s16 minstrel_ofdm_bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; + static u8 sample_table[SAMPLE_COLUMNS][MCS_GROUP_RATES] __read_mostly; ++static const u8 minstrel_sample_seq[] = { ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_SLOW, ++}; + + static void + minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi); +@@ -279,6 +317,13 @@ minstrel_get_valid_vht_rates(int bw, int nss, __le16 mcs_map) + return 0x3ff & ~mask; + } + ++static bool ++minstrel_ht_is_legacy_group(int group) ++{ ++ return group == MINSTREL_CCK_GROUP || ++ group == MINSTREL_OFDM_GROUP; ++} ++ + /* + * Look up an MCS group index based on mac80211 rate information + */ +@@ -308,37 +353,74 @@ minstrel_ht_get_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + if (rate->flags & IEEE80211_TX_RC_MCS) { + group = minstrel_ht_get_group_idx(rate); + idx = rate->idx % 8; +- } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { ++ goto out; ++ } ++ ++ if (rate->flags & IEEE80211_TX_RC_VHT_MCS) { + group = minstrel_vht_get_group_idx(rate); + idx = ieee80211_rate_get_vht_mcs(rate); +- } else { +- group = MINSTREL_CCK_GROUP; ++ goto out; ++ } + +- for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) +- if (rate->idx == mp->cck_rates[idx]) +- break; ++ group = MINSTREL_CCK_GROUP; ++ for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) { ++ if (rate->idx != mp->cck_rates[idx]) ++ continue; + + /* short preamble */ + if ((mi->supported[group] & BIT(idx + 4)) && + (rate->flags & IEEE80211_TX_RC_USE_SHORT_PREAMBLE)) +- idx += 4; ++ idx += 4; ++ goto out; + } ++ ++ group = MINSTREL_OFDM_GROUP; ++ for (idx = 0; idx < ARRAY_SIZE(mp->ofdm_rates[0]); idx++) ++ if (rate->idx == mp->ofdm_rates[mi->band][idx]) ++ goto out; ++ ++ idx = 0; ++out: + return &mi->groups[group].rates[idx]; + } + + static inline struct minstrel_rate_stats * + minstrel_get_ratestats(struct minstrel_ht_sta *mi, int index) + { +- return &mi->groups[index / MCS_GROUP_RATES].rates[index % MCS_GROUP_RATES]; ++ return &mi->groups[MI_RATE_GROUP(index)].rates[MI_RATE_IDX(index)]; ++} ++ ++static inline int minstrel_get_duration(int index) ++{ ++ const struct mcs_group *group = &minstrel_mcs_groups[MI_RATE_GROUP(index)]; ++ unsigned int duration = group->duration[MI_RATE_IDX(index)]; ++ ++ return duration << group->shift; + } + + static unsigned int + minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) + { +- if (!mi->avg_ampdu_len) +- return AVG_AMPDU_SIZE; ++ int duration; ++ ++ if (mi->avg_ampdu_len) ++ return MINSTREL_TRUNC(mi->avg_ampdu_len); ++ ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_tp_rate[0]))) ++ return 1; ++ ++ duration = minstrel_get_duration(mi->max_tp_rate[0]); + +- return MINSTREL_TRUNC(mi->avg_ampdu_len); ++ if (duration > 400 * 1000) ++ return 2; ++ ++ if (duration > 250 * 1000) ++ return 4; ++ ++ if (duration > 150 * 1000) ++ return 8; ++ ++ return 16; + } /* -+ * Coefficients for moving average with noise filter (period=16), -+ * scaled by 10 bits -+ * -+ * a1 = exp(-pi * sqrt(2) / period) -+ * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) -+ * coeff3 = -sqr(a1) -+ * coeff1 = 1 - coeff2 - coeff3 -+ */ -+#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ -+ MINSTREL_AVG_COEFF2 - \ -+ MINSTREL_AVG_COEFF3) -+#define MINSTREL_AVG_COEFF2 0x00001499 -+#define MINSTREL_AVG_COEFF3 -0x0000092e +@@ -349,15 +431,19 @@ int + minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, + int prob_avg) + { +- unsigned int nsecs = 0; ++ unsigned int nsecs = 0, overhead = mi->overhead; ++ unsigned int ampdu_len = 1; + + /* do not account throughput if sucess prob is below 10% */ + if (prob_avg < MINSTREL_FRAC(10, 100)) + return 0; + +- if (group != MINSTREL_CCK_GROUP) +- nsecs = 1000 * mi->overhead / minstrel_ht_avg_ampdu_len(mi); ++ if (minstrel_ht_is_legacy_group(group)) ++ overhead = mi->overhead_legacy; ++ else ++ ampdu_len = minstrel_ht_avg_ampdu_len(mi); + ++ nsecs = 1000 * overhead / ampdu_len; + nsecs += minstrel_mcs_groups[group].duration[rate] << + minstrel_mcs_groups[group].shift; + +@@ -367,10 +453,9 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, + * (prob is scaled - see MINSTREL_FRAC above) + */ + if (prob_avg > MINSTREL_FRAC(90, 100)) +- return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) +- / nsecs)); +- else +- return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs)); ++ prob_avg = MINSTREL_FRAC(90, 100); + -+/* - * Perform EWMA (Exponentially Weighted Moving Average) calculation - */ - static inline int -@@ -32,6 +47,37 @@ minstrel_ewma(int old, int new, int weight) - return old + incr; ++ return MINSTREL_TRUNC(100 * ((prob_avg * 1000000) / nsecs)); } + /* +@@ -388,14 +473,14 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, + int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; + int j = MAX_THR_RATES; + +- cur_group = index / MCS_GROUP_RATES; +- cur_idx = index % MCS_GROUP_RATES; ++ cur_group = MI_RATE_GROUP(index); ++ cur_idx = MI_RATE_IDX(index); + cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); + + do { +- tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; +- tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tp_list[j - 1]); ++ tmp_idx = MI_RATE_IDX(tp_list[j - 1]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, + tmp_prob); +@@ -417,41 +502,53 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, + * Find and set the topmost probability rate per sta and per group + */ + static void +-minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) ++minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 *dest, u16 index) + { + struct minstrel_mcs_group_data *mg; + struct minstrel_rate_stats *mrs; + int tmp_group, tmp_idx, tmp_tp_avg, tmp_prob; +- int max_tp_group, cur_tp_avg, cur_group, cur_idx; ++ int max_tp_group, max_tp_idx, max_tp_prob; ++ int cur_tp_avg, cur_group, cur_idx; + int max_gpr_group, max_gpr_idx; + int max_gpr_tp_avg, max_gpr_prob; ++ int min_dur; + +- cur_group = index / MCS_GROUP_RATES; +- cur_idx = index % MCS_GROUP_RATES; +- mg = &mi->groups[index / MCS_GROUP_RATES]; +- mrs = &mg->rates[index % MCS_GROUP_RATES]; ++ min_dur = max(minstrel_get_duration(mi->max_tp_rate[0]), ++ minstrel_get_duration(mi->max_tp_rate[1])); + +- tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; +- tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; ++ /* make the rate at least 18% slower than max tp rates */ ++ if (minstrel_get_duration(index) <= min_dur * 19 / 16) ++ return; ++ ++ cur_group = MI_RATE_GROUP(index); ++ cur_idx = MI_RATE_IDX(index); ++ mg = &mi->groups[cur_group]; ++ mrs = &mg->rates[cur_idx]; ++ ++ tmp_group = MI_RATE_GROUP(*dest); ++ tmp_idx = MI_RATE_IDX(*dest); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + + /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from + * MCS_GROUP as well as CCK_GROUP rates do not allow aggregation */ +- max_tp_group = mi->max_tp_rate[0] / MCS_GROUP_RATES; +- if((index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) && +- (max_tp_group != MINSTREL_CCK_GROUP)) ++ max_tp_group = MI_RATE_GROUP(mi->max_tp_rate[0]); ++ max_tp_idx = MI_RATE_IDX(mi->max_tp_rate[0]); ++ max_tp_prob = mi->groups[max_tp_group].rates[max_tp_idx].prob_avg; ++ ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index)) && ++ !minstrel_ht_is_legacy_group(max_tp_group)) + return; + +- max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; +- max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; ++ max_gpr_group = MI_RATE_GROUP(mg->max_group_prob_rate); ++ max_gpr_idx = MI_RATE_IDX(mg->max_group_prob_rate); + max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; + + if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { + cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, + mrs->prob_avg); + if (cur_tp_avg > tmp_tp_avg) +- mi->max_prob_rate = index; ++ *dest = index; + + max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group, + max_gpr_idx, +@@ -460,7 +557,7 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) + mg->max_group_prob_rate = index; + } else { + if (mrs->prob_avg > tmp_prob) +- mi->max_prob_rate = index; ++ *dest = index; + if (mrs->prob_avg > max_gpr_prob) + mg->max_group_prob_rate = index; + } +@@ -476,188 +573,384 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) + static void + minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, + u16 tmp_mcs_tp_rate[MAX_THR_RATES], +- u16 tmp_cck_tp_rate[MAX_THR_RATES]) ++ u16 tmp_legacy_tp_rate[MAX_THR_RATES]) + { + unsigned int tmp_group, tmp_idx, tmp_cck_tp, tmp_mcs_tp, tmp_prob; + int i; + +- tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; +- tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tmp_legacy_tp_rate[0]); ++ tmp_idx = MI_RATE_IDX(tmp_legacy_tp_rate[0]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + +- tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; +- tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; ++ tmp_group = MI_RATE_GROUP(tmp_mcs_tp_rate[0]); ++ tmp_idx = MI_RATE_IDX(tmp_mcs_tp_rate[0]); + tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; + tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + + if (tmp_cck_tp > tmp_mcs_tp) { + for(i = 0; i < MAX_THR_RATES; i++) { +- minstrel_ht_sort_best_tp_rates(mi, tmp_cck_tp_rate[i], ++ minstrel_ht_sort_best_tp_rates(mi, tmp_legacy_tp_rate[i], + tmp_mcs_tp_rate); + } + } + + } + +-/* +- * Try to increase robustness of max_prob rate by decrease number of +- * streams if possible. +- */ +-static inline void +-minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) ++static u16 ++__minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi, ++ enum minstrel_sample_type type) + { +- struct minstrel_mcs_group_data *mg; +- int tmp_max_streams, group, tmp_idx, tmp_prob; +- int tmp_tp = 0; ++ u16 *rates = mi->sample[type].sample_rates; ++ u16 cur; ++ int i; + +- tmp_max_streams = minstrel_mcs_groups[mi->max_tp_rate[0] / +- MCS_GROUP_RATES].streams; +- for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { +- mg = &mi->groups[group]; +- if (!mi->supported[group] || group == MINSTREL_CCK_GROUP) ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ if (!rates[i]) + continue; + +- tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; +- tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; +- +- if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && +- (minstrel_mcs_groups[group].streams < tmp_max_streams)) { +- mi->max_prob_rate = mg->max_group_prob_rate; +- tmp_tp = minstrel_ht_get_tp_avg(mi, group, +- tmp_idx, +- tmp_prob); +- } ++ cur = rates[i]; ++ rates[i] = 0; ++ return cur; + } ++ ++ return 0; + } + + static inline int +-minstrel_get_duration(int index) ++minstrel_ewma(int old, int new, int weight) + { +- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; +- unsigned int duration = group->duration[index % MCS_GROUP_RATES]; +- return duration << group->shift; ++ int diff, incr; ++ ++ diff = new - old; ++ incr = (EWMA_DIV - weight) * diff / EWMA_DIV; ++ ++ return old + incr; + } + +-static bool +-minstrel_ht_probe_group(struct minstrel_ht_sta *mi, const struct mcs_group *tp_group, +- int tp_idx, const struct mcs_group *group) +static inline int minstrel_filter_avg_add(u16 *prev_1, u16 *prev_2, s32 in) -+{ + { +- if (group->bw < tp_group->bw) +- return false; + s32 out_1 = *prev_1; + s32 out_2 = *prev_2; + s32 val; -+ + +- if (group->streams == tp_group->streams) +- return true; + if (!in) + in += 1; -+ + +- if (tp_idx < 4 && group->streams == tp_group->streams - 1) +- return true; + if (!out_1) { + val = out_1 = in; + goto out; + } -+ + +- return group->streams == tp_group->streams + 1; + val = MINSTREL_AVG_COEFF1 * in; + val += MINSTREL_AVG_COEFF2 * out_1; + val += MINSTREL_AVG_COEFF3 * out_2; @@ -2298,404 +3353,2100 @@ index 9b6c433..f3fbea2 100644 + *prev_1 = val; + + return val; + } + ++/* ++* Recalculate statistics and counters of a given rate ++*/ + static void +-minstrel_ht_find_probe_rates(struct minstrel_ht_sta *mi, u16 *rates, int *n_rates, +- bool faster_rate) ++minstrel_ht_calc_rate_stats(struct minstrel_priv *mp, ++ struct minstrel_rate_stats *mrs) + { +- const struct mcs_group *group, *tp_group; +- int i, g, max_dur; +- int tp_idx; ++ unsigned int cur_prob; ++ ++ if (unlikely(mrs->attempts > 0)) { ++ cur_prob = MINSTREL_FRAC(mrs->success + mrs->last_success, ++ mrs->attempts + mrs->last_attempts); ++ minstrel_filter_avg_add(&mrs->prob_avg, ++ &mrs->prob_avg_1, cur_prob); ++ mrs->att_hist += mrs->attempts; ++ mrs->succ_hist += mrs->success; ++ } + +- tp_group = &minstrel_mcs_groups[mi->max_tp_rate[0] / MCS_GROUP_RATES]; +- tp_idx = mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ mrs->last_success = mrs->success; ++ mrs->last_attempts = mrs->attempts; ++ mrs->success = 0; ++ mrs->attempts = 0; ++} + +- max_dur = minstrel_get_duration(mi->max_tp_rate[0]); +- if (faster_rate) +- max_dur -= max_dur / 16; ++static bool ++minstrel_ht_find_sample_rate(struct minstrel_ht_sta *mi, int type, int idx) ++{ ++ int i; + +- for (g = 0; g < MINSTREL_GROUPS_NB; g++) { +- u16 supported = mi->supported[g]; ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ u16 cur = mi->sample[type].sample_rates[i]; + +- if (!supported) +- continue; ++ if (cur == idx) ++ return true; + +- group = &minstrel_mcs_groups[g]; +- if (!minstrel_ht_probe_group(mi, tp_group, tp_idx, group)) +- continue; ++ if (!cur) ++ break; ++ } + +- for (i = 0; supported; supported >>= 1, i++) { +- int idx; ++ return false; ++} + +- if (!(supported & 1)) +- continue; ++static int ++minstrel_ht_move_sample_rates(struct minstrel_ht_sta *mi, int type, ++ u32 fast_rate_dur, u32 slow_rate_dur) ++{ ++ u16 *rates = mi->sample[type].sample_rates; ++ int i, j; + +- if ((group->duration[i] << group->shift) > max_dur) +- continue; ++ for (i = 0, j = 0; i < MINSTREL_SAMPLE_RATES; i++) { ++ u32 duration; ++ bool valid = false; ++ u16 cur; + +- idx = g * MCS_GROUP_RATES + i; +- if (idx == mi->max_tp_rate[0]) +- continue; ++ cur = rates[i]; ++ if (!cur) ++ continue; + +- rates[(*n_rates)++] = idx; ++ duration = minstrel_get_duration(cur); ++ switch (type) { ++ case MINSTREL_SAMPLE_TYPE_SLOW: ++ valid = duration > fast_rate_dur && ++ duration < slow_rate_dur; ++ break; ++ case MINSTREL_SAMPLE_TYPE_INC: ++ case MINSTREL_SAMPLE_TYPE_JUMP: ++ valid = duration < fast_rate_dur; ++ break; ++ default: ++ valid = false; + break; + } ++ ++ if (!valid) { ++ rates[i] = 0; ++ continue; ++ } ++ ++ if (i == j) ++ continue; ++ ++ rates[j++] = cur; ++ rates[i] = 0; + } ++ ++ return j; + } + +-static void +-minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, +- struct minstrel_ht_sta *mi) ++static int ++minstrel_ht_group_min_rate_offset(struct minstrel_ht_sta *mi, int group, ++ u32 max_duration) + { +- struct minstrel_rate_stats *mrs; +- u16 rates[MINSTREL_GROUPS_NB]; +- int n_rates = 0; +- int probe_rate = 0; +- bool faster_rate; ++ u16 supported = mi->supported[group]; + int i; +- u8 random; + +- /* +- * Use rate switching instead of probing packets for devices with +- * little control over retry fallback behavior +- */ +- if (mp->hw->max_rates > 1) +- return; ++ for (i = 0; i < MCS_GROUP_RATES && supported; i++, supported >>= 1) { ++ if (!(supported & BIT(0))) ++ continue; + +- /* +- * If the current EWMA prob is >75%, look for a rate that's 6.25% +- * faster than the max tp rate. +- * If that fails, look again for a rate that is at least as fast +- */ +- mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); +- faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100); +- minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate); +- if (!n_rates && faster_rate) +- minstrel_ht_find_probe_rates(mi, rates, &n_rates, false); +- +- /* If no suitable rate was found, try to pick the next one in the group */ +- if (!n_rates) { +- int g_idx = mi->max_tp_rate[0] / MCS_GROUP_RATES; +- u16 supported = mi->supported[g_idx]; +- +- supported >>= mi->max_tp_rate[0] % MCS_GROUP_RATES; +- for (i = 0; supported; supported >>= 1, i++) { +- if (!(supported & 1)) +- continue; ++ if (minstrel_get_duration(MI_RATE(group, i)) >= max_duration) ++ continue; ++ ++ return i; ++ } + +- probe_rate = mi->max_tp_rate[0] + i; ++ return -1; +} + - struct minstrel_rate_stats { - /* current / last sampling period attempts/success counters */ - u16 attempts, last_attempts; -@@ -40,8 +86,9 @@ struct minstrel_rate_stats { - /* total attempts/success counters */ - u32 att_hist, succ_hist; ++/* ++ * Incremental update rates: ++ * Flip through groups and pick the first group rate that is faster than the ++ * highest currently selected rate ++ */ ++static u16 ++minstrel_ht_next_inc_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur) ++{ ++ struct minstrel_mcs_group_data *mg; ++ u8 type = MINSTREL_SAMPLE_TYPE_INC; ++ int i, index = 0; ++ u8 group; ++ ++ group = mi->sample[type].sample_group; ++ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { ++ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); ++ mg = &mi->groups[group]; ++ ++ index = minstrel_ht_group_min_rate_offset(mi, group, ++ fast_rate_dur); ++ if (index < 0) ++ continue; ++ ++ index = MI_RATE(group, index & 0xf); ++ if (!minstrel_ht_find_sample_rate(mi, type, index)) + goto out; ++ } ++ index = 0; ++ ++out: ++ mi->sample[type].sample_group = group; ++ ++ return index; ++} ++ ++static int ++minstrel_ht_next_group_sample_rate(struct minstrel_ht_sta *mi, int group, ++ u16 supported, int offset) ++{ ++ struct minstrel_mcs_group_data *mg = &mi->groups[group]; ++ u16 idx; ++ int i; ++ ++ for (i = 0; i < MCS_GROUP_RATES; i++) { ++ idx = sample_table[mg->column][mg->index]; ++ if (++mg->index >= MCS_GROUP_RATES) { ++ mg->index = 0; ++ if (++mg->column >= ARRAY_SIZE(sample_table)) ++ mg->column = 0; + } -- /* prob_ewma - exponential weighted moving average of prob */ -- u16 prob_ewma; -+ /* prob_avg - moving average of prob */ -+ u16 prob_avg; -+ u16 prob_avg_1; - - /* maximum retry counts */ - u8 retry_count; -@@ -95,6 +142,7 @@ struct minstrel_sta_info { - struct minstrel_priv { - struct ieee80211_hw *hw; - bool has_mrr; -+ bool new_avg; - u32 sample_switch; - unsigned int cw_min; - unsigned int cw_max; -@@ -126,8 +174,9 @@ extern const struct rate_control_ops mac80211_minstrel; - void minstrel_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); - - /* Recalculate success probabilities and counters for a given rate using EWMA */ --void minstrel_calc_rate_stats(struct minstrel_rate_stats *mrs); --int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_ewma); -+void minstrel_calc_rate_stats(struct minstrel_priv *mp, -+ struct minstrel_rate_stats *mrs); -+int minstrel_get_tp_avg(struct minstrel_rate *mr, int prob_avg); - - /* debugfs */ - int minstrel_stats_open(struct inode *inode, struct file *file); -diff --git a/net/mac80211/rc80211_minstrel_debugfs.c b/net/mac80211/rc80211_minstrel_debugfs.c -index c8afd85..9b8e0da 100644 ---- a/net/mac80211/rc80211_minstrel_debugfs.c -+++ b/net/mac80211/rc80211_minstrel_debugfs.c -@@ -90,8 +90,8 @@ minstrel_stats_open(struct inode *inode, struct file *file) - p += sprintf(p, "%6u ", mr->perfect_tx_time); - - tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); -- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); -- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); -+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); -+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); - - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" - " %3u %3u %-3u " -@@ -147,8 +147,8 @@ minstrel_stats_csv_open(struct inode *inode, struct file *file) - p += sprintf(p, "%u,",mr->perfect_tx_time); - - tp_max = minstrel_get_tp_avg(mr, MINSTREL_FRAC(100,100)); -- tp_avg = minstrel_get_tp_avg(mr, mrs->prob_ewma); -- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); -+ tp_avg = minstrel_get_tp_avg(mr, mrs->prob_avg); -+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); - - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u,%u," - "%llu,%llu,%d,%d\n", -diff --git a/net/mac80211/rc80211_minstrel_ht.c b/net/mac80211/rc80211_minstrel_ht.c -index 2888011..db5811c 100644 ---- a/net/mac80211/rc80211_minstrel_ht.c -+++ b/net/mac80211/rc80211_minstrel_ht.c -@@ -346,12 +346,12 @@ minstrel_ht_avg_ampdu_len(struct minstrel_ht_sta *mi) - */ - int - minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, -- int prob_ewma) -+ int prob_avg) - { - unsigned int nsecs = 0; - - /* do not account throughput if sucess prob is below 10% */ -- if (prob_ewma < MINSTREL_FRAC(10, 100)) -+ if (prob_avg < MINSTREL_FRAC(10, 100)) - return 0; - - if (group != MINSTREL_CCK_GROUP) -@@ -365,11 +365,11 @@ minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, - * account for collision related packet error rate fluctuation - * (prob is scaled - see MINSTREL_FRAC above) - */ -- if (prob_ewma > MINSTREL_FRAC(90, 100)) -+ if (prob_avg > MINSTREL_FRAC(90, 100)) - return MINSTREL_TRUNC(100000 * ((MINSTREL_FRAC(90, 100) * 1000) - / nsecs)); - else -- return MINSTREL_TRUNC(100000 * ((prob_ewma * 1000) / nsecs)); -+ return MINSTREL_TRUNC(100000 * ((prob_avg * 1000) / nsecs)); - } - - /* -@@ -389,13 +389,13 @@ minstrel_ht_sort_best_tp_rates(struct minstrel_ht_sta *mi, u16 index, - - cur_group = index / MCS_GROUP_RATES; - cur_idx = index % MCS_GROUP_RATES; -- cur_prob = mi->groups[cur_group].rates[cur_idx].prob_ewma; -+ cur_prob = mi->groups[cur_group].rates[cur_idx].prob_avg; - cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, cur_prob); - - do { - tmp_group = tp_list[j - 1] / MCS_GROUP_RATES; - tmp_idx = tp_list[j - 1] % MCS_GROUP_RATES; -- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; -+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, - tmp_prob); - if (cur_tp_avg < tmp_tp_avg || -@@ -432,7 +432,7 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) - - tmp_group = mi->max_prob_rate / MCS_GROUP_RATES; - tmp_idx = mi->max_prob_rate % MCS_GROUP_RATES; -- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; -+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_tp_avg = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); - - /* if max_tp_rate[0] is from MCS_GROUP max_prob_rate get selected from -@@ -444,11 +444,11 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) - - max_gpr_group = mg->max_group_prob_rate / MCS_GROUP_RATES; - max_gpr_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; -- max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_ewma; -+ max_gpr_prob = mi->groups[max_gpr_group].rates[max_gpr_idx].prob_avg; - -- if (mrs->prob_ewma > MINSTREL_FRAC(75, 100)) { -+ if (mrs->prob_avg > MINSTREL_FRAC(75, 100)) { - cur_tp_avg = minstrel_ht_get_tp_avg(mi, cur_group, cur_idx, -- mrs->prob_ewma); -+ mrs->prob_avg); - if (cur_tp_avg > tmp_tp_avg) - mi->max_prob_rate = index; - -@@ -458,9 +458,9 @@ minstrel_ht_set_best_prob_rate(struct minstrel_ht_sta *mi, u16 index) - if (cur_tp_avg > max_gpr_tp_avg) - mg->max_group_prob_rate = index; - } else { -- if (mrs->prob_ewma > tmp_prob) -+ if (mrs->prob_avg > tmp_prob) - mi->max_prob_rate = index; -- if (mrs->prob_ewma > max_gpr_prob) -+ if (mrs->prob_avg > max_gpr_prob) - mg->max_group_prob_rate = index; +- return; ++ if (idx < offset) ++ continue; ++ ++ if (!(supported & BIT(idx))) ++ continue; ++ ++ return MI_RATE(group, idx); ++ } ++ ++ return -1; ++} ++ ++/* ++ * Jump rates: ++ * Sample random rates, use those that are faster than the highest ++ * currently selected rate. Rates between the fastest and the slowest ++ * get sorted into the slow sample bucket, but only if it has room ++ */ ++static u16 ++minstrel_ht_next_jump_rate(struct minstrel_ht_sta *mi, u32 fast_rate_dur, ++ u32 slow_rate_dur, int *slow_rate_ofs) ++{ ++ struct minstrel_mcs_group_data *mg; ++ struct minstrel_rate_stats *mrs; ++ u32 max_duration = slow_rate_dur; ++ int i, index, offset; ++ u16 *slow_rates; ++ u16 supported; ++ u32 duration; ++ u8 group; ++ ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ max_duration = fast_rate_dur; ++ ++ slow_rates = mi->sample[MINSTREL_SAMPLE_TYPE_SLOW].sample_rates; ++ group = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group; ++ for (i = 0; i < ARRAY_SIZE(minstrel_mcs_groups); i++) { ++ u8 type; ++ ++ group = (group + 1) % ARRAY_SIZE(minstrel_mcs_groups); ++ mg = &mi->groups[group]; ++ ++ supported = mi->supported[group]; ++ if (!supported) ++ continue; ++ ++ offset = minstrel_ht_group_min_rate_offset(mi, group, ++ max_duration); ++ if (offset < 0) ++ continue; ++ ++ index = minstrel_ht_next_group_sample_rate(mi, group, supported, ++ offset); ++ if (index < 0) ++ continue; ++ ++ duration = minstrel_get_duration(index); ++ if (duration < fast_rate_dur) ++ type = MINSTREL_SAMPLE_TYPE_JUMP; ++ else ++ type = MINSTREL_SAMPLE_TYPE_SLOW; ++ ++ if (minstrel_ht_find_sample_rate(mi, type, index)) ++ continue; ++ ++ if (type == MINSTREL_SAMPLE_TYPE_JUMP) ++ goto found; ++ ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ continue; ++ ++ if (duration >= slow_rate_dur) ++ continue; ++ ++ /* skip slow rates with high success probability */ ++ mrs = minstrel_get_ratestats(mi, index); ++ if (mrs->prob_avg > MINSTREL_FRAC(95, 100)) ++ continue; ++ ++ slow_rates[(*slow_rate_ofs)++] = index; ++ if (*slow_rate_ofs >= MINSTREL_SAMPLE_RATES) ++ max_duration = fast_rate_dur; } ++ index = 0; ++ ++found: ++ mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_group = group; ++ ++ return index; ++} + +- i = 0; +- if (n_rates > 1) { +- random = prandom_u32(); +- i = random % n_rates; ++static void ++minstrel_ht_refill_sample_rates(struct minstrel_ht_sta *mi) ++{ ++ u32 prob_dur = minstrel_get_duration(mi->max_prob_rate); ++ u32 tp_dur = minstrel_get_duration(mi->max_tp_rate[0]); ++ u32 tp2_dur = minstrel_get_duration(mi->max_tp_rate[1]); ++ u32 fast_rate_dur = min(min(tp_dur, tp2_dur), prob_dur); ++ u32 slow_rate_dur = max(max(tp_dur, tp2_dur), prob_dur); ++ u16 *rates; ++ int i, j; ++ ++ rates = mi->sample[MINSTREL_SAMPLE_TYPE_INC].sample_rates; ++ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_INC, ++ fast_rate_dur, slow_rate_dur); ++ while (i < MINSTREL_SAMPLE_RATES) { ++ rates[i] = minstrel_ht_next_inc_rate(mi, tp_dur); ++ if (!rates[i]) ++ break; ++ ++ i++; + } +- probe_rate = rates[i]; + +-out: +- mi->sample_rate = probe_rate; +- mi->sample_mode = MINSTREL_SAMPLE_ACTIVE; ++ rates = mi->sample[MINSTREL_SAMPLE_TYPE_JUMP].sample_rates; ++ i = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_JUMP, ++ fast_rate_dur, slow_rate_dur); ++ j = minstrel_ht_move_sample_rates(mi, MINSTREL_SAMPLE_TYPE_SLOW, ++ fast_rate_dur, slow_rate_dur); ++ while (i < MINSTREL_SAMPLE_RATES) { ++ rates[i] = minstrel_ht_next_jump_rate(mi, fast_rate_dur, ++ slow_rate_dur, &j); ++ if (!rates[i]) ++ break; ++ ++ i++; ++ } ++ ++ for (i = 0; i < ARRAY_SIZE(mi->sample); i++) ++ memcpy(mi->sample[i].cur_sample_rates, mi->sample[i].sample_rates, ++ sizeof(mi->sample[i].cur_sample_rates)); } -@@ -482,12 +482,12 @@ minstrel_ht_assign_best_tp_rates(struct minstrel_ht_sta *mi, - tmp_group = tmp_cck_tp_rate[0] / MCS_GROUP_RATES; - tmp_idx = tmp_cck_tp_rate[0] % MCS_GROUP_RATES; -- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; -+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_cck_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); ++ + /* + * Update rate statistics and select new primary rates + * +@@ -668,26 +961,15 @@ out: + * higher throughput rates, even if the probablity is a bit lower + */ + static void +-minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, +- bool sample) ++minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { + struct minstrel_mcs_group_data *mg; + struct minstrel_rate_stats *mrs; + int group, i, j, cur_prob; + u16 tmp_mcs_tp_rate[MAX_THR_RATES], tmp_group_tp_rate[MAX_THR_RATES]; +- u16 tmp_cck_tp_rate[MAX_THR_RATES], index; +- +- mi->sample_mode = MINSTREL_SAMPLE_IDLE; +- +- if (sample) { +- mi->total_packets_cur = mi->total_packets - +- mi->total_packets_last; +- mi->total_packets_last = mi->total_packets; +- } +- if (!mp->sample_switch) +- sample = false; +- if (mi->total_packets_cur < SAMPLE_SWITCH_THR && mp->sample_switch != 1) +- sample = false; ++ u16 tmp_legacy_tp_rate[MAX_THR_RATES], tmp_max_prob_rate; ++ u16 index; ++ bool ht_supported = mi->sta->ht_cap.ht_supported; - tmp_group = tmp_mcs_tp_rate[0] / MCS_GROUP_RATES; - tmp_idx = tmp_mcs_tp_rate[0] % MCS_GROUP_RATES; -- tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_ewma; -+ tmp_prob = mi->groups[tmp_group].rates[tmp_idx].prob_avg; - tmp_mcs_tp = minstrel_ht_get_tp_avg(mi, tmp_group, tmp_idx, tmp_prob); + if (mi->ampdu_packets > 0) { + if (!ieee80211_hw_check(mp->hw, TX_STATUS_NO_AMPDU_LEN)) +@@ -700,65 +982,72 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + mi->ampdu_packets = 0; + } - if (tmp_cck_tp_rate && tmp_cck_tp > tmp_mcs_tp) { -@@ -518,7 +518,7 @@ minstrel_ht_prob_rate_reduce_streams(struct minstrel_ht_sta *mi) +- mi->sample_slow = 0; +- mi->sample_count = 0; +- +- memset(tmp_mcs_tp_rate, 0, sizeof(tmp_mcs_tp_rate)); +- memset(tmp_cck_tp_rate, 0, sizeof(tmp_cck_tp_rate)); + if (mi->supported[MINSTREL_CCK_GROUP]) +- for (j = 0; j < ARRAY_SIZE(tmp_cck_tp_rate); j++) +- tmp_cck_tp_rate[j] = MINSTREL_CCK_GROUP * MCS_GROUP_RATES; ++ group = MINSTREL_CCK_GROUP; ++ else if (mi->supported[MINSTREL_OFDM_GROUP]) ++ group = MINSTREL_OFDM_GROUP; ++ else ++ group = 0; ++ ++ index = MI_RATE(group, 0); ++ for (j = 0; j < ARRAY_SIZE(tmp_legacy_tp_rate); j++) ++ tmp_legacy_tp_rate[j] = index; + + if (mi->supported[MINSTREL_VHT_GROUP_0]) +- index = MINSTREL_VHT_GROUP_0 * MCS_GROUP_RATES; ++ group = MINSTREL_VHT_GROUP_0; ++ else if (ht_supported) ++ group = MINSTREL_HT_GROUP_0; ++ else if (mi->supported[MINSTREL_CCK_GROUP]) ++ group = MINSTREL_CCK_GROUP; + else +- index = MINSTREL_HT_GROUP_0 * MCS_GROUP_RATES; ++ group = MINSTREL_OFDM_GROUP; + ++ index = MI_RATE(group, 0); ++ tmp_max_prob_rate = index; + for (j = 0; j < ARRAY_SIZE(tmp_mcs_tp_rate); j++) + tmp_mcs_tp_rate[j] = index; + + /* Find best rate sets within all MCS groups*/ + for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { ++ u16 *tp_rate = tmp_mcs_tp_rate; ++ u16 last_prob = 0; + + mg = &mi->groups[group]; + if (!mi->supported[group]) continue; - tmp_idx = mg->max_group_prob_rate % MCS_GROUP_RATES; -- tmp_prob = mi->groups[group].rates[tmp_idx].prob_ewma; -+ tmp_prob = mi->groups[group].rates[tmp_idx].prob_avg; +- mi->sample_count++; +- + /* (re)Initialize group rate indexes */ + for(j = 0; j < MAX_THR_RATES; j++) +- tmp_group_tp_rate[j] = MCS_GROUP_RATES * group; ++ tmp_group_tp_rate[j] = MI_RATE(group, 0); - if (tmp_tp < minstrel_ht_get_tp_avg(mi, group, tmp_idx, tmp_prob) && - (minstrel_mcs_groups[group].streams < tmp_max_streams)) { -@@ -623,7 +623,7 @@ minstrel_ht_rate_sample_switch(struct minstrel_priv *mp, - * If that fails, look again for a rate that is at least as fast - */ - mrs = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); -- faster_rate = mrs->prob_ewma > MINSTREL_FRAC(75, 100); -+ faster_rate = mrs->prob_avg > MINSTREL_FRAC(75, 100); - minstrel_ht_find_probe_rates(mi, rates, &n_rates, faster_rate); - if (!n_rates && faster_rate) - minstrel_ht_find_probe_rates(mi, rates, &n_rates, false); -@@ -737,8 +737,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, +- for (i = 0; i < MCS_GROUP_RATES; i++) { ++ if (group == MINSTREL_CCK_GROUP && ht_supported) ++ tp_rate = tmp_legacy_tp_rate; ++ ++ for (i = MCS_GROUP_RATES - 1; i >= 0; i--) { + if (!(mi->supported[group] & BIT(i))) + continue; + +- index = MCS_GROUP_RATES * group + i; ++ index = MI_RATE(group, i); mrs = &mg->rates[i]; mrs->retry_updated = false; -- minstrel_calc_rate_stats(mrs); -- cur_prob = mrs->prob_ewma; -+ minstrel_calc_rate_stats(mp, mrs); -+ cur_prob = mrs->prob_avg; +- minstrel_calc_rate_stats(mp, mrs); ++ minstrel_ht_calc_rate_stats(mp, mrs); ++ ++ if (mrs->att_hist) ++ last_prob = max(last_prob, mrs->prob_avg); ++ else ++ mrs->prob_avg = max(last_prob, mrs->prob_avg); + cur_prob = mrs->prob_avg; if (minstrel_ht_get_tp_avg(mi, group, i, cur_prob) == 0) continue; -@@ -773,6 +773,8 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - /* try to sample all available rates during each interval */ - mi->sample_count *= 8; -+ if (mp->new_avg) -+ mi->sample_count /= 2; + /* Find max throughput rate set */ +- if (group != MINSTREL_CCK_GROUP) { +- minstrel_ht_sort_best_tp_rates(mi, index, +- tmp_mcs_tp_rate); +- } else if (group == MINSTREL_CCK_GROUP) { +- minstrel_ht_sort_best_tp_rates(mi, index, +- tmp_cck_tp_rate); +- } ++ minstrel_ht_sort_best_tp_rates(mi, index, tp_rate); - if (sample) - minstrel_ht_rate_sample_switch(mp, mi); -@@ -889,6 +891,7 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, - struct ieee80211_tx_rate *ar = info->status.rates; - struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; - struct minstrel_priv *mp = priv; -+ u32 update_interval = mp->update_interval / 2; - bool last, update = false; - bool sample_status = false; - int i; -@@ -943,6 +946,10 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, - - switch (mi->sample_mode) { - case MINSTREL_SAMPLE_IDLE: -+ if (mp->new_avg && -+ (mp->hw->max_rates > 1 || -+ mi->total_packets_cur < SAMPLE_SWITCH_THR)) -+ update_interval /= 2; - break; - - case MINSTREL_SAMPLE_ACTIVE: -@@ -970,23 +977,20 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, - */ - rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); - if (rate->attempts > 30 && -- MINSTREL_FRAC(rate->success, rate->attempts) < -- MINSTREL_FRAC(20, 100)) { -+ rate->success < rate->attempts / 4) { - minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); - update = true; + /* Find max throughput rate set within a group */ + minstrel_ht_sort_best_tp_rates(mi, index, + tmp_group_tp_rate); +- +- /* Find max probability rate per group and global */ +- minstrel_ht_set_best_prob_rate(mi, index); } - rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); - if (rate2->attempts > 30 && -- MINSTREL_FRAC(rate2->success, rate2->attempts) < -- MINSTREL_FRAC(20, 100)) { -+ rate2->success < rate2->attempts / 4) { - minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); - update = true; - } + memcpy(mg->max_group_tp_rate, tmp_group_tp_rate, +@@ -766,19 +1055,32 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, } -- if (time_after(jiffies, mi->last_stats_update + -- (mp->update_interval / 2 * HZ) / 1000)) { -+ if (time_after(jiffies, mi->last_stats_update + update_interval)) { - update = true; - minstrel_ht_update_stats(mp, mi, true); + /* Assign new rate set per sta */ +- minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, tmp_cck_tp_rate); ++ minstrel_ht_assign_best_tp_rates(mi, tmp_mcs_tp_rate, ++ tmp_legacy_tp_rate); + memcpy(mi->max_tp_rate, tmp_mcs_tp_rate, sizeof(mi->max_tp_rate)); + +- /* Try to increase robustness of max_prob_rate*/ +- minstrel_ht_prob_rate_reduce_streams(mi); ++ for (group = 0; group < ARRAY_SIZE(minstrel_mcs_groups); group++) { ++ if (!mi->supported[group]) ++ continue; + +- /* try to sample all available rates during each interval */ +- mi->sample_count *= 8; +- if (mp->new_avg) +- mi->sample_count /= 2; ++ mg = &mi->groups[group]; ++ mg->max_group_prob_rate = MI_RATE(group, 0); ++ ++ for (i = 0; i < MCS_GROUP_RATES; i++) { ++ if (!(mi->supported[group] & BIT(i))) ++ continue; ++ ++ index = MI_RATE(group, i); ++ ++ /* Find max probability rate per group and global */ ++ minstrel_ht_set_best_prob_rate(mi, &tmp_max_prob_rate, ++ index); ++ } ++ } ++ ++ mi->max_prob_rate = tmp_max_prob_rate; + +- if (sample) +- minstrel_ht_rate_sample_switch(mp, mi); ++ minstrel_ht_refill_sample_rates(mi); + + #ifdef CPTCFG_MAC80211_DEBUGFS + /* use fixed index if set */ +@@ -786,17 +1088,20 @@ minstrel_ht_update_stats(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + for (i = 0; i < 4; i++) + mi->max_tp_rate[i] = mp->fixed_rate_idx; + mi->max_prob_rate = mp->fixed_rate_idx; +- mi->sample_mode = MINSTREL_SAMPLE_IDLE; } -@@ -1008,7 +1012,7 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - unsigned int overhead = 0, overhead_rtscts = 0; + #endif - mrs = minstrel_get_ratestats(mi, index); -- if (mrs->prob_ewma < MINSTREL_FRAC(1, 10)) { -+ if (mrs->prob_avg < MINSTREL_FRAC(1, 10)) { - mrs->retry_count = 1; - mrs->retry_count_rtscts = 1; - return; -@@ -1065,7 +1069,7 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, - if (!mrs->retry_updated) - minstrel_calc_retransmit(mp, mi, index); - -- if (mrs->prob_ewma < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { -+ if (mrs->prob_avg < MINSTREL_FRAC(20, 100) || !mrs->retry_count) { - ratetbl->rate[offset].count = 2; - ratetbl->rate[offset].count_rts = 2; - ratetbl->rate[offset].count_cts = 2; -@@ -1099,11 +1103,11 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + /* Reset update timer */ + mi->last_stats_update = jiffies; ++ mi->sample_time = jiffies; } - static inline int --minstrel_ht_get_prob_ewma(struct minstrel_ht_sta *mi, int rate) -+minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) + static bool +-minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rate) ++minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ++ struct ieee80211_tx_rate *rate) { - int group = rate / MCS_GROUP_RATES; - rate %= MCS_GROUP_RATES; -- return mi->groups[group].rates[rate].prob_ewma; -+ return mi->groups[group].rates[rate].prob_avg; ++ int i; ++ + if (rate->idx < 0) + return false; + +@@ -807,40 +1112,23 @@ minstrel_ht_txstat_valid(struct minstrel_priv *mp, struct ieee80211_tx_rate *rat + rate->flags & IEEE80211_TX_RC_VHT_MCS) + return true; + +- return rate->idx == mp->cck_rates[0] || +- rate->idx == mp->cck_rates[1] || +- rate->idx == mp->cck_rates[2] || +- rate->idx == mp->cck_rates[3]; +-} ++ for (i = 0; i < ARRAY_SIZE(mp->cck_rates); i++) ++ if (rate->idx == mp->cck_rates[i]) ++ return true; + +-static void +-minstrel_set_next_sample_idx(struct minstrel_ht_sta *mi) +-{ +- struct minstrel_mcs_group_data *mg; ++ for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) ++ if (rate->idx == mp->ofdm_rates[mi->band][i]) ++ return true; + +- for (;;) { +- mi->sample_group++; +- mi->sample_group %= ARRAY_SIZE(minstrel_mcs_groups); +- mg = &mi->groups[mi->sample_group]; +- +- if (!mi->supported[mi->sample_group]) +- continue; +- +- if (++mg->index >= MCS_GROUP_RATES) { +- mg->index = 0; +- if (++mg->column >= ARRAY_SIZE(sample_table)) +- mg->column = 0; +- } +- break; +- } ++ return false; + } + + static void +-minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) ++minstrel_downgrade_prob_rate(struct minstrel_ht_sta *mi, u16 *idx) + { + int group, orig_group; + +- orig_group = group = *idx / MCS_GROUP_RATES; ++ orig_group = group = MI_RATE_GROUP(*idx); + while (group > 0) { + group--; + +@@ -851,11 +1139,7 @@ minstrel_downgrade_rate(struct minstrel_ht_sta *mi, u16 *idx, bool primary) + minstrel_mcs_groups[orig_group].streams) + continue; + +- if (primary) +- *idx = mi->groups[group].max_group_tp_rate[0]; +- else +- *idx = mi->groups[group].max_group_tp_rate[1]; +- break; ++ *idx = mi->groups[group].max_group_prob_rate; + } + } + +@@ -887,21 +1171,14 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, + void *priv_sta, struct ieee80211_tx_status *st) + { + struct ieee80211_tx_info *info = st->info; +- struct minstrel_ht_sta_priv *msp = priv_sta; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = priv_sta; + struct ieee80211_tx_rate *ar = info->status.rates; +- struct minstrel_rate_stats *rate, *rate2, *rate_sample = NULL; ++ struct minstrel_rate_stats *rate; + struct minstrel_priv *mp = priv; +- u32 update_interval = mp->update_interval / 2; ++ u32 update_interval = mp->update_interval; + bool last, update = false; +- bool sample_status = false; + int i; + +- if (!msp->is_ht) +- return mac80211_minstrel.tx_status_ext(priv, sband, +- &msp->legacy, st); +- +- + /* This packet was aggregated but doesn't carry status info */ + if ((info->flags & IEEE80211_TX_CTL_AMPDU) && + !(info->flags & IEEE80211_TX_STAT_AMPDU)) +@@ -913,87 +1190,49 @@ minstrel_ht_tx_status(void *priv, struct ieee80211_supported_band *sband, + info->status.ampdu_len = 1; + } + +- mi->ampdu_packets++; +- mi->ampdu_len += info->status.ampdu_len; +- +- if (!mi->sample_wait && !mi->sample_tries && mi->sample_count > 0) { +- int avg_ampdu_len = minstrel_ht_avg_ampdu_len(mi); +- +- mi->sample_wait = 16 + 2 * avg_ampdu_len; +- mi->sample_tries = 1; +- mi->sample_count--; ++ /* wraparound */ ++ if (mi->total_packets >= ~0 - info->status.ampdu_len) { ++ mi->total_packets = 0; ++ mi->sample_packets = 0; + } + ++ mi->total_packets += info->status.ampdu_len; + if (info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE) + mi->sample_packets += info->status.ampdu_len; + +- if (mi->sample_mode != MINSTREL_SAMPLE_IDLE) +- rate_sample = minstrel_get_ratestats(mi, mi->sample_rate); ++ mi->ampdu_packets++; ++ mi->ampdu_len += info->status.ampdu_len; + +- last = !minstrel_ht_txstat_valid(mp, &ar[0]); ++ last = !minstrel_ht_txstat_valid(mp, mi, &ar[0]); + for (i = 0; !last; i++) { + last = (i == IEEE80211_TX_MAX_RATES - 1) || +- !minstrel_ht_txstat_valid(mp, &ar[i + 1]); ++ !minstrel_ht_txstat_valid(mp, mi, &ar[i + 1]); + + rate = minstrel_ht_get_stats(mp, mi, &ar[i]); +- if (rate == rate_sample) +- sample_status = true; +- + if (last) + rate->success += info->status.ampdu_ack_len; + + rate->attempts += ar[i].count * info->status.ampdu_len; + } + +- switch (mi->sample_mode) { +- case MINSTREL_SAMPLE_IDLE: +- if (mp->new_avg && +- (mp->hw->max_rates > 1 || +- mi->total_packets_cur < SAMPLE_SWITCH_THR)) +- update_interval /= 2; +- break; +- +- case MINSTREL_SAMPLE_ACTIVE: +- if (!sample_status) +- break; +- +- mi->sample_mode = MINSTREL_SAMPLE_PENDING; +- update = true; +- break; +- +- case MINSTREL_SAMPLE_PENDING: +- if (sample_status) +- break; +- +- update = true; +- minstrel_ht_update_stats(mp, mi, false); +- break; +- } +- +- + if (mp->hw->max_rates > 1) { + /* + * check for sudden death of spatial multiplexing, + * downgrade to a lower number of streams if necessary. ++ * only do this for the max_prob_rate to prevent spurious ++ * rate fluctuations when the link changes suddenly + */ +- rate = minstrel_get_ratestats(mi, mi->max_tp_rate[0]); ++ rate = minstrel_get_ratestats(mi, mi->max_prob_rate); + if (rate->attempts > 30 && + rate->success < rate->attempts / 4) { +- minstrel_downgrade_rate(mi, &mi->max_tp_rate[0], true); +- update = true; +- } +- +- rate2 = minstrel_get_ratestats(mi, mi->max_tp_rate[1]); +- if (rate2->attempts > 30 && +- rate2->success < rate2->attempts / 4) { +- minstrel_downgrade_rate(mi, &mi->max_tp_rate[1], false); ++ minstrel_downgrade_prob_rate(mi, &mi->max_prob_rate); + update = true; + } + } + + if (time_after(jiffies, mi->last_stats_update + update_interval)) { + update = true; +- minstrel_ht_update_stats(mp, mi, true); ++ minstrel_ht_update_stats(mp, mi); + } + + if (update) +@@ -1031,7 +1270,10 @@ minstrel_calc_retransmit(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + ctime += (t_slot * cw) >> 1; + cw = min((cw << 1) | 1, mp->cw_max); + +- if (index / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) { ++ if (minstrel_ht_is_legacy_group(MI_RATE_GROUP(index))) { ++ overhead = mi->overhead_legacy; ++ overhead_rtscts = mi->overhead_legacy_rtscts; ++ } else { + overhead = mi->overhead; + overhead_rtscts = mi->overhead_rtscts; + } +@@ -1061,7 +1303,8 @@ static void + minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + struct ieee80211_sta_rates *ratetbl, int offset, int index) + { +- const struct mcs_group *group = &minstrel_mcs_groups[index / MCS_GROUP_RATES]; ++ int group_idx = MI_RATE_GROUP(index); ++ const struct mcs_group *group = &minstrel_mcs_groups[group_idx]; + struct minstrel_rate_stats *mrs; + u8 idx; + u16 flags = group->flags; +@@ -1080,13 +1323,17 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + ratetbl->rate[offset].count_rts = mrs->retry_count_rtscts; + } + +- if (index / MCS_GROUP_RATES == MINSTREL_CCK_GROUP) ++ index = MI_RATE_IDX(index); ++ if (group_idx == MINSTREL_CCK_GROUP) + idx = mp->cck_rates[index % ARRAY_SIZE(mp->cck_rates)]; ++ else if (group_idx == MINSTREL_OFDM_GROUP) ++ idx = mp->ofdm_rates[mi->band][index % ++ ARRAY_SIZE(mp->ofdm_rates[0])]; + else if (flags & IEEE80211_TX_RC_VHT_MCS) + idx = ((group->streams - 1) << 4) | +- ((index % MCS_GROUP_RATES) & 0xF); ++ (index & 0xF); + else +- idx = index % MCS_GROUP_RATES + (group->streams - 1) * 8; ++ idx = index + (group->streams - 1) * 8; + + /* enable RTS/CTS if needed: + * - if station is in dynamic SMPS (and streams > 1) +@@ -1106,17 +1353,17 @@ minstrel_ht_set_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + static inline int + minstrel_ht_get_prob_avg(struct minstrel_ht_sta *mi, int rate) + { +- int group = rate / MCS_GROUP_RATES; +- rate %= MCS_GROUP_RATES; ++ int group = MI_RATE_GROUP(rate); ++ rate = MI_RATE_IDX(rate); + return mi->groups[group].rates[rate].prob_avg; } static int -@@ -1115,7 +1119,7 @@ minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) + minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) + { +- int group = mi->max_prob_rate / MCS_GROUP_RATES; ++ int group = MI_RATE_GROUP(mi->max_prob_rate); + const struct mcs_group *g = &minstrel_mcs_groups[group]; +- int rate = mi->max_prob_rate % MCS_GROUP_RATES; ++ int rate = MI_RATE_IDX(mi->max_prob_rate); unsigned int duration; /* Disable A-MSDU if max_prob_rate is bad */ -- if (mi->groups[group].rates[rate].prob_ewma < MINSTREL_FRAC(50, 100)) -+ if (mi->groups[group].rates[rate].prob_avg < MINSTREL_FRAC(50, 100)) - return 1; +@@ -1164,18 +1411,14 @@ static void + minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { + struct ieee80211_sta_rates *rates; +- u16 first_rate = mi->max_tp_rate[0]; + int i = 0; - duration = g->duration[rate]; -@@ -1138,7 +1142,7 @@ minstrel_ht_get_max_amsdu_len(struct minstrel_ht_sta *mi) - * data packet size - */ - if (duration > MCS_DURATION(1, 0, 260) || -- (minstrel_ht_get_prob_ewma(mi, mi->max_tp_rate[0]) < -+ (minstrel_ht_get_prob_avg(mi, mi->max_tp_rate[0]) < - MINSTREL_FRAC(75, 100))) - return 3200; +- if (mi->sample_mode == MINSTREL_SAMPLE_ACTIVE) +- first_rate = mi->sample_rate; +- + rates = kzalloc(sizeof(*rates), GFP_ATOMIC); + if (!rates) + return; -@@ -1243,7 +1247,7 @@ minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) - * rate, to avoid wasting airtime. - */ - sample_dur = minstrel_get_duration(sample_idx); -- if (mrs->prob_ewma > MINSTREL_FRAC(95, 100) || -+ if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || - minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) - return -1; + /* Start with max_tp_rate[0] */ +- minstrel_ht_set_rate(mp, mi, rates, i++, first_rate); ++ minstrel_ht_set_rate(mp, mi, rates, i++, mi->max_tp_rate[0]); -@@ -1666,7 +1670,8 @@ minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) + if (mp->hw->max_rates >= 3) { + /* At least 3 tx rates supported, use max_tp_rate[1] next */ +@@ -1191,102 +1434,20 @@ minstrel_ht_update_rates(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + rate_control_set_rates(mp->hw, mi->sta, rates); + } + +-static int +-minstrel_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) ++static u16 ++minstrel_ht_get_sample_rate(struct minstrel_priv *mp, struct minstrel_ht_sta *mi) + { +- struct minstrel_rate_stats *mrs; +- struct minstrel_mcs_group_data *mg; +- unsigned int sample_dur, sample_group, cur_max_tp_streams; +- int tp_rate1, tp_rate2; +- int sample_idx = 0; +- +- if (mp->hw->max_rates == 1 && mp->sample_switch && +- (mi->total_packets_cur >= SAMPLE_SWITCH_THR || +- mp->sample_switch == 1)) +- return -1; +- +- if (mi->sample_wait > 0) { +- mi->sample_wait--; +- return -1; +- } +- +- if (!mi->sample_tries) +- return -1; +- +- sample_group = mi->sample_group; +- mg = &mi->groups[sample_group]; +- sample_idx = sample_table[mg->column][mg->index]; +- minstrel_set_next_sample_idx(mi); ++ u8 seq; + +- if (!(mi->supported[sample_group] & BIT(sample_idx))) +- return -1; +- +- mrs = &mg->rates[sample_idx]; +- sample_idx += sample_group * MCS_GROUP_RATES; +- +- /* Set tp_rate1, tp_rate2 to the highest / second highest max_tp_rate */ +- if (minstrel_get_duration(mi->max_tp_rate[0]) > +- minstrel_get_duration(mi->max_tp_rate[1])) { +- tp_rate1 = mi->max_tp_rate[1]; +- tp_rate2 = mi->max_tp_rate[0]; ++ if (mp->hw->max_rates > 1) { ++ seq = mi->sample_seq; ++ mi->sample_seq = (seq + 1) % ARRAY_SIZE(minstrel_sample_seq); ++ seq = minstrel_sample_seq[seq]; + } else { +- tp_rate1 = mi->max_tp_rate[0]; +- tp_rate2 = mi->max_tp_rate[1]; ++ seq = MINSTREL_SAMPLE_TYPE_INC; + } + +- /* +- * Sampling might add some overhead (RTS, no aggregation) +- * to the frame. Hence, don't use sampling for the highest currently +- * used highest throughput or probability rate. +- */ +- if (sample_idx == mi->max_tp_rate[0] || sample_idx == mi->max_prob_rate) +- return -1; +- +- /* +- * Do not sample if the probability is already higher than 95%, +- * or if the rate is 3 times slower than the current max probability +- * rate, to avoid wasting airtime. +- */ +- sample_dur = minstrel_get_duration(sample_idx); +- if (mrs->prob_avg > MINSTREL_FRAC(95, 100) || +- minstrel_get_duration(mi->max_prob_rate) * 3 < sample_dur) +- return -1; +- +- +- /* +- * For devices with no configurable multi-rate retry, skip sampling +- * below the per-group max throughput rate, and only use one sampling +- * attempt per rate +- */ +- if (mp->hw->max_rates == 1 && +- (minstrel_get_duration(mg->max_group_tp_rate[0]) < sample_dur || +- mrs->attempts)) +- return -1; +- +- /* Skip already sampled slow rates */ +- if (sample_dur >= minstrel_get_duration(tp_rate1) && mrs->attempts) +- return -1; +- +- /* +- * Make sure that lower rates get sampled only occasionally, +- * if the link is working perfectly. +- */ +- +- cur_max_tp_streams = minstrel_mcs_groups[tp_rate1 / +- MCS_GROUP_RATES].streams; +- if (sample_dur >= minstrel_get_duration(tp_rate2) && +- (cur_max_tp_streams - 1 < +- minstrel_mcs_groups[sample_group].streams || +- sample_dur >= minstrel_get_duration(mi->max_prob_rate))) { +- if (mrs->sample_skipped < 20) +- return -1; +- +- if (mi->sample_slow++ > 2) +- return -1; +- } +- mi->sample_tries--; +- +- return sample_idx; ++ return __minstrel_ht_get_sample_rate(mi, seq); + } + + static void +@@ -1296,16 +1457,12 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + const struct mcs_group *sample_group; + struct ieee80211_tx_info *info = IEEE80211_SKB_CB(txrc->skb); + struct ieee80211_tx_rate *rate = &info->status.rates[0]; +- struct minstrel_ht_sta_priv *msp = priv_sta; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = priv_sta; + struct minstrel_priv *mp = priv; +- int sample_idx; +- +- if (!msp->is_ht) +- return mac80211_minstrel.get_rate(priv, sta, &msp->legacy, txrc); ++ u16 sample_idx; + + if (!(info->flags & IEEE80211_TX_CTL_AMPDU) && +- mi->max_prob_rate / MCS_GROUP_RATES != MINSTREL_CCK_GROUP) ++ !minstrel_ht_is_legacy_group(MI_RATE_GROUP(mi->max_prob_rate))) + minstrel_aggr_check(sta, txrc->skb); + + info->flags |= mi->tx_flags; +@@ -1318,23 +1475,18 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + /* Don't use EAPOL frames for sampling on non-mrr hw */ + if (mp->hw->max_rates == 1 && + (info->control.flags & IEEE80211_TX_CTRL_PORT_CTRL_PROTO)) +- sample_idx = -1; +- else +- sample_idx = minstrel_get_sample_rate(mp, mi); +- +- mi->total_packets++; ++ return; + +- /* wraparound */ +- if (mi->total_packets == ~0) { +- mi->total_packets = 0; +- mi->sample_packets = 0; +- } ++ if (time_is_before_jiffies(mi->sample_time)) ++ return; + +- if (sample_idx < 0) ++ mi->sample_time = jiffies + MINSTREL_SAMPLE_INTERVAL; ++ sample_idx = minstrel_ht_get_sample_rate(mp, mi); ++ if (!sample_idx) + return; + +- sample_group = &minstrel_mcs_groups[sample_idx / MCS_GROUP_RATES]; +- sample_idx %= MCS_GROUP_RATES; ++ sample_group = &minstrel_mcs_groups[MI_RATE_GROUP(sample_idx)]; ++ sample_idx = MI_RATE_IDX(sample_idx); + + if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP] && + (sample_idx >= 4) != txrc->short_preamble) +@@ -1346,8 +1498,11 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta, + if (sample_group == &minstrel_mcs_groups[MINSTREL_CCK_GROUP]) { + int idx = sample_idx % ARRAY_SIZE(mp->cck_rates); + rate->idx = mp->cck_rates[idx]; ++ } else if (sample_group == &minstrel_mcs_groups[MINSTREL_OFDM_GROUP]) { ++ int idx = sample_idx % ARRAY_SIZE(mp->ofdm_rates[0]); ++ rate->idx = mp->ofdm_rates[mi->band][idx]; + } else if (sample_group->flags & IEEE80211_TX_RC_VHT_MCS) { +- ieee80211_rate_set_vht(rate, sample_idx % MCS_GROUP_RATES, ++ ieee80211_rate_set_vht(rate, MI_RATE_IDX(sample_idx), + sample_group->streams); + } else { + rate->idx = sample_idx + (sample_group->streams - 1) * 8; +@@ -1366,44 +1521,59 @@ minstrel_ht_update_cck(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, + if (sband->band != NL80211_BAND_2GHZ) + return; + +- if (!ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) ++ if (sta->ht_cap.ht_supported && ++ !ieee80211_hw_check(mp->hw, SUPPORTS_HT_CCK_RATES)) + return; + +- mi->cck_supported = 0; +- mi->cck_supported_short = 0; + for (i = 0; i < 4; i++) { +- if (!rate_supported(sta, sband->band, mp->cck_rates[i])) ++ if (mp->cck_rates[i] == 0xff || ++ !rate_supported(sta, sband->band, mp->cck_rates[i])) + continue; + +- mi->cck_supported |= BIT(i); ++ mi->supported[MINSTREL_CCK_GROUP] |= BIT(i); + if (sband->bitrates[i].flags & IEEE80211_RATE_SHORT_PREAMBLE) +- mi->cck_supported_short |= BIT(i); ++ mi->supported[MINSTREL_CCK_GROUP] |= BIT(i + 4); + } ++} ++ ++static void ++minstrel_ht_update_ofdm(struct minstrel_priv *mp, struct minstrel_ht_sta *mi, ++ struct ieee80211_supported_band *sband, ++ struct ieee80211_sta *sta) ++{ ++ const u8 *rates; ++ int i; + +- mi->supported[MINSTREL_CCK_GROUP] = mi->cck_supported; ++ if (sta->ht_cap.ht_supported) ++ return; ++ ++ rates = mp->ofdm_rates[sband->band]; ++ for (i = 0; i < ARRAY_SIZE(mp->ofdm_rates[0]); i++) { ++ if (rates[i] == 0xff || ++ !rate_supported(sta, sband->band, rates[i])) ++ continue; ++ ++ mi->supported[MINSTREL_OFDM_GROUP] |= BIT(i); ++ } + } + + static void + minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + struct cfg80211_chan_def *chandef, +- struct ieee80211_sta *sta, void *priv_sta) ++ struct ieee80211_sta *sta, void *priv_sta) + { + struct minstrel_priv *mp = priv; +- struct minstrel_ht_sta_priv *msp = priv_sta; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = priv_sta; + struct ieee80211_mcs_info *mcs = &sta->ht_cap.mcs; + u16 ht_cap = sta->ht_cap.cap; + struct ieee80211_sta_vht_cap *vht_cap = &sta->vht_cap; ++ const struct ieee80211_rate *ctl_rate; ++ bool ldpc, erp; + int use_vht; + int n_supported = 0; + int ack_dur; + int stbc; + int i; +- bool ldpc; +- +- /* fall back to the old minstrel for legacy stations */ +- if (!sta->ht_cap.ht_supported) +- goto use_legacy; + + BUILD_BUG_ON(ARRAY_SIZE(minstrel_mcs_groups) != MINSTREL_GROUPS_NB); + +@@ -1412,10 +1582,10 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + else + use_vht = 0; + +- msp->is_ht = true; + memset(mi, 0, sizeof(*mi)); + + mi->sta = sta; ++ mi->band = sband->band; + mi->last_stats_update = jiffies; + + ack_dur = ieee80211_frame_duration(sband->band, 10, 60, 1, 1, 0); +@@ -1423,17 +1593,15 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + mi->overhead += ack_dur; + mi->overhead_rtscts = mi->overhead + 2 * ack_dur; + +- mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); ++ ctl_rate = &sband->bitrates[rate_lowest_index(sband, sta)]; ++ erp = ctl_rate->flags & IEEE80211_RATE_ERP_G; ++ ack_dur = ieee80211_frame_duration(sband->band, 10, ++ ctl_rate->bitrate, erp, 1, ++ ieee80211_chandef_get_shift(chandef)); ++ mi->overhead_legacy = ack_dur; ++ mi->overhead_legacy_rtscts = mi->overhead_legacy + 2 * ack_dur; + +- /* When using MRR, sample more on the first attempt, without delay */ +- if (mp->has_mrr) { +- mi->sample_count = 16; +- mi->sample_wait = 0; +- } else { +- mi->sample_count = 8; +- mi->sample_wait = 8; +- } +- mi->sample_tries = 4; ++ mi->avg_ampdu_len = MINSTREL_FRAC(1, 1); + + if (!use_vht) { + stbc = (ht_cap & IEEE80211_HT_CAP_RX_STBC) >> +@@ -1456,10 +1624,8 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + int bw, nss; + + mi->supported[i] = 0; +- if (i == MINSTREL_CCK_GROUP) { +- minstrel_ht_update_cck(mp, mi, sband, sta); ++ if (minstrel_ht_is_legacy_group(i)) + continue; +- } + + if (gflags & IEEE80211_TX_RC_SHORT_GI) { + if (gflags & IEEE80211_TX_RC_40_MHZ_WIDTH) { +@@ -1520,24 +1686,12 @@ minstrel_ht_update_caps(void *priv, struct ieee80211_supported_band *sband, + n_supported++; + } + +- if (!n_supported) +- goto use_legacy; +- +- mi->supported[MINSTREL_CCK_GROUP] |= mi->cck_supported_short << 4; ++ minstrel_ht_update_cck(mp, mi, sband, sta); ++ minstrel_ht_update_ofdm(mp, mi, sband, sta); + + /* create an initial rate table with the lowest supported rates */ +- minstrel_ht_update_stats(mp, mi, true); ++ minstrel_ht_update_stats(mp, mi); + minstrel_ht_update_rates(mp, mi); +- +- return; +- +-use_legacy: +- msp->is_ht = false; +- memset(&msp->legacy, 0, sizeof(msp->legacy)); +- msp->legacy.r = msp->ratelist; +- msp->legacy.sample_table = msp->sample_table; +- return mac80211_minstrel.rate_init(priv, sband, chandef, sta, +- &msp->legacy); + } + + static void +@@ -1561,7 +1715,7 @@ static void * + minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) + { + struct ieee80211_supported_band *sband; +- struct minstrel_ht_sta_priv *msp; ++ struct minstrel_ht_sta *mi; + struct minstrel_priv *mp = priv; + struct ieee80211_hw *hw = mp->hw; + int max_rates = 0; +@@ -1573,91 +1727,91 @@ minstrel_ht_alloc_sta(void *priv, struct ieee80211_sta *sta, gfp_t gfp) + max_rates = sband->n_bitrates; + } + +- msp = kzalloc(sizeof(*msp), gfp); +- if (!msp) +- return NULL; +- +- msp->ratelist = kcalloc(max_rates, sizeof(struct minstrel_rate), gfp); +- if (!msp->ratelist) +- goto error; +- +- msp->sample_table = kmalloc_array(max_rates, SAMPLE_COLUMNS, gfp); +- if (!msp->sample_table) +- goto error1; +- +- return msp; +- +-error1: +- kfree(msp->ratelist); +-error: +- kfree(msp); +- return NULL; ++ return kzalloc(sizeof(*mi), gfp); + } + + static void + minstrel_ht_free_sta(void *priv, struct ieee80211_sta *sta, void *priv_sta) + { +- struct minstrel_ht_sta_priv *msp = priv_sta; +- +- kfree(msp->sample_table); +- kfree(msp->ratelist); +- kfree(msp); ++ kfree(priv_sta); + } + + static void +-minstrel_ht_init_cck_rates(struct minstrel_priv *mp) ++minstrel_ht_fill_rate_array(u8 *dest, struct ieee80211_supported_band *sband, ++ const s16 *bitrates, int n_rates, u32 rate_flags) + { +- static const int bitrates[4] = { 10, 20, 55, 110 }; +- struct ieee80211_supported_band *sband; +- u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); + int i, j; + +- sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; +- if (!sband) +- return; +- + for (i = 0; i < sband->n_bitrates; i++) { + struct ieee80211_rate *rate = &sband->bitrates[i]; + +- if (rate->flags & IEEE80211_RATE_ERP_G) +- continue; +- + if ((rate_flags & sband->bitrates[i].flags) != rate_flags) + continue; + +- for (j = 0; j < ARRAY_SIZE(bitrates); j++) { ++ for (j = 0; j < n_rates; j++) { + if (rate->bitrate != bitrates[j]) + continue; + +- mp->cck_rates[j] = i; ++ dest[j] = i; + break; + } + } + } + ++static void ++minstrel_ht_init_cck_rates(struct minstrel_priv *mp) ++{ ++ static const s16 bitrates[4] = { 10, 20, 55, 110 }; ++ struct ieee80211_supported_band *sband; ++ u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); ++ ++ memset(mp->cck_rates, 0xff, sizeof(mp->cck_rates)); ++ sband = mp->hw->wiphy->bands[NL80211_BAND_2GHZ]; ++ if (!sband) ++ return; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(mp->cck_rates) != ARRAY_SIZE(bitrates)); ++ minstrel_ht_fill_rate_array(mp->cck_rates, sband, ++ minstrel_cck_bitrates, ++ ARRAY_SIZE(minstrel_cck_bitrates), ++ rate_flags); ++} ++ ++static void ++minstrel_ht_init_ofdm_rates(struct minstrel_priv *mp, enum nl80211_band band) ++{ ++ static const s16 bitrates[8] = { 60, 90, 120, 180, 240, 360, 480, 540 }; ++ struct ieee80211_supported_band *sband; ++ u32 rate_flags = ieee80211_chandef_rate_flags(&mp->hw->conf.chandef); ++ ++ memset(mp->ofdm_rates[band], 0xff, sizeof(mp->ofdm_rates[band])); ++ sband = mp->hw->wiphy->bands[band]; ++ if (!sband) ++ return; ++ ++ BUILD_BUG_ON(ARRAY_SIZE(mp->ofdm_rates[band]) != ARRAY_SIZE(bitrates)); ++ minstrel_ht_fill_rate_array(mp->ofdm_rates[band], sband, ++ minstrel_ofdm_bitrates, ++ ARRAY_SIZE(minstrel_ofdm_bitrates), ++ rate_flags); ++} ++ + static void * + minstrel_ht_alloc(struct ieee80211_hw *hw) + { + struct minstrel_priv *mp; ++ int i; + + mp = kzalloc(sizeof(struct minstrel_priv), GFP_ATOMIC); + if (!mp) + return NULL; + +- mp->sample_switch = -1; +- + /* contention window settings + * Just an approximation. Using the per-queue values would complicate + * the calculations and is probably unnecessary */ + mp->cw_min = 15; + mp->cw_max = 1023; + +- /* number of packets (in %) to use for sampling other rates +- * sample less often for non-mrr packets, because the overhead +- * is much higher than with mrr */ +- mp->lookaround_rate = 5; +- mp->lookaround_rate_mrr = 10; +- + /* maximum time that the hw is allowed to stay in one MRR segment */ + mp->segment_size = 6000; + +@@ -1671,10 +1825,11 @@ minstrel_ht_alloc(struct ieee80211_hw *hw) mp->has_mrr = true; mp->hw = hw; -- mp->update_interval = 100; -+ mp->update_interval = HZ / 10; -+ mp->new_avg = true; - - #ifdef CPTCFG_MAC80211_DEBUGFS - mp->fixed_rate_idx = (u32) -1; -@@ -1674,6 +1679,8 @@ minstrel_ht_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir) - &mp->fixed_rate_idx); - debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, - &mp->sample_switch); -+ debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir, -+ &mp->new_avg); - #endif +- mp->update_interval = HZ / 10; +- mp->new_avg = true; ++ mp->update_interval = HZ / 20; minstrel_ht_init_cck_rates(mp); -@@ -1698,7 +1705,7 @@ static u32 minstrel_ht_get_expected_throughput(void *priv_sta) ++ for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++) ++ minstrel_ht_init_ofdm_rates(mp, i); - i = mi->max_tp_rate[0] / MCS_GROUP_RATES; - j = mi->max_tp_rate[0] % MCS_GROUP_RATES; -- prob = mi->groups[i].rates[j].prob_ewma; -+ prob = mi->groups[i].rates[j].prob_avg; + return mp; + } +@@ -1688,10 +1843,6 @@ static void minstrel_ht_add_debugfs(struct ieee80211_hw *hw, void *priv, + mp->fixed_rate_idx = (u32) -1; + debugfs_create_u32("fixed_rate_idx", S_IRUGO | S_IWUGO, debugfsdir, + &mp->fixed_rate_idx); +- debugfs_create_u32("sample_switch", S_IRUGO | S_IWUSR, debugfsdir, +- &mp->sample_switch); +- debugfs_create_bool("new_avg", S_IRUGO | S_IWUSR, debugfsdir, +- &mp->new_avg); + } + #endif + +@@ -1703,15 +1854,11 @@ minstrel_ht_free(void *priv) + + static u32 minstrel_ht_get_expected_throughput(void *priv_sta) + { +- struct minstrel_ht_sta_priv *msp = priv_sta; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = priv_sta; + int i, j, prob, tp_avg; + +- if (!msp->is_ht) +- return mac80211_minstrel.get_expected_throughput(priv_sta); +- +- i = mi->max_tp_rate[0] / MCS_GROUP_RATES; +- j = mi->max_tp_rate[0] % MCS_GROUP_RATES; ++ i = MI_RATE_GROUP(mi->max_tp_rate[0]); ++ j = MI_RATE_IDX(mi->max_tp_rate[0]); + prob = mi->groups[i].rates[j].prob_avg; /* convert tp_avg from pkt per second in kbps */ - tp_avg = minstrel_ht_get_tp_avg(mi, i, j, prob) * 10; diff --git a/net/mac80211/rc80211_minstrel_ht.h b/net/mac80211/rc80211_minstrel_ht.h -index f938701..53ea3c2 100644 +index 53ea3c2..a5b56e5 100644 --- a/net/mac80211/rc80211_minstrel_ht.h +++ b/net/mac80211/rc80211_minstrel_ht.h -@@ -119,6 +119,6 @@ struct minstrel_ht_sta_priv { +@@ -6,6 +6,35 @@ + #ifndef __RC_MINSTREL_HT_H + #define __RC_MINSTREL_HT_H ++#include ++ ++/* number of highest throughput rates to consider*/ ++#define MAX_THR_RATES 4 ++#define SAMPLE_COLUMNS 10 /* number of columns in sample table */ ++ ++/* scaled fraction values */ ++#define MINSTREL_SCALE 12 ++#define MINSTREL_FRAC(val, div) (((val) << MINSTREL_SCALE) / div) ++#define MINSTREL_TRUNC(val) ((val) >> MINSTREL_SCALE) ++ ++#define EWMA_LEVEL 96 /* ewma weighting factor [/EWMA_DIV] */ ++#define EWMA_DIV 128 ++ ++/* ++ * Coefficients for moving average with noise filter (period=16), ++ * scaled by 10 bits ++ * ++ * a1 = exp(-pi * sqrt(2) / period) ++ * coeff2 = 2 * a1 * cos(sqrt(2) * 2 * pi / period) ++ * coeff3 = -sqr(a1) ++ * coeff1 = 1 - coeff2 - coeff3 ++ */ ++#define MINSTREL_AVG_COEFF1 (MINSTREL_FRAC(1, 1) - \ ++ MINSTREL_AVG_COEFF2 - \ ++ MINSTREL_AVG_COEFF3) ++#define MINSTREL_AVG_COEFF2 0x00001499 ++#define MINSTREL_AVG_COEFF3 -0x0000092e ++ + /* + * The number of streams can be changed to 2 to reduce code + * size and memory footprint. +@@ -18,17 +47,55 @@ + MINSTREL_HT_STREAM_GROUPS) + #define MINSTREL_VHT_GROUPS_NB (MINSTREL_MAX_STREAMS * \ + MINSTREL_VHT_STREAM_GROUPS) +-#define MINSTREL_CCK_GROUPS_NB 1 ++#define MINSTREL_LEGACY_GROUPS_NB 2 + #define MINSTREL_GROUPS_NB (MINSTREL_HT_GROUPS_NB + \ + MINSTREL_VHT_GROUPS_NB + \ +- MINSTREL_CCK_GROUPS_NB) ++ MINSTREL_LEGACY_GROUPS_NB) + + #define MINSTREL_HT_GROUP_0 0 + #define MINSTREL_CCK_GROUP (MINSTREL_HT_GROUP_0 + MINSTREL_HT_GROUPS_NB) +-#define MINSTREL_VHT_GROUP_0 (MINSTREL_CCK_GROUP + 1) ++#define MINSTREL_OFDM_GROUP (MINSTREL_CCK_GROUP + 1) ++#define MINSTREL_VHT_GROUP_0 (MINSTREL_OFDM_GROUP + 1) + + #define MCS_GROUP_RATES 10 + ++#define MI_RATE_IDX_MASK GENMASK(3, 0) ++#define MI_RATE_GROUP_MASK GENMASK(15, 4) ++ ++#define MI_RATE(_group, _idx) \ ++ (FIELD_PREP(MI_RATE_GROUP_MASK, _group) | \ ++ FIELD_PREP(MI_RATE_IDX_MASK, _idx)) ++ ++#define MI_RATE_IDX(_rate) FIELD_GET(MI_RATE_IDX_MASK, _rate) ++#define MI_RATE_GROUP(_rate) FIELD_GET(MI_RATE_GROUP_MASK, _rate) ++ ++#define MINSTREL_SAMPLE_RATES 5 /* rates per sample type */ ++#define MINSTREL_SAMPLE_INTERVAL (HZ / 50) ++ ++struct minstrel_priv { ++ struct ieee80211_hw *hw; ++ bool has_mrr; ++ unsigned int cw_min; ++ unsigned int cw_max; ++ unsigned int max_retry; ++ unsigned int segment_size; ++ unsigned int update_interval; ++ ++ u8 cck_rates[4]; ++ u8 ofdm_rates[NUM_NL80211_BANDS][8]; ++ ++#ifdef CPTCFG_MAC80211_DEBUGFS ++ /* ++ * enable fixed rate processing per RC ++ * - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx ++ * - write -1 to enable RC processing again ++ * - setting will be applied on next update ++ */ ++ u32 fixed_rate_idx; ++#endif ++}; ++ ++ + struct mcs_group { + u16 flags; + u8 streams; +@@ -37,8 +104,36 @@ struct mcs_group { + u16 duration[MCS_GROUP_RATES]; + }; + ++extern const s16 minstrel_cck_bitrates[4]; ++extern const s16 minstrel_ofdm_bitrates[8]; + extern const struct mcs_group minstrel_mcs_groups[]; + ++struct minstrel_rate_stats { ++ /* current / last sampling period attempts/success counters */ ++ u16 attempts, last_attempts; ++ u16 success, last_success; ++ ++ /* total attempts/success counters */ ++ u32 att_hist, succ_hist; ++ ++ /* prob_avg - moving average of prob */ ++ u16 prob_avg; ++ u16 prob_avg_1; ++ ++ /* maximum retry counts */ ++ u8 retry_count; ++ u8 retry_count_rtscts; ++ ++ bool retry_updated; ++}; ++ ++enum minstrel_sample_type { ++ MINSTREL_SAMPLE_TYPE_INC, ++ MINSTREL_SAMPLE_TYPE_JUMP, ++ MINSTREL_SAMPLE_TYPE_SLOW, ++ __MINSTREL_SAMPLE_TYPE_MAX ++}; ++ + struct minstrel_mcs_group_data { + u8 index; + u8 column; +@@ -51,10 +146,10 @@ struct minstrel_mcs_group_data { + struct minstrel_rate_stats rates[MCS_GROUP_RATES]; + }; + +-enum minstrel_sample_mode { +- MINSTREL_SAMPLE_IDLE, +- MINSTREL_SAMPLE_ACTIVE, +- MINSTREL_SAMPLE_PENDING, ++struct minstrel_sample_category { ++ u8 sample_group; ++ u16 sample_rates[MINSTREL_SAMPLE_RATES]; ++ u16 cur_sample_rates[MINSTREL_SAMPLE_RATES]; + }; + + struct minstrel_ht_sta { +@@ -77,28 +172,22 @@ struct minstrel_ht_sta { + /* overhead time in usec for each frame */ + unsigned int overhead; + unsigned int overhead_rtscts; ++ unsigned int overhead_legacy; ++ unsigned int overhead_legacy_rtscts; + +- unsigned int total_packets_last; +- unsigned int total_packets_cur; + unsigned int total_packets; + unsigned int sample_packets; + + /* tx flags to add for frames for this sta */ + u32 tx_flags; + +- u8 sample_wait; +- u8 sample_tries; +- u8 sample_count; +- u8 sample_slow; ++ u8 band; + +- enum minstrel_sample_mode sample_mode; ++ u8 sample_seq; + u16 sample_rate; + +- /* current MCS group to be sampled */ +- u8 sample_group; +- +- u8 cck_supported; +- u8 cck_supported_short; ++ unsigned long sample_time; ++ struct minstrel_sample_category sample[__MINSTREL_SAMPLE_TYPE_MAX]; + + /* Bitfield of supported MCS rates of all groups */ + u16 supported[MINSTREL_GROUPS_NB]; +@@ -107,16 +196,6 @@ struct minstrel_ht_sta { + struct minstrel_mcs_group_data groups[MINSTREL_GROUPS_NB]; + }; + +-struct minstrel_ht_sta_priv { +- union { +- struct minstrel_ht_sta ht; +- struct minstrel_sta_info legacy; +- }; +- void *ratelist; +- void *sample_table; +- bool is_ht; +-}; +- void minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir); int minstrel_ht_get_tp_avg(struct minstrel_ht_sta *mi, int group, int rate, -- int prob_ewma); -+ int prob_avg); - - #endif + int prob_avg); diff --git a/net/mac80211/rc80211_minstrel_ht_debugfs.c b/net/mac80211/rc80211_minstrel_ht_debugfs.c -index 5a6e9f3..bebb719 100644 +index bebb719..25b8a67 100644 --- a/net/mac80211/rc80211_minstrel_ht_debugfs.c +++ b/net/mac80211/rc80211_minstrel_ht_debugfs.c -@@ -98,8 +98,8 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) - p += sprintf(p, "%6u ", tx_time); +@@ -9,9 +9,13 @@ + #include + #include + #include +-#include "rc80211_minstrel.h" + #include "rc80211_minstrel_ht.h" - tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); -- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); -- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); -+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg); -+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); - - p += sprintf(p, "%4u.%1u %4u.%1u %3u.%1u" - " %3u %3u %-3u " -@@ -243,8 +243,8 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) - p += sprintf(p, "%u,", tx_time); - - tp_max = minstrel_ht_get_tp_avg(mi, i, j, MINSTREL_FRAC(100, 100)); -- tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_ewma); -- eprob = MINSTREL_TRUNC(mrs->prob_ewma * 1000); -+ tp_avg = minstrel_ht_get_tp_avg(mi, i, j, mrs->prob_avg); -+ eprob = MINSTREL_TRUNC(mrs->prob_avg * 1000); - - p += sprintf(p, "%u.%u,%u.%u,%u.%u,%u,%u," - "%u,%llu,%llu,", -diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c -index c431722..ee72428 100644 ---- a/net/mac80211/sta_info.c -+++ b/net/mac80211/sta_info.c -@@ -210,6 +210,20 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, - return NULL; ++struct minstrel_debugfs_info { ++ size_t len; ++ char buf[]; ++}; ++ + static ssize_t + minstrel_stats_read(struct file *file, char __user *buf, size_t len, loff_t *ppos) + { +@@ -28,6 +32,18 @@ minstrel_stats_release(struct inode *inode, struct file *file) + return 0; } -+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, -+ const u8 *sta_addr, const u8 *vif_addr) ++static bool ++minstrel_ht_is_sample_rate(struct minstrel_ht_sta *mi, int idx) +{ -+ struct rhlist_head *tmp; -+ struct sta_info *sta; ++ int type, i; + -+ for_each_sta_info(local, sta_addr, sta, tmp) { -+ if (ether_addr_equal(vif_addr, sta->sdata->vif.addr)) -+ return sta; -+ } -+ -+ return NULL; ++ for (type = 0; type < ARRAY_SIZE(mi->sample); type++) ++ for (i = 0; i < MINSTREL_SAMPLE_RATES; i++) ++ if (mi->sample[type].cur_sample_rates[i] == idx) ++ return true; ++ return false; +} + - struct sta_info *sta_info_get_by_idx(struct ieee80211_sub_if_data *sdata, - int idx) + static char * + minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) { -@@ -324,6 +338,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, +@@ -52,8 +68,7 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) + + for (j = 0; j < MCS_GROUP_RATES; j++) { + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; +- static const int bitrates[4] = { 10, 20, 55, 110 }; +- int idx = i * MCS_GROUP_RATES + j; ++ int idx = MI_RATE(i, j); + unsigned int duration; + + if (!(mi->supported[i] & BIT(j))) +@@ -67,6 +82,9 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) + p += sprintf(p, "VHT%c0 ", htmode); + p += sprintf(p, "%cGI ", gimode); + p += sprintf(p, "%d ", mg->streams); ++ } else if (i == MINSTREL_OFDM_GROUP) { ++ p += sprintf(p, "OFDM "); ++ p += sprintf(p, "1 "); + } else { + p += sprintf(p, "CCK "); + p += sprintf(p, "%cP ", j < 4 ? 'L' : 'S'); +@@ -78,13 +96,19 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) + *(p++) = (idx == mi->max_tp_rate[2]) ? 'C' : ' '; + *(p++) = (idx == mi->max_tp_rate[3]) ? 'D' : ' '; + *(p++) = (idx == mi->max_prob_rate) ? 'P' : ' '; ++ *(p++) = minstrel_ht_is_sample_rate(mi, idx) ? 'S' : ' '; + + if (gflags & IEEE80211_TX_RC_MCS) { + p += sprintf(p, " MCS%-2u", (mg->streams - 1) * 8 + j); + } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { + p += sprintf(p, " MCS%-1u/%1u", j, mg->streams); + } else { +- int r = bitrates[j % 4]; ++ int r; ++ ++ if (i == MINSTREL_OFDM_GROUP) ++ r = minstrel_ofdm_bitrates[j % 8]; ++ else ++ r = minstrel_cck_bitrates[j % 4]; + + p += sprintf(p, " %2u.%1uM", r / 10, r % 10); + } +@@ -120,20 +144,11 @@ minstrel_ht_stats_dump(struct minstrel_ht_sta *mi, int i, char *p) + static int + minstrel_ht_stats_open(struct inode *inode, struct file *file) + { +- struct minstrel_ht_sta_priv *msp = inode->i_private; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = inode->i_private; + struct minstrel_debugfs_info *ms; + unsigned int i; +- int ret; + char *p; + +- if (!msp->is_ht) { +- inode->i_private = &msp->legacy; +- ret = minstrel_stats_open(inode, file); +- inode->i_private = msp; +- return ret; +- } +- + ms = kmalloc(32768, GFP_KERNEL); + if (!ms) + return -ENOMEM; +@@ -143,9 +158,9 @@ minstrel_ht_stats_open(struct inode *inode, struct file *file) + + p += sprintf(p, "\n"); + p += sprintf(p, +- " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); ++ " best ____________rate__________ ____statistics___ _____last____ ______sum-of________\n"); + p += sprintf(p, +- "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); ++ "mode guard # rate [name idx airtime max_tp] [avg(tp) avg(prob)] [retry|suc|att] [#success | #attempts]\n"); + + p = minstrel_ht_stats_dump(mi, MINSTREL_CCK_GROUP, p); + for (i = 0; i < MINSTREL_CCK_GROUP; i++) +@@ -199,8 +214,7 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) + + for (j = 0; j < MCS_GROUP_RATES; j++) { + struct minstrel_rate_stats *mrs = &mi->groups[i].rates[j]; +- static const int bitrates[4] = { 10, 20, 55, 110 }; +- int idx = i * MCS_GROUP_RATES + j; ++ int idx = MI_RATE(i, j); + unsigned int duration; + + if (!(mi->supported[i] & BIT(j))) +@@ -214,6 +228,8 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) + p += sprintf(p, "VHT%c0,", htmode); + p += sprintf(p, "%cGI,", gimode); + p += sprintf(p, "%d,", mg->streams); ++ } else if (i == MINSTREL_OFDM_GROUP) { ++ p += sprintf(p, "OFDM,,1,"); + } else { + p += sprintf(p, "CCK,"); + p += sprintf(p, "%cP,", j < 4 ? 'L' : 'S'); +@@ -225,13 +241,20 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[2]) ? "C" : "")); + p += sprintf(p, "%s" ,((idx == mi->max_tp_rate[3]) ? "D" : "")); + p += sprintf(p, "%s" ,((idx == mi->max_prob_rate) ? "P" : "")); ++ p += sprintf(p, "%s", (minstrel_ht_is_sample_rate(mi, idx) ? "S" : "")); + + if (gflags & IEEE80211_TX_RC_MCS) { + p += sprintf(p, ",MCS%-2u,", (mg->streams - 1) * 8 + j); + } else if (gflags & IEEE80211_TX_RC_VHT_MCS) { + p += sprintf(p, ",MCS%-1u/%1u,", j, mg->streams); + } else { +- int r = bitrates[j % 4]; ++ int r; ++ ++ if (i == MINSTREL_OFDM_GROUP) ++ r = minstrel_ofdm_bitrates[j % 8]; ++ else ++ r = minstrel_cck_bitrates[j % 4]; ++ + p += sprintf(p, ",%2u.%1uM,", r / 10, r % 10); + } + +@@ -270,22 +293,12 @@ minstrel_ht_stats_csv_dump(struct minstrel_ht_sta *mi, int i, char *p) + static int + minstrel_ht_stats_csv_open(struct inode *inode, struct file *file) + { +- struct minstrel_ht_sta_priv *msp = inode->i_private; +- struct minstrel_ht_sta *mi = &msp->ht; ++ struct minstrel_ht_sta *mi = inode->i_private; + struct minstrel_debugfs_info *ms; + unsigned int i; +- int ret; + char *p; + +- if (!msp->is_ht) { +- inode->i_private = &msp->legacy; +- ret = minstrel_stats_csv_open(inode, file); +- inode->i_private = msp; +- return ret; +- } +- + ms = kmalloc(32768, GFP_KERNEL); +- + if (!ms) + return -ENOMEM; + +@@ -316,10 +329,8 @@ static const struct file_operations minstrel_ht_stat_csv_fops = { + void + minstrel_ht_add_sta_debugfs(void *priv, void *priv_sta, struct dentry *dir) + { +- struct minstrel_ht_sta_priv *msp = priv_sta; +- +- debugfs_create_file("rc_stats", 0444, dir, msp, ++ debugfs_create_file("rc_stats", 0444, dir, priv_sta, + &minstrel_ht_stat_fops); +- debugfs_create_file("rc_stats_csv", 0444, dir, msp, ++ debugfs_create_file("rc_stats_csv", 0444, dir, priv_sta, + &minstrel_ht_stat_csv_fops); + } +diff --git a/net/mac80211/rx.c b/net/mac80211/rx.c +index 0c5c63a..adeac74 100644 +--- a/net/mac80211/rx.c ++++ b/net/mac80211/rx.c +@@ -4114,7 +4114,9 @@ void ieee80211_check_fast_rx(struct sta_info *sta) + .vif_type = sdata->vif.type, + .control_port_protocol = sdata->control_port_protocol, + }, *old, *new = NULL; ++ bool set_offload = false; + bool assign = false; ++ bool offload; + + /* use sparse to check that we don't return without updating */ + __acquire(check_fast_rx); +@@ -4227,6 +4229,17 @@ void ieee80211_check_fast_rx(struct sta_info *sta) + if (assign) + new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL); + ++ offload = assign && ++ (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED); ++ ++ if (offload) ++ set_offload = !test_and_set_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); ++ else ++ set_offload = test_and_clear_sta_flag(sta, WLAN_STA_DECAP_OFFLOAD); ++ ++ if (set_offload) ++ drv_sta_set_decap_offload(local, sdata, &sta->sta, assign); ++ + spin_lock_bh(&sta->lock); + old = rcu_dereference_protected(sta->fast_rx, true); + rcu_assign_pointer(sta->fast_rx, new); +@@ -4273,6 +4286,108 @@ void ieee80211_check_fast_rx_iface(struct ieee80211_sub_if_data *sdata) + mutex_unlock(&local->sta_mtx); + } + ++static void ieee80211_rx_8023(struct ieee80211_rx_data *rx, ++ struct ieee80211_fast_rx *fast_rx, ++ int orig_len) ++{ ++ struct ieee80211_sta_rx_stats *stats; ++ struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb); ++ struct sta_info *sta = rx->sta; ++ struct sk_buff *skb = rx->skb; ++ void *sa = skb->data + ETH_ALEN; ++ void *da = skb->data; ++ ++ stats = &sta->rx_stats; ++ if (fast_rx->uses_rss) ++ stats = this_cpu_ptr(sta->pcpu_rx_stats); ++ ++ /* statistics part of ieee80211_rx_h_sta_process() */ ++ if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { ++ stats->last_signal = status->signal; ++ if (!fast_rx->uses_rss) ++ ewma_signal_add(&sta->rx_stats_avg.signal, ++ -status->signal); ++ } ++ ++ if (status->chains) { ++ int i; ++ ++ stats->chains = status->chains; ++ for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { ++ int signal = status->chain_signal[i]; ++ ++ if (!(status->chains & BIT(i))) ++ continue; ++ ++ stats->chain_signal_last[i] = signal; ++ if (!fast_rx->uses_rss) ++ ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], ++ -signal); ++ } ++ } ++ /* end of statistics */ ++ ++ stats->last_rx = jiffies; ++ stats->last_rate = sta_stats_encode_rate(status); ++ ++ stats->fragments++; ++ stats->packets++; ++ ++ skb->dev = fast_rx->dev; ++ ++ ieee80211_rx_stats(fast_rx->dev, skb->len); ++ ++ /* The seqno index has the same property as needed ++ * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS ++ * for non-QoS-data frames. Here we know it's a data ++ * frame, so count MSDUs. ++ */ ++ u64_stats_update_begin(&stats->syncp); ++ stats->msdu[rx->seqno_idx]++; ++ stats->bytes += orig_len; ++ u64_stats_update_end(&stats->syncp); ++ ++ if (fast_rx->internal_forward) { ++ struct sk_buff *xmit_skb = NULL; ++ if (is_multicast_ether_addr(da)) { ++ xmit_skb = skb_copy(skb, GFP_ATOMIC); ++ } else if (!ether_addr_equal(da, sa) && ++ sta_info_get(rx->sdata, da)) { ++ xmit_skb = skb; ++ skb = NULL; ++ } ++ ++ if (xmit_skb) { ++ /* ++ * Send to wireless media and increase priority by 256 ++ * to keep the received priority instead of ++ * reclassifying the frame (see cfg80211_classify8021d). ++ */ ++ xmit_skb->priority += 256; ++ xmit_skb->protocol = htons(ETH_P_802_3); ++ skb_reset_network_header(xmit_skb); ++ skb_reset_mac_header(xmit_skb); ++ dev_queue_xmit(xmit_skb); ++ } ++ ++ if (!skb) ++ return; ++ } ++ ++ /* deliver to local stack */ ++ skb->protocol = eth_type_trans(skb, fast_rx->dev); ++ memset(skb->cb, 0, sizeof(skb->cb)); ++ if (rx->list) ++#if LINUX_VERSION_IS_GEQ(4,19,0) ++ list_add_tail(&skb->list, rx->list); ++#else ++ __skb_queue_tail(rx->list, skb); ++#endif ++ else ++ netif_receive_skb(skb); ++ ++} ++ + static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + struct ieee80211_fast_rx *fast_rx) + { +@@ -4293,9 +4408,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + } addrs __aligned(2); + struct ieee80211_sta_rx_stats *stats = &sta->rx_stats; + +- if (fast_rx->uses_rss) +- stats = this_cpu_ptr(sta->pcpu_rx_stats); +- + /* for parallel-rx, we need to have DUP_VALIDATED, otherwise we write + * to a common data structure; drivers can implement that per queue + * but we don't have that information in mac80211 +@@ -4369,32 +4481,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + pskb_trim(skb, skb->len - fast_rx->icv_len)) + goto drop; + +- /* statistics part of ieee80211_rx_h_sta_process() */ +- if (!(status->flag & RX_FLAG_NO_SIGNAL_VAL)) { +- stats->last_signal = status->signal; +- if (!fast_rx->uses_rss) +- ewma_signal_add(&sta->rx_stats_avg.signal, +- -status->signal); +- } +- +- if (status->chains) { +- int i; +- +- stats->chains = status->chains; +- for (i = 0; i < ARRAY_SIZE(status->chain_signal); i++) { +- int signal = status->chain_signal[i]; +- +- if (!(status->chains & BIT(i))) +- continue; +- +- stats->chain_signal_last[i] = signal; +- if (!fast_rx->uses_rss) +- ewma_signal_add(&sta->rx_stats_avg.chain_signal[i], +- -signal); +- } +- } +- /* end of statistics */ +- + if (rx->key && !ieee80211_has_protected(hdr->frame_control)) + goto drop; + +@@ -4406,12 +4492,6 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + return true; + } + +- stats->last_rx = jiffies; +- stats->last_rate = sta_stats_encode_rate(status); +- +- stats->fragments++; +- stats->packets++; +- + /* do the header conversion - first grab the addresses */ + ether_addr_copy(addrs.da, skb->data + fast_rx->da_offs); + ether_addr_copy(addrs.sa, skb->data + fast_rx->sa_offs); +@@ -4420,62 +4500,14 @@ static bool ieee80211_invoke_fast_rx(struct ieee80211_rx_data *rx, + /* push the addresses in front */ + memcpy(skb_push(skb, sizeof(addrs)), &addrs, sizeof(addrs)); + +- skb->dev = fast_rx->dev; +- +- ieee80211_rx_stats(fast_rx->dev, skb->len); +- +- /* The seqno index has the same property as needed +- * for the rx_msdu field, i.e. it is IEEE80211_NUM_TIDS +- * for non-QoS-data frames. Here we know it's a data +- * frame, so count MSDUs. +- */ +- u64_stats_update_begin(&stats->syncp); +- stats->msdu[rx->seqno_idx]++; +- stats->bytes += orig_len; +- u64_stats_update_end(&stats->syncp); +- +- if (fast_rx->internal_forward) { +- struct sk_buff *xmit_skb = NULL; +- if (is_multicast_ether_addr(addrs.da)) { +- xmit_skb = skb_copy(skb, GFP_ATOMIC); +- } else if (!ether_addr_equal(addrs.da, addrs.sa) && +- sta_info_get(rx->sdata, addrs.da)) { +- xmit_skb = skb; +- skb = NULL; +- } +- +- if (xmit_skb) { +- /* +- * Send to wireless media and increase priority by 256 +- * to keep the received priority instead of +- * reclassifying the frame (see cfg80211_classify8021d). +- */ +- xmit_skb->priority += 256; +- xmit_skb->protocol = htons(ETH_P_802_3); +- skb_reset_network_header(xmit_skb); +- skb_reset_mac_header(xmit_skb); +- dev_queue_xmit(xmit_skb); +- } +- +- if (!skb) +- return true; +- } +- +- /* deliver to local stack */ +- skb->protocol = eth_type_trans(skb, fast_rx->dev); +- memset(skb->cb, 0, sizeof(skb->cb)); +- if (rx->list) +-#if LINUX_VERSION_IS_GEQ(4,19,0) +- list_add_tail(&skb->list, rx->list); +-#else +- __skb_queue_tail(rx->list, skb); +-#endif +- else +- netif_receive_skb(skb); ++ ieee80211_rx_8023(rx, fast_rx, orig_len); + + return true; + drop: + dev_kfree_skb(skb); ++ if (fast_rx->uses_rss) ++ stats = this_cpu_ptr(sta->pcpu_rx_stats); ++ + stats->dropped++; + return true; + } +@@ -4529,6 +4561,47 @@ static bool ieee80211_prepare_and_rx_handle(struct ieee80211_rx_data *rx, + return true; + } + ++static void __ieee80211_rx_handle_8023(struct ieee80211_hw *hw, ++ struct ieee80211_sta *pubsta, ++ struct sk_buff *skb, ++#if LINUX_VERSION_IS_GEQ(4,19,0) ++ struct list_head *list) ++#else ++ struct sk_buff_head *list) ++#endif ++{ ++ struct ieee80211_local *local = hw_to_local(hw); ++ struct ieee80211_fast_rx *fast_rx; ++ struct ieee80211_rx_data rx; ++ ++ memset(&rx, 0, sizeof(rx)); ++ rx.skb = skb; ++ rx.local = local; ++ rx.list = list; ++ ++ I802_DEBUG_INC(local->dot11ReceivedFragmentCount); ++ ++ /* drop frame if too short for header */ ++ if (skb->len < sizeof(struct ethhdr)) ++ goto drop; ++ ++ if (!pubsta) ++ goto drop; ++ ++ rx.sta = container_of(pubsta, struct sta_info, sta); ++ rx.sdata = rx.sta->sdata; ++ ++ fast_rx = rcu_dereference(rx.sta->fast_rx); ++ if (!fast_rx) ++ goto drop; ++ ++ ieee80211_rx_8023(&rx, fast_rx, skb->len); ++ return; ++ ++drop: ++ dev_kfree_skb(skb); ++} ++ + /* + * This is the actual Rx frames handler. as it belongs to Rx path it must + * be called with rcu_read_lock protection. +@@ -4766,15 +4839,20 @@ void ieee80211_rx_list(struct ieee80211_hw *hw, struct ieee80211_sta *pubsta, + * if it was previously present. + * Also, frames with less than 16 bytes are dropped. + */ +- skb = ieee80211_rx_monitor(local, skb, rate); +- if (!skb) +- return; ++ if (!(status->flag & RX_FLAG_8023)) { ++ skb = ieee80211_rx_monitor(local, skb, rate); ++ if (!skb) ++ return; ++ } + + ieee80211_tpt_led_trig_rx(local, + ((struct ieee80211_hdr *)skb->data)->frame_control, + skb->len); + +- __ieee80211_rx_handle_packet(hw, pubsta, skb, list); ++ if (status->flag & RX_FLAG_8023) ++ __ieee80211_rx_handle_8023(hw, pubsta, skb, list); ++ else ++ __ieee80211_rx_handle_packet(hw, pubsta, skb, list); + + return; + drop: +diff --git a/net/mac80211/sta_info.c b/net/mac80211/sta_info.c +index 3058f0a..83c2d15 100644 +--- a/net/mac80211/sta_info.c ++++ b/net/mac80211/sta_info.c +@@ -357,6 +357,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, INIT_WORK(&sta->drv_deliver_wk, sta_deliver_ps_frames); INIT_WORK(&sta->ampdu_mlme.work, ieee80211_ba_session_work); mutex_init(&sta->ampdu_mlme.mtx); @@ -2703,613 +5454,176 @@ index c431722..ee72428 100644 #ifdef CPTCFG_MAC80211_MESH if (ieee80211_vif_is_mesh(&sdata->vif)) { sta->mesh = kzalloc(sizeof(*sta->mesh), gfp); -@@ -396,6 +411,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata, - skb_queue_head_init(&sta->ps_tx_buf[i]); - skb_queue_head_init(&sta->tx_filtered[i]); - sta->airtime[i].deficit = sta->airtime_weight; -+ atomic_set(&sta->airtime[i].aql_tx_pending, 0); -+ sta->airtime[i].aql_limit_low = local->aql_txq_limit_low[i]; -+ sta->airtime[i].aql_limit_high = local->aql_txq_limit_high[i]; - } - - for (i = 0; i < IEEE80211_NUM_TIDS; i++) -@@ -1893,6 +1911,44 @@ void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid, - } - EXPORT_SYMBOL(ieee80211_sta_register_airtime); - -+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, -+ struct sta_info *sta, u8 ac, -+ u16 tx_airtime, bool tx_completed) -+{ -+ int tx_pending; -+ -+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) -+ return; -+ -+ if (!tx_completed) { -+ if (sta) -+ atomic_add(tx_airtime, -+ &sta->airtime[ac].aql_tx_pending); -+ -+ atomic_add(tx_airtime, &local->aql_total_pending_airtime); -+ return; -+ } -+ -+ if (sta) { -+ tx_pending = atomic_sub_return(tx_airtime, -+ &sta->airtime[ac].aql_tx_pending); -+ if (WARN_ONCE(tx_pending < 0, -+ "STA %pM AC %d txq pending airtime underflow: %u, %u", -+ sta->addr, ac, tx_pending, tx_airtime)) -+ atomic_cmpxchg(&sta->airtime[ac].aql_tx_pending, -+ tx_pending, 0); -+ } -+ -+ tx_pending = atomic_sub_return(tx_airtime, -+ &local->aql_total_pending_airtime); -+ if (WARN_ONCE(tx_pending < 0, -+ "Device %s AC %d pending airtime underflow: %u, %u", -+ wiphy_name(local->hw.wiphy), ac, tx_pending, -+ tx_airtime)) -+ atomic_cmpxchg(&local->aql_total_pending_airtime, -+ tx_pending, 0); -+} -+ - int sta_info_move_state(struct sta_info *sta, - enum ieee80211_sta_state new_state) - { diff --git a/net/mac80211/sta_info.h b/net/mac80211/sta_info.h -index ad6c547..768000d 100644 +index 94f4422..df67568 100644 --- a/net/mac80211/sta_info.h +++ b/net/mac80211/sta_info.h -@@ -98,6 +98,7 @@ enum ieee80211_sta_info_flags { - WLAN_STA_MPSP_OWNER, +@@ -71,6 +71,7 @@ + * until pending frames are delivered + * @WLAN_STA_USES_ENCRYPTION: This station was configured for encryption, + * so drop all packets without a key later. ++ * @WLAN_STA_DECAP_OFFLOAD: This station uses rx decap offload + * + * @NUM_WLAN_STA_FLAGS: number of defined flags + */ +@@ -102,6 +103,7 @@ enum ieee80211_sta_info_flags { WLAN_STA_MPSP_RECIPIENT, WLAN_STA_PS_DELIVER, -+ WLAN_STA_USES_ENCRYPTION, + WLAN_STA_USES_ENCRYPTION, ++ WLAN_STA_DECAP_OFFLOAD, NUM_WLAN_STA_FLAGS, }; -@@ -132,8 +133,15 @@ struct airtime_info { - u64 rx_airtime; - u64 tx_airtime; - s64 deficit; -+ atomic_t aql_tx_pending; /* Estimated airtime for frames pending */ -+ u32 aql_limit_low; -+ u32 aql_limit_high; - }; +diff --git a/net/mac80211/trace.h b/net/mac80211/trace.h +index 8972390..8fcc390 100644 +--- a/net/mac80211/trace.h ++++ b/net/mac80211/trace.h +@@ -2,7 +2,7 @@ + /* + * Portions of this file + * Copyright(c) 2016-2017 Intel Deutschland GmbH +-* Copyright (C) 2018 - 2019 Intel Corporation ++* Copyright (C) 2018 - 2020 Intel Corporation + */ -+void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local, -+ struct sta_info *sta, u8 ac, -+ u16 tx_airtime, bool tx_completed); + #if !defined(__MAC80211_DRIVER_TRACE) || defined(TRACE_HEADER_MULTI_READ) +@@ -2086,6 +2086,27 @@ TRACE_EVENT(api_connection_loss, + ) + ); + ++TRACE_EVENT(api_disconnect, ++ TP_PROTO(struct ieee80211_sub_if_data *sdata, bool reconnect), + - struct sta_info; - - /** -@@ -725,6 +733,10 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata, - struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata, - const u8 *addr); - -+/* user must hold sta_mtx or be in RCU critical section */ -+struct sta_info *sta_info_get_by_addrs(struct ieee80211_local *local, -+ const u8 *sta_addr, const u8 *vif_addr); ++ TP_ARGS(sdata, reconnect), + - #define for_each_sta_info(local, _addr, _sta, _tmp) \ - rhl_for_each_entry_rcu(_sta, _tmp, \ - sta_info_hash_lookup(local, _addr), hash_node) -diff --git a/net/mac80211/status.c b/net/mac80211/status.c -index 351fd8e..2e3ae66 100644 ---- a/net/mac80211/status.c -+++ b/net/mac80211/status.c -@@ -670,12 +670,26 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local, - struct sk_buff *skb, bool dropped) - { - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); -+ u16 tx_time_est = ieee80211_info_get_tx_time_est(info); - struct ieee80211_hdr *hdr = (void *)skb->data; - bool acked = info->flags & IEEE80211_TX_STAT_ACK; - - if (dropped) - acked = false; - -+ if (tx_time_est) { -+ struct sta_info *sta; ++ TP_STRUCT__entry( ++ VIF_ENTRY ++ __field(int, reconnect) ++ ), + -+ rcu_read_lock(); ++ TP_fast_assign( ++ VIF_ASSIGN; ++ __entry->reconnect = reconnect; ++ ), + -+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2); -+ ieee80211_sta_update_pending_airtime(local, sta, -+ skb_get_queue_mapping(skb), -+ tx_time_est, -+ true); -+ rcu_read_unlock(); -+ } ++ TP_printk( ++ VIF_PR_FMT " reconnect:%d", ++ VIF_PR_ARG, __entry->reconnect ++ ) ++); + - if (info->flags & IEEE80211_TX_INTFL_MLME_CONN_TX) { - struct ieee80211_sub_if_data *sdata; + TRACE_EVENT(api_cqm_rssi_notify, + TP_PROTO(struct ieee80211_sub_if_data *sdata, + enum nl80211_cqm_rssi_threshold_event rssi_event, +@@ -2740,7 +2761,7 @@ DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload, + TP_ARGS(local, sdata) + ); -@@ -815,6 +829,11 @@ void ieee80211_tx_monitor(struct ieee80211_local *local, struct sk_buff *skb, - struct net_device *prev_dev = NULL; - int rtap_len; +-TRACE_EVENT(drv_sta_set_4addr, ++DECLARE_EVENT_CLASS(sta_flag_evt, + TP_PROTO(struct ieee80211_local *local, + struct ieee80211_sub_if_data *sdata, + struct ieee80211_sta *sta, bool enabled), +@@ -2767,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr, + ) + ); -+ if (ieee80211_skb_resize(local, NULL, skb, 0, 0)) { -+ dev_kfree_skb(skb); -+ return; -+ } ++DEFINE_EVENT(sta_flag_evt, drv_sta_set_4addr, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, bool enabled), + - /* send frame to monitor interfaces now */ - rtap_len = ieee80211_tx_radiotap_len(info, status); - if (WARN_ON_ONCE(skb_headroom(skb) < rtap_len)) { -@@ -876,9 +895,11 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, - int rates_idx; - bool send_to_cooked; - bool acked; -+ bool noack_success; - struct ieee80211_bar *bar; - int shift = 0; - int tid = IEEE80211_NUM_TIDS; -+ u16 tx_time_est; - - rates_idx = ieee80211_tx_get_rates(hw, info, &retry_count); - -@@ -893,6 +914,8 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, - clear_sta_flag(sta, WLAN_STA_SP); - - acked = !!(info->flags & IEEE80211_TX_STAT_ACK); -+ noack_success = !!(info->flags & -+ IEEE80211_TX_STAT_NOACK_TRANSMITTED); - - /* mesh Peer Service Period support */ - if (ieee80211_vif_is_mesh(&sta->sdata->vif) && -@@ -957,12 +980,12 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, - ieee80211_handle_filtered_frame(local, sta, skb); - return; - } else { -- if (!acked) -+ if (!acked && !noack_success) - sta->status_stats.retry_failed++; - sta->status_stats.retry_count += retry_count; - - if (ieee80211_is_data_present(fc)) { -- if (!acked) -+ if (!acked && !noack_success) - sta->status_stats.msdu_failed[tid]++; - - sta->status_stats.msdu_retries[tid] += -@@ -988,8 +1011,19 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, - ieee80211_sta_register_airtime(&sta->sta, tid, - info->status.tx_time, 0); - -+ if ((tx_time_est = ieee80211_info_get_tx_time_est(info)) > 0) { -+ /* Do this here to avoid the expensive lookup of the sta -+ * in ieee80211_report_used_skb(). -+ */ -+ ieee80211_sta_update_pending_airtime(local, sta, -+ skb_get_queue_mapping(skb), -+ tx_time_est, -+ true); -+ ieee80211_info_set_tx_time_est(info, 0); -+ } ++ TP_ARGS(local, sdata, sta, enabled) ++); + - if (ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) { -- if (info->flags & IEEE80211_TX_STAT_ACK) { -+ if (acked) { - if (sta->status_stats.lost_packets) - sta->status_stats.lost_packets = 0; ++DEFINE_EVENT(sta_flag_evt, drv_sta_set_decap_offload, ++ TP_PROTO(struct ieee80211_local *local, ++ struct ieee80211_sub_if_data *sdata, ++ struct ieee80211_sta *sta, bool enabled), ++ ++ TP_ARGS(local, sdata, sta, enabled) ++); ++ + #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */ -@@ -997,6 +1031,8 @@ static void __ieee80211_tx_status(struct ieee80211_hw *hw, - if (test_sta_flag(sta, WLAN_STA_TDLS_PEER_AUTH)) - sta->status_stats.last_tdls_pkt_time = - jiffies; -+ } else if (noack_success) { -+ /* nothing to do here, do not account as lost */ - } else { - ieee80211_lost_packet(sta, info); - } -@@ -1076,19 +1112,13 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb) - .skb = skb, - .info = IEEE80211_SKB_CB(skb), - }; -- struct rhlist_head *tmp; - struct sta_info *sta; - - rcu_read_lock(); - -- for_each_sta_info(local, hdr->addr1, sta, tmp) { -- /* skip wrong virtual interface */ -- if (!ether_addr_equal(hdr->addr2, sta->sdata->vif.addr)) -- continue; -- -+ sta = sta_info_get_by_addrs(local, hdr->addr1, hdr->addr2); -+ if (sta) - status.sta = &sta->sta; -- break; -- } - - __ieee80211_tx_status(hw, &status); - rcu_read_unlock(); -@@ -1123,7 +1153,7 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, - - sta = container_of(pubsta, struct sta_info, sta); - -- if (!acked) -+ if (!acked && !noack_success) - sta->status_stats.retry_failed++; - sta->status_stats.retry_count += retry_count; - -@@ -1138,6 +1168,8 @@ void ieee80211_tx_status_ext(struct ieee80211_hw *hw, - sta->status_stats.last_tdls_pkt_time = jiffies; - } else if (test_sta_flag(sta, WLAN_STA_PS_STA)) { - return; -+ } else if (noack_success) { -+ /* nothing to do here, do not account as lost */ - } else { - ieee80211_lost_packet(sta, info); - } + #undef TRACE_INCLUDE_PATH diff --git a/net/mac80211/tx.c b/net/mac80211/tx.c -index 535911b..9a04c48 100644 +index 32b13b4..e5e8aa1 100644 --- a/net/mac80211/tx.c +++ b/net/mac80211/tx.c -@@ -590,10 +590,13 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb); - struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data; +@@ -1322,7 +1322,7 @@ static struct sk_buff *codel_dequeue_func(struct codel_vars *cvars, + fq = &local->fq; -- if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) -+ if (unlikely(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) { - tx->key = NULL; -- else if (tx->sta && -- (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) -+ return TX_CONTINUE; -+ } -+ -+ if (tx->sta && -+ (key = rcu_dereference(tx->sta->ptk[tx->sta->ptk_idx]))) - tx->key = key; - else if (ieee80211_is_group_privacy_action(tx->skb) && - (key = rcu_dereference(tx->sdata->default_multicast_key))) -@@ -654,6 +657,9 @@ ieee80211_tx_h_select_key(struct ieee80211_tx_data *tx) - if (!skip_hw && tx->key && - tx->key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE) - info->control.hw_key = &tx->key->conf; -+ } else if (!ieee80211_is_mgmt(hdr->frame_control) && tx->sta && -+ test_sta_flag(tx->sta, WLAN_STA_USES_ENCRYPTION)) { -+ return TX_DROP; - } - - return TX_CONTINUE; -@@ -1937,37 +1943,53 @@ static bool ieee80211_tx(struct ieee80211_sub_if_data *sdata, - } - - /* device xmit handlers */ -- --static int ieee80211_skb_resize(struct ieee80211_sub_if_data *sdata, -- struct sk_buff *skb, -- int head_need, bool may_encrypt) -+int ieee80211_skb_resize(struct ieee80211_local *local, -+ struct ieee80211_sub_if_data *sdata, -+ struct sk_buff *skb, int hdr_len, int hdr_extra) - { -- struct ieee80211_local *local = sdata->local; -+ struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr; -- bool enc_tailroom; -- int tail_need = 0; -+ int head_need, head_max; -+ int tail_need, tail_max; -+ bool enc_tailroom = false; - -- hdr = (struct ieee80211_hdr *) skb->data; -- enc_tailroom = may_encrypt && -- (sdata->crypto_tx_tailroom_needed_cnt || -- ieee80211_is_mgmt(hdr->frame_control)); -- -- if (enc_tailroom) { -- tail_need = IEEE80211_ENCRYPT_TAILROOM; -- tail_need -= skb_tailroom(skb); -- tail_need = max_t(int, tail_need, 0); -+ if (sdata && !hdr_len && -+ !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT)) { -+ hdr = (struct ieee80211_hdr *) skb->data; -+ enc_tailroom = (sdata->crypto_tx_tailroom_needed_cnt || -+ ieee80211_is_mgmt(hdr->frame_control)); -+ hdr_len += sdata->encrypt_headroom; -+ } -+ -+ head_need = head_max = hdr_len; -+ tail_need = tail_max = 0; -+ if (!sdata) { -+ head_need = head_max = local->tx_headroom; -+ } else { -+ head_max += hdr_extra; -+ head_max += max_t(int, local->tx_headroom, -+ local->hw.extra_tx_headroom); -+ head_need += local->hw.extra_tx_headroom; -+ -+ tail_max = IEEE80211_ENCRYPT_TAILROOM; -+ if (enc_tailroom) -+ tail_need = tail_max; - } - - if (skb_cloned(skb) && - (!ieee80211_hw_check(&local->hw, SUPPORTS_CLONED_SKBS) || - !skb_clone_writable(skb, ETH_HLEN) || enc_tailroom)) - I802_DEBUG_INC(local->tx_expand_skb_head_cloned); -- else if (head_need || tail_need) -+ else if (head_need > skb_headroom(skb) || -+ tail_need > skb_tailroom(skb)) - I802_DEBUG_INC(local->tx_expand_skb_head); + if (cvars == &txqi->def_cvars) +- flow = &txqi->def_flow; ++ flow = &txqi->tin.default_flow; else - return 0; + flow = &fq->flows[cvars - local->cvars]; -- if (pskb_expand_head(skb, head_need, tail_need, GFP_ATOMIC)) { -+ head_max = max_t(int, 0, head_max - skb_headroom(skb)); -+ tail_max = max_t(int, 0, tail_max - skb_tailroom(skb)); -+ -+ if (pskb_expand_head(skb, head_max, tail_max, GFP_ATOMIC)) { - wiphy_debug(local->hw.wiphy, - "failed to reallocate TX buffer\n"); - return -ENOMEM; -@@ -1983,18 +2005,8 @@ void ieee80211_xmit(struct ieee80211_sub_if_data *sdata, - struct ieee80211_local *local = sdata->local; - struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb); - struct ieee80211_hdr *hdr; -- int headroom; -- bool may_encrypt; -- -- may_encrypt = !(info->flags & IEEE80211_TX_INTFL_DONT_ENCRYPT); -- -- headroom = local->tx_headroom; -- if (may_encrypt) -- headroom += sdata->encrypt_headroom; -- headroom -= skb_headroom(skb); -- headroom = max_t(int, 0, headroom); - -- if (ieee80211_skb_resize(sdata, skb, headroom, may_encrypt)) { -+ if (ieee80211_skb_resize(local, sdata, skb, 0, 0)) { - ieee80211_free_txskb(&local->hw, skb); - return; +@@ -1365,7 +1365,7 @@ static struct sk_buff *fq_tin_dequeue_func(struct fq *fq, + cparams = &local->cparams; } -@@ -2433,6 +2445,33 @@ static int ieee80211_lookup_ra_sta(struct ieee80211_sub_if_data *sdata, - return 0; + +- if (flow == &txqi->def_flow) ++ if (flow == &tin->default_flow) + cvars = &txqi->def_cvars; + else + cvars = &local->cvars[flow - fq->flows]; +@@ -1392,17 +1392,6 @@ static void fq_skb_free_func(struct fq *fq, + ieee80211_free_txskb(&local->hw, skb); } -+static int ieee80211_store_ack_skb(struct ieee80211_local *local, -+ struct sk_buff *skb, -+ u32 *info_flags) -+{ -+ struct sk_buff *ack_skb = skb_clone_sk(skb); -+ u16 info_id = 0; -+ -+ if (ack_skb) { -+ unsigned long flags; -+ int id; -+ -+ spin_lock_irqsave(&local->ack_status_lock, flags); -+ id = idr_alloc(&local->ack_status_frames, ack_skb, -+ 1, 0x2000, GFP_ATOMIC); -+ spin_unlock_irqrestore(&local->ack_status_lock, flags); -+ -+ if (id >= 0) { -+ info_id = id; -+ *info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; -+ } else { -+ kfree_skb(ack_skb); -+ } -+ } -+ -+ return info_id; -+} -+ - /** - * ieee80211_build_hdr - build 802.11 header in the given frame - * @sdata: virtual interface to build the header for -@@ -2726,26 +2765,8 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, - } - - if (unlikely(!multicast && skb->sk && -- skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) { -- struct sk_buff *ack_skb = skb_clone_sk(skb); +-static struct fq_flow *fq_flow_get_default_func(struct fq *fq, +- struct fq_tin *tin, +- int idx, +- struct sk_buff *skb) +-{ +- struct txq_info *txqi; - -- if (ack_skb) { -- unsigned long flags; -- int id; +- txqi = container_of(tin, struct txq_info, tin); +- return &txqi->def_flow; +-} - -- spin_lock_irqsave(&local->ack_status_lock, flags); -- id = idr_alloc(&local->ack_status_frames, ack_skb, -- 1, 0x10000, GFP_ATOMIC); -- spin_unlock_irqrestore(&local->ack_status_lock, flags); -- -- if (id >= 0) { -- info_id = id; -- info_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS; -- } else { -- kfree_skb(ack_skb); -- } -- } -- } -+ skb_shinfo(skb)->tx_flags & SKBTX_WIFI_STATUS)) -+ info_id = ieee80211_store_ack_skb(local, skb, &info_flags); + static void ieee80211_txq_enqueue(struct ieee80211_local *local, + struct txq_info *txqi, + struct sk_buff *skb) +@@ -1415,8 +1404,7 @@ static void ieee80211_txq_enqueue(struct ieee80211_local *local, - /* - * If the skb is shared we need to obtain our own copy. -@@ -2784,29 +2805,13 @@ static struct sk_buff *ieee80211_build_hdr(struct ieee80211_sub_if_data *sdata, - } - - skb_pull(skb, skip_header_bytes); -- head_need = hdrlen + encaps_len + meshhdrlen - skb_headroom(skb); -+ head_need = hdrlen + encaps_len + meshhdrlen; - -- /* -- * So we need to modify the skb header and hence need a copy of -- * that. The head_need variable above doesn't, so far, include -- * the needed header space that we don't need right away. If we -- * can, then we don't reallocate right now but only after the -- * frame arrives at the master device (if it does...) -- * -- * If we cannot, however, then we will reallocate to include all -- * the ever needed space. Also, if we need to reallocate it anyway, -- * make it big enough for everything we may ever need. -- */ -- -- if (head_need > 0 || skb_cloned(skb)) { -- head_need += sdata->encrypt_headroom; -- head_need += local->tx_headroom; -- head_need = max_t(int, 0, head_need); -- if (ieee80211_skb_resize(sdata, skb, head_need, true)) { -- ieee80211_free_txskb(&local->hw, skb); -- skb = NULL; -- return ERR_PTR(-ENOMEM); -- } -+ if (ieee80211_skb_resize(local, sdata, skb, head_need, -+ sdata->encrypt_headroom)) { -+ ieee80211_free_txskb(&local->hw, skb); -+ skb = NULL; -+ return ERR_PTR(-ENOMEM); - } - - if (encaps_data) -@@ -3421,7 +3426,6 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, - struct ieee80211_local *local = sdata->local; - u16 ethertype = (skb->data[12] << 8) | skb->data[13]; - int extra_head = fast_tx->hdr_len - (ETH_HLEN - 2); -- int hw_headroom = sdata->local->hw.extra_tx_headroom; - struct ethhdr eth; - struct ieee80211_tx_info *info; - struct ieee80211_hdr *hdr = (void *)fast_tx->hdr; -@@ -3473,10 +3477,7 @@ static bool ieee80211_xmit_fast(struct ieee80211_sub_if_data *sdata, - * as the may-encrypt argument for the resize to not account for - * more room than we already have in 'extra_head' - */ -- if (unlikely(ieee80211_skb_resize(sdata, skb, -- max_t(int, extra_head + hw_headroom - -- skb_headroom(skb), 0), -- false))) { -+ if (unlikely(ieee80211_skb_resize(local, sdata, skb, extra_head, 0))) { - kfree_skb(skb); - return true; - } -@@ -3558,6 +3559,9 @@ struct sk_buff *ieee80211_tx_dequeue(struct ieee80211_hw *hw, - - WARN_ON_ONCE(softirq_count() == 0); - -+ if (!ieee80211_txq_airtime_check(hw, txq)) -+ return NULL; -+ - begin: spin_lock_bh(&fq->lock); - -@@ -3668,6 +3672,21 @@ begin: - } - - IEEE80211_SKB_CB(skb)->control.vif = vif; -+ -+ if (wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) { -+ u32 airtime; -+ -+ airtime = ieee80211_calc_expected_tx_airtime(hw, vif, txq->sta, -+ skb->len); -+ if (airtime) { -+ airtime = ieee80211_info_set_tx_time_est(info, airtime); -+ ieee80211_sta_update_pending_airtime(local, tx.sta, -+ txq->ac, -+ airtime, -+ false); -+ } -+ } -+ - return skb; - - out: -@@ -3681,7 +3700,8 @@ 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; -+ struct txq_info *txqi = NULL, *head = NULL; -+ bool found_eligible_txq = false; - - spin_lock_bh(&local->active_txq_lock[ac]); - -@@ -3692,13 +3712,30 @@ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac) - if (!txqi) - goto out; - -+ if (txqi == head) { -+ if (!found_eligible_txq) -+ goto out; -+ else -+ found_eligible_txq = false; -+ } -+ -+ if (!head) -+ head = txqi; -+ - if (txqi->txq.sta) { - struct sta_info *sta = container_of(txqi->txq.sta, -- struct sta_info, sta); -+ struct sta_info, sta); -+ bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq); -+ s64 deficit = sta->airtime[txqi->txq.ac].deficit; -+ -+ if (aql_check) -+ found_eligible_txq = true; - -- if (sta->airtime[txqi->txq.ac].deficit < 0) { -+ if (deficit < 0) - sta->airtime[txqi->txq.ac].deficit += - sta->airtime_weight; -+ -+ if (deficit < 0 || !aql_check) { - list_move_tail(&txqi->schedule_order, - &local->active_txqs[txqi->txq.ac]); - goto begin; -@@ -3752,6 +3789,33 @@ void __ieee80211_schedule_txq(struct ieee80211_hw *hw, + fq_tin_enqueue(fq, tin, flow_idx, skb, +- fq_skb_free_func, +- fq_flow_get_default_func); ++ fq_skb_free_func); + spin_unlock_bh(&fq->lock); } - EXPORT_SYMBOL(__ieee80211_schedule_txq); -+bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw, -+ struct ieee80211_txq *txq) -+{ -+ struct sta_info *sta; -+ struct ieee80211_local *local = hw_to_local(hw); -+ -+ if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) -+ return true; -+ -+ if (!txq->sta) -+ return true; -+ -+ sta = container_of(txq->sta, struct sta_info, sta); -+ if (atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < -+ sta->airtime[txq->ac].aql_limit_low) -+ return true; -+ -+ if (atomic_read(&local->aql_total_pending_airtime) < -+ local->aql_threshold && -+ atomic_read(&sta->airtime[txq->ac].aql_tx_pending) < -+ sta->airtime[txq->ac].aql_limit_high) -+ return true; -+ -+ return false; -+} -+EXPORT_SYMBOL(ieee80211_txq_airtime_check); -+ - bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw, - struct ieee80211_txq *txq) +@@ -1459,7 +1447,6 @@ void ieee80211_txq_init(struct ieee80211_sub_if_data *sdata, + struct txq_info *txqi, int tid) { -@@ -4024,6 +4088,12 @@ out: - netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb, - struct net_device *dev) - { -+#if defined(sk_pacing_shift) || LINUX_VERSION_IS_GEQ(4,15,0) -+ if (skb->sk && sk_fullsock(skb->sk) && -+ skb->sk->sk_pacing_shift != 6) -+ skb->sk->sk_pacing_shift = 6; -+#endif -+ - if (unlikely(ieee80211_multicast_to_unicast(skb, dev))) { - struct sk_buff_head queue; + fq_tin_init(&txqi->tin); +- fq_flow_init(&txqi->def_flow); + codel_vars_init(&txqi->def_cvars); + codel_stats_init(&txqi->cstats); + __skb_queue_head_init(&txqi->frags); +@@ -3310,8 +3297,7 @@ static bool ieee80211_amsdu_aggregate(struct ieee80211_sub_if_data *sdata, + */ + tin = &txqi->tin; +- flow = fq_flow_classify(fq, tin, flow_idx, skb, +- fq_flow_get_default_func); ++ flow = fq_flow_classify(fq, tin, flow_idx, skb); + head = skb_peek_tail(&flow->queue); + if (!head || skb_is_gso(head)) + goto out; +@@ -3378,8 +3364,6 @@ out_recalc: + if (head->len != orig_len) { + flow->backlog += head->len - orig_len; + tin->backlog_bytes += head->len - orig_len; +- +- fq_recalc_backlog(fq, tin, flow); + } + out: + spin_unlock_bh(&fq->lock); diff --git a/net/mac80211/wpa.c b/net/mac80211/wpa.c index 91bf32a..690fe47 100644 --- a/net/mac80211/wpa.c @@ -3434,10 +5748,10 @@ index 91bf32a..690fe47 100644 if (!ieee80211_is_mgmt(hdr->frame_control)) diff --git a/net/wireless/core.c b/net/wireless/core.c -index 8bffbb6..c8a6c0e 100644 +index 587ad11..afdfcc2 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c -@@ -613,21 +613,6 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) +@@ -614,21 +614,6 @@ static int wiphy_verify_combinations(struct wiphy *wiphy) c->limits[j].max > 1)) return -EINVAL; @@ -3459,19 +5773,112 @@ index 8bffbb6..c8a6c0e 100644 cnt += c->limits[j].max; /* * Don't advertise an unsupported type +diff --git a/net/wireless/mlme.c b/net/wireless/mlme.c +index 33f4ee6..ea2c4ee 100644 +--- a/net/wireless/mlme.c ++++ b/net/wireless/mlme.c +@@ -4,7 +4,7 @@ + * + * Copyright (c) 2009, Jouni Malinen + * Copyright (c) 2015 Intel Deutschland GmbH +- * Copyright (C) 2019 Intel Corporation ++ * Copyright (C) 2019-2020 Intel Corporation + */ + + #include +@@ -81,7 +81,8 @@ static void cfg80211_process_auth(struct wireless_dev *wdev, + } + + static void cfg80211_process_deauth(struct wireless_dev *wdev, +- const u8 *buf, size_t len) ++ const u8 *buf, size_t len, ++ bool reconnect) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; +@@ -89,7 +90,7 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev, + u16 reason_code = le16_to_cpu(mgmt->u.deauth.reason_code); + bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); + +- nl80211_send_deauth(rdev, wdev->netdev, buf, len, GFP_KERNEL); ++ nl80211_send_deauth(rdev, wdev->netdev, buf, len, reconnect, GFP_KERNEL); + + if (!wdev->current_bss || + !ether_addr_equal(wdev->current_bss->pub.bssid, bssid)) +@@ -100,7 +101,8 @@ static void cfg80211_process_deauth(struct wireless_dev *wdev, + } + + static void cfg80211_process_disassoc(struct wireless_dev *wdev, +- const u8 *buf, size_t len) ++ const u8 *buf, size_t len, ++ bool reconnect) + { + struct cfg80211_registered_device *rdev = wiphy_to_rdev(wdev->wiphy); + struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)buf; +@@ -108,7 +110,8 @@ static void cfg80211_process_disassoc(struct wireless_dev *wdev, + u16 reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code); + bool from_ap = !ether_addr_equal(mgmt->sa, wdev->netdev->dev_addr); + +- nl80211_send_disassoc(rdev, wdev->netdev, buf, len, GFP_KERNEL); ++ nl80211_send_disassoc(rdev, wdev->netdev, buf, len, reconnect, ++ GFP_KERNEL); + + if (WARN_ON(!wdev->current_bss || + !ether_addr_equal(wdev->current_bss->pub.bssid, bssid))) +@@ -133,9 +136,9 @@ void cfg80211_rx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) + if (ieee80211_is_auth(mgmt->frame_control)) + cfg80211_process_auth(wdev, buf, len); + else if (ieee80211_is_deauth(mgmt->frame_control)) +- cfg80211_process_deauth(wdev, buf, len); ++ cfg80211_process_deauth(wdev, buf, len, false); + else if (ieee80211_is_disassoc(mgmt->frame_control)) +- cfg80211_process_disassoc(wdev, buf, len); ++ cfg80211_process_disassoc(wdev, buf, len, false); + } + EXPORT_SYMBOL(cfg80211_rx_mlme_mgmt); + +@@ -180,22 +183,23 @@ void cfg80211_abandon_assoc(struct net_device *dev, struct cfg80211_bss *bss) + } + EXPORT_SYMBOL(cfg80211_abandon_assoc); + +-void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len) ++void cfg80211_tx_mlme_mgmt(struct net_device *dev, const u8 *buf, size_t len, ++ bool reconnect) + { + struct wireless_dev *wdev = dev->ieee80211_ptr; + struct ieee80211_mgmt *mgmt = (void *)buf; + + ASSERT_WDEV_LOCK(wdev); + +- trace_cfg80211_tx_mlme_mgmt(dev, buf, len); ++ trace_cfg80211_tx_mlme_mgmt(dev, buf, len, reconnect); + + if (WARN_ON(len < 2)) + return; + + if (ieee80211_is_deauth(mgmt->frame_control)) +- cfg80211_process_deauth(wdev, buf, len); ++ cfg80211_process_deauth(wdev, buf, len, reconnect); + else +- cfg80211_process_disassoc(wdev, buf, len); ++ cfg80211_process_disassoc(wdev, buf, len, reconnect); + } + EXPORT_SYMBOL(cfg80211_tx_mlme_mgmt); + diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c -index 6b0bcec..c93a4e0 100644 +index b389cbf..132df74 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -630,6 +630,7 @@ const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { - .len = SAE_PASSWORD_MAX_LEN }, - [NL80211_ATTR_TWT_RESPONDER] = { .type = NLA_FLAG }, - [NL80211_ATTR_HE_OBSS_PD] = NLA_POLICY_NESTED(he_obss_pd_policy), +@@ -732,6 +732,8 @@ static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = { + NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), + [NL80211_ATTR_S1G_CAPABILITY_MASK] = + NLA_POLICY_EXACT_LEN(IEEE80211_S1G_CAPABILITY_LEN), ++ [NL80211_ATTR_RECONNECT_REQUESTED] = { .type = NLA_REJECT }, + [NL80211_ATTR_WIPHY_ANTENNA_GAIN] = { .type = NLA_U32 }, }; /* policy for the key attributes */ -@@ -2995,6 +2996,20 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) +@@ -3241,6 +3243,20 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info) return result; } @@ -3492,6 +5899,103 @@ index 6b0bcec..c93a4e0 100644 if (info->attrs[NL80211_ATTR_WIPHY_ANTENNA_TX] && info->attrs[NL80211_ATTR_WIPHY_ANTENNA_RX]) { u32 tx_ant, rx_ant; +@@ -15899,7 +15915,7 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, + const u8 *buf, size_t len, + enum nl80211_commands cmd, gfp_t gfp, + int uapsd_queues, const u8 *req_ies, +- size_t req_ies_len) ++ size_t req_ies_len, bool reconnect) + { + struct sk_buff *msg; + void *hdr; +@@ -15921,6 +15937,9 @@ static void nl80211_send_mlme_event(struct cfg80211_registered_device *rdev, + nla_put(msg, NL80211_ATTR_REQ_IE, req_ies_len, req_ies))) + goto nla_put_failure; + ++ if (reconnect && nla_put_flag(msg, NL80211_ATTR_RECONNECT_REQUESTED)) ++ goto nla_put_failure; ++ + if (uapsd_queues >= 0) { + struct nlattr *nla_wmm = + nla_nest_start_noflag(msg, NL80211_ATTR_STA_WME); +@@ -15949,7 +15968,8 @@ void nl80211_send_rx_auth(struct cfg80211_registered_device *rdev, + size_t len, gfp_t gfp) + { + nl80211_send_mlme_event(rdev, netdev, buf, len, +- NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0); ++ NL80211_CMD_AUTHENTICATE, gfp, -1, NULL, 0, ++ false); + } + + void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, +@@ -15959,23 +15979,25 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, + { + nl80211_send_mlme_event(rdev, netdev, buf, len, + NL80211_CMD_ASSOCIATE, gfp, uapsd_queues, +- req_ies, req_ies_len); ++ req_ies, req_ies_len, false); + } + + void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, +- size_t len, gfp_t gfp) ++ size_t len, bool reconnect, gfp_t gfp) + { + nl80211_send_mlme_event(rdev, netdev, buf, len, +- NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0); ++ NL80211_CMD_DEAUTHENTICATE, gfp, -1, NULL, 0, ++ reconnect); + } + + void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, const u8 *buf, +- size_t len, gfp_t gfp) ++ size_t len, bool reconnect, gfp_t gfp) + { + nl80211_send_mlme_event(rdev, netdev, buf, len, +- NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0); ++ NL80211_CMD_DISASSOCIATE, gfp, -1, NULL, 0, ++ reconnect); + } + + void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, +@@ -16006,7 +16028,7 @@ void cfg80211_rx_unprot_mlme_mgmt(struct net_device *dev, const u8 *buf, + + trace_cfg80211_rx_unprot_mlme_mgmt(dev, buf, len); + nl80211_send_mlme_event(rdev, dev, buf, len, cmd, GFP_ATOMIC, -1, +- NULL, 0); ++ NULL, 0, false); + } + EXPORT_SYMBOL(cfg80211_rx_unprot_mlme_mgmt); + +diff --git a/net/wireless/nl80211.h b/net/wireless/nl80211.h +index d3e8e42..a3f3877 100644 +--- a/net/wireless/nl80211.h ++++ b/net/wireless/nl80211.h +@@ -1,7 +1,7 @@ + /* SPDX-License-Identifier: GPL-2.0 */ + /* + * Portions of this file +- * Copyright (C) 2018 Intel Corporation ++ * Copyright (C) 2018, 2020 Intel Corporation + */ + #ifndef __NET_WIRELESS_NL80211_H + #define __NET_WIRELESS_NL80211_H +@@ -69,10 +69,12 @@ void nl80211_send_rx_assoc(struct cfg80211_registered_device *rdev, + const u8 *req_ies, size_t req_ies_len); + void nl80211_send_deauth(struct cfg80211_registered_device *rdev, + struct net_device *netdev, +- const u8 *buf, size_t len, gfp_t gfp); ++ const u8 *buf, size_t len, ++ bool reconnect, gfp_t gfp); + void nl80211_send_disassoc(struct cfg80211_registered_device *rdev, + struct net_device *netdev, +- const u8 *buf, size_t len, gfp_t gfp); ++ const u8 *buf, size_t len, ++ bool reconnect, gfp_t gfp); + void nl80211_send_auth_timeout(struct cfg80211_registered_device *rdev, + struct net_device *netdev, + const u8 *addr, gfp_t gfp); diff --git a/net/wireless/sysfs.c b/net/wireless/sysfs.c index 93d663c..bd4227b 100644 --- a/net/wireless/sysfs.c @@ -3537,3 +6041,35 @@ index 93d663c..bd4227b 100644 static ssize_t name_show(struct device *dev, struct device_attribute *attr, +diff --git a/net/wireless/trace.h b/net/wireless/trace.h +index 0a29cd1..e838ccc 100644 +--- a/net/wireless/trace.h ++++ b/net/wireless/trace.h +@@ -2684,19 +2684,23 @@ DEFINE_EVENT(netdev_frame_event, cfg80211_rx_mlme_mgmt, + ); + + TRACE_EVENT(cfg80211_tx_mlme_mgmt, +- TP_PROTO(struct net_device *netdev, const u8 *buf, int len), +- TP_ARGS(netdev, buf, len), ++ TP_PROTO(struct net_device *netdev, const u8 *buf, int len, ++ bool reconnect), ++ TP_ARGS(netdev, buf, len, reconnect), + TP_STRUCT__entry( + NETDEV_ENTRY + __dynamic_array(u8, frame, len) ++ __field(int, reconnect) + ), + TP_fast_assign( + NETDEV_ASSIGN; + memcpy(__get_dynamic_array(frame), buf, len); ++ __entry->reconnect = reconnect; + ), +- TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x", ++ TP_printk(NETDEV_PR_FMT ", ftype:0x%.2x reconnect:%d", + NETDEV_PR_ARG, +- le16_to_cpup((__le16 *)__get_dynamic_array(frame))) ++ le16_to_cpup((__le16 *)__get_dynamic_array(frame)), ++ __entry->reconnect) + ); + + DECLARE_EVENT_CLASS(netdev_mac_evt, diff --git a/recipes-kernel/mac80211/mac80211/0003-backport-of-ath-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0003-backport-of-ath-patches-from-openwrt.patch index a29f9e9..57376e3 100644 --- a/recipes-kernel/mac80211/mac80211/0003-backport-of-ath-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0003-backport-of-ath-patches-from-openwrt.patch @@ -1,7 +1,7 @@ -From c4762b3c27cd17589da336df4d2b1b5954200f8d Mon Sep 17 00:00:00 2001 +From ac9c73283fd0b8464a1b29d2e8e29a94a1f53fff Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:19:43 +0200 -Subject: [PATCH] FIX: [mac80211] backport of ath patches from openwrt +Date: Mon, 22 Mar 2021 16:37:02 +0100 +Subject: [PATCH] 0003 backport of ath patches from openwrt --- drivers/net/wireless/ath/Kconfig | 5 +- @@ -15,12 +15,12 @@ Subject: [PATCH] FIX: [mac80211] backport of ath patches from openwrt drivers/net/wireless/ath/ath10k/hw.h | 1 + drivers/net/wireless/ath/ath10k/leds.c | 101 ++++++ drivers/net/wireless/ath/ath10k/leds.h | 41 +++ - drivers/net/wireless/ath/ath10k/mac.c | 126 +++++-- + drivers/net/wireless/ath/ath10k/mac.c | 65 +++- drivers/net/wireless/ath/ath10k/thermal.h | 2 +- drivers/net/wireless/ath/ath10k/wmi-ops.h | 32 ++ drivers/net/wireless/ath/ath10k/wmi-tlv.c | 2 + - drivers/net/wireless/ath/ath10k/wmi.c | 72 +++- - drivers/net/wireless/ath/ath10k/wmi.h | 49 ++- + drivers/net/wireless/ath/ath10k/wmi.c | 54 +++ + drivers/net/wireless/ath/ath10k/wmi.h | 35 ++ drivers/net/wireless/ath/ath5k/ath5k.h | 1 + drivers/net/wireless/ath/ath5k/base.c | 8 +- drivers/net/wireless/ath/ath5k/debug.c | 93 ++++++ @@ -36,9 +36,9 @@ Subject: [PATCH] FIX: [mac80211] backport of ath patches from openwrt drivers/net/wireless/ath/ath9k/ar5008_phy.c | 72 ++-- drivers/net/wireless/ath/ath9k/ar9002_phy.h | 11 + drivers/net/wireless/ath/ath9k/ar9003_phy.c | 95 ++---- - drivers/net/wireless/ath/ath9k/ath9k.h | 34 +- + drivers/net/wireless/ath/ath9k/ath9k.h | 37 ++- .../net/wireless/ath/ath9k/ath9k_pci_owl_loader.c | 17 + - drivers/net/wireless/ath/ath9k/channel.c | 8 + + drivers/net/wireless/ath/ath9k/channel.c | 7 + drivers/net/wireless/ath/ath9k/common.c | 21 +- drivers/net/wireless/ath/ath9k/debug.c | 202 ++++++++++++ drivers/net/wireless/ath/ath9k/gpio.c | 365 +++++++++++++++++++-- @@ -47,18 +47,19 @@ Subject: [PATCH] FIX: [mac80211] backport of ath patches from openwrt drivers/net/wireless/ath/ath9k/hw-ops.h | 6 + drivers/net/wireless/ath/ath9k/hw.c | 154 ++++++--- drivers/net/wireless/ath/ath9k/hw.h | 12 + - drivers/net/wireless/ath/ath9k/init.c | 49 ++- + drivers/net/wireless/ath/ath9k/init.c | 53 ++- drivers/net/wireless/ath/ath9k/mac.c | 9 +- - drivers/net/wireless/ath/ath9k/main.c | 13 + + drivers/net/wireless/ath/ath9k/main.c | 12 + drivers/net/wireless/ath/ath9k/pci.c | 1 + drivers/net/wireless/ath/ath9k/phy.h | 3 + + drivers/net/wireless/ath/ath9k/xmit.c | 6 + drivers/net/wireless/ath/regd.c | 72 ++-- drivers/net/wireless/ath/regd_common.h | 3 + include/linux/ath5k_platform.h | 30 ++ - include/linux/ath9k_platform.h | 9 + + include/linux/ath9k_platform.h | 7 + local-symbols | 4 + net/wireless/reg.c | 3 + - 54 files changed, 2137 insertions(+), 293 deletions(-) + 55 files changed, 2082 insertions(+), 264 deletions(-) create mode 100644 drivers/net/wireless/ath/ath10k/leds.c create mode 100644 drivers/net/wireless/ath/ath10k/leds.h create mode 100644 drivers/net/wireless/ath/ath9k/hsr.c @@ -66,7 +67,7 @@ Subject: [PATCH] FIX: [mac80211] backport of ath patches from openwrt create mode 100644 include/linux/ath5k_platform.h diff --git a/drivers/net/wireless/ath/Kconfig b/drivers/net/wireless/ath/Kconfig -index b8a8688..53588af 100644 +index 26ed519..aa2b633 100644 --- a/drivers/net/wireless/ath/Kconfig +++ b/drivers/net/wireless/ath/Kconfig @@ -1,6 +1,6 @@ @@ -86,12 +87,12 @@ index b8a8688..53588af 100644 + config ATH_DEBUG bool "Atheros wireless debugging" - ---help--- + help diff --git a/drivers/net/wireless/ath/Makefile b/drivers/net/wireless/ath/Makefile -index 113420d..0a6a773 100644 +index 7fa5fa1..d154c96 100644 --- a/drivers/net/wireless/ath/Makefile +++ b/drivers/net/wireless/ath/Makefile -@@ -14,10 +14,10 @@ ath-objs := main.o \ +@@ -15,10 +15,10 @@ ath-objs := main.o \ regd.o \ hw.o \ key.o \ @@ -131,10 +132,10 @@ index a547b2d..2a18e2e 100644 extern const char *ath_bus_type_strings[]; static inline const char *ath_bus_type_to_string(enum ath_bus_type bustype) diff --git a/drivers/net/wireless/ath/ath10k/Kconfig b/drivers/net/wireless/ath/ath10k/Kconfig -index 56a25d7..754c92d 100644 +index db70f7f..e360751 100644 --- a/drivers/net/wireless/ath/ath10k/Kconfig +++ b/drivers/net/wireless/ath/ath10k/Kconfig -@@ -71,6 +71,16 @@ config ATH10K_DEBUGFS +@@ -70,6 +70,16 @@ config ATH10K_DEBUGFS If unsure, say Y to make it easier to debug problems. @@ -151,8 +152,8 @@ index 56a25d7..754c92d 100644 config ATH10K_SPECTRAL bool "Atheros ath10k spectral scan support" depends on ATH10K_DEBUGFS -@@ -87,6 +97,12 @@ config ATH10K_TRACING - ---help--- +@@ -86,6 +96,12 @@ config ATH10K_TRACING + help Select this to ath10k use tracing infrastructure. +config ATH10K_THERMAL @@ -179,10 +180,10 @@ index 24d846a..e040d84 100644 ath10k_core-$(CONFIG_PM) += wow.o ath10k_core-$(CONFIG_DEV_COREDUMP) += coredump.o diff --git a/drivers/net/wireless/ath/ath10k/core.c b/drivers/net/wireless/ath/ath10k/core.c -index 383d4fa..9d5bede 100644 +index d73ad60..9c57698 100644 --- a/drivers/net/wireless/ath/ath10k/core.c +++ b/drivers/net/wireless/ath/ath10k/core.c -@@ -24,6 +24,7 @@ +@@ -25,6 +25,7 @@ #include "testmode.h" #include "wmi-ops.h" #include "coredump.h" @@ -190,7 +191,7 @@ index 383d4fa..9d5bede 100644 unsigned int ath10k_debug_mask; EXPORT_SYMBOL(ath10k_debug_mask); -@@ -60,6 +61,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { +@@ -61,6 +62,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .dev_id = QCA988X_2_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca988x hw2.0", @@ -206,7 +207,7 @@ index 383d4fa..9d5bede 100644 .patch_load_addr = QCA9887_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL, -@@ -337,6 +340,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { +@@ -335,6 +338,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .dev_id = QCA99X0_2_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca99x0 hw2.0", @@ -214,7 +215,7 @@ index 383d4fa..9d5bede 100644 .patch_load_addr = QCA99X0_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .otp_exe_param = 0x00000700, -@@ -378,6 +382,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { +@@ -375,6 +379,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .dev_id = QCA9984_1_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca9984/qca9994 hw1.0", @@ -222,7 +223,7 @@ index 383d4fa..9d5bede 100644 .patch_load_addr = QCA9984_HW_1_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, -@@ -426,6 +431,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { +@@ -422,6 +427,7 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = { .dev_id = QCA9888_2_0_DEVICE_ID, .bus = ATH10K_BUS_PCI, .name = "qca9888 hw2.0", @@ -230,7 +231,7 @@ index 383d4fa..9d5bede 100644 .patch_load_addr = QCA9888_HW_2_0_PATCH_LOAD_ADDR, .uart_pin = 7, .cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH, -@@ -2791,6 +2797,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, +@@ -2904,6 +2910,10 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode, goto err_hif_stop; } @@ -241,7 +242,7 @@ index 383d4fa..9d5bede 100644 return 0; err_hif_stop: -@@ -3047,9 +3057,18 @@ static void ath10k_core_register_work(struct work_struct *work) +@@ -3162,9 +3172,18 @@ static void ath10k_core_register_work(struct work_struct *work) goto err_spectral_destroy; } @@ -260,7 +261,7 @@ index 383d4fa..9d5bede 100644 err_spectral_destroy: ath10k_spectral_destroy(ar); err_debug_destroy: -@@ -3074,6 +3093,16 @@ int ath10k_core_register(struct ath10k *ar, +@@ -3189,6 +3208,16 @@ int ath10k_core_register(struct ath10k *ar, queue_work(ar->workqueue, &ar->register_work); @@ -277,7 +278,7 @@ index 383d4fa..9d5bede 100644 return 0; } EXPORT_SYMBOL(ath10k_core_register); -@@ -3085,6 +3114,8 @@ void ath10k_core_unregister(struct ath10k *ar) +@@ -3200,6 +3229,8 @@ void ath10k_core_unregister(struct ath10k *ar) if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags)) return; @@ -287,7 +288,7 @@ index 383d4fa..9d5bede 100644 /* Stop spectral before unregistering from mac80211 to remove the * relayfs debugfs file cleanly. Otherwise the parent debugfs tree diff --git a/drivers/net/wireless/ath/ath10k/core.h b/drivers/net/wireless/ath/ath10k/core.h -index 80d2f64..2dae928 100644 +index d8701c2..507c902 100644 --- a/drivers/net/wireless/ath/ath10k/core.h +++ b/drivers/net/wireless/ath/ath10k/core.h @@ -14,6 +14,7 @@ @@ -298,7 +299,7 @@ index 80d2f64..2dae928 100644 #include "htt.h" #include "htc.h" -@@ -1170,6 +1171,13 @@ struct ath10k { +@@ -1237,6 +1238,13 @@ struct ath10k { } testmode; struct { @@ -310,24 +311,24 @@ index 80d2f64..2dae928 100644 + + struct { /* protected by data_lock */ + u32 rx_crc_err_drop; u32 fw_crash_counter; - u32 fw_warm_reset_counter; -@@ -1211,6 +1219,10 @@ struct ath10k { - struct ath10k_bus_params bus_param; - struct completion peer_delete_done; +@@ -1282,6 +1290,10 @@ struct ath10k { + bool coex_support; + int coex_gpio_pin; +#ifdef CPTCFG_MAC80211_LEDS + const char *led_default_trigger; +#endif + /* must be last */ - u8 drv_priv[0] __aligned(sizeof(void *)); + u8 drv_priv[] __aligned(sizeof(void *)); }; diff --git a/drivers/net/wireless/ath/ath10k/htt.h b/drivers/net/wireless/ath/ath10k/htt.h -index 4eaaa84..9c8ad11 100644 +index 5df6379..c2a5825 100644 --- a/drivers/net/wireless/ath/ath10k/htt.h +++ b/drivers/net/wireless/ath/ath10k/htt.h -@@ -2219,7 +2219,7 @@ struct htt_rx_chan_info { +@@ -2242,7 +2242,7 @@ struct htt_rx_chan_info { * Should be: sizeof(struct htt_host_rx_desc) + max rx MSDU size, * rounded up to a cache line size. */ @@ -337,10 +338,10 @@ index 4eaaa84..9c8ad11 100644 /* Refill a bunch of RX buffers for each refill round so that FW/HW can handle diff --git a/drivers/net/wireless/ath/ath10k/hw.h b/drivers/net/wireless/ath/ath10k/hw.h -index 6cb1845..4417204 100644 +index c78090e..5bb900c 100644 --- a/drivers/net/wireless/ath/ath10k/hw.h +++ b/drivers/net/wireless/ath/ath10k/hw.h -@@ -514,6 +514,7 @@ struct ath10k_hw_params { +@@ -517,6 +517,7 @@ struct ath10k_hw_params { const char *name; u32 patch_load_addr; int uart_pin; @@ -503,10 +504,10 @@ index 0000000..a0f5c84 +#endif +#endif /* _LEDS_H_ */ diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c -index aad1bda..7946d3b 100644 +index 30dc036..d07a4a1 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -23,6 +23,7 @@ +@@ -24,6 +24,7 @@ #include "wmi-tlv.h" #include "wmi-ops.h" #include "wow.h" @@ -514,7 +515,7 @@ index aad1bda..7946d3b 100644 /*********/ /* Rates */ -@@ -1008,6 +1009,40 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) +@@ -1005,6 +1006,40 @@ static inline int ath10k_vdev_setup_sync(struct ath10k *ar) return ar->last_wmi_vdev_start_status; } @@ -555,7 +556,7 @@ index aad1bda..7946d3b 100644 static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) { struct cfg80211_chan_def *chandef = NULL; -@@ -1040,7 +1075,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) +@@ -1037,7 +1072,8 @@ static int ath10k_monitor_vdev_start(struct ath10k *ar, int vdev_id) arg.channel.min_power = 0; arg.channel.max_power = channel->max_power * 2; arg.channel.max_reg_power = channel->max_reg_power * 2; @@ -565,7 +566,7 @@ index aad1bda..7946d3b 100644 reinit_completion(&ar->vdev_setup_done); reinit_completion(&ar->vdev_delete_done); -@@ -1486,7 +1522,8 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, +@@ -1483,7 +1519,8 @@ static int ath10k_vdev_start_restart(struct ath10k_vif *arvif, arg.channel.min_power = 0; arg.channel.max_power = chandef->chan->max_power * 2; arg.channel.max_reg_power = chandef->chan->max_reg_power * 2; @@ -575,87 +576,7 @@ index aad1bda..7946d3b 100644 if (arvif->vdev_type == WMI_VDEV_TYPE_AP) { arg.ssid = arvif->u.ap.ssid; -@@ -2515,7 +2552,7 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, - const u16 *vht_mcs_mask; - u8 ampdu_factor; - u8 max_nss, vht_mcs; -- int i; -+ int i, nss160; - - if (WARN_ON(ath10k_mac_vif_chan(vif, &def))) - return; -@@ -2575,23 +2612,45 @@ static void ath10k_peer_assoc_h_vht(struct ath10k *ar, - __le16_to_cpu(vht_cap->vht_mcs.tx_highest); - arg->peer_vht_rates.tx_mcs_set = ath10k_peer_assoc_h_vht_limit( - __le16_to_cpu(vht_cap->vht_mcs.tx_mcs_map), vht_mcs_mask); -+ arg->peer_bw_rxnss_override = 0; -+ nss160 = 1; /* 1x1 default config for VHT160 */ - -- ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x\n", -- sta->addr, arg->peer_max_mpdu, arg->peer_flags); -+ /* only local 4x4 configuration do support 2x2 for VHT160, -+ * everything else must use 1x1 -+ */ - -- if (arg->peer_vht_rates.rx_max_rate && -- (sta->vht_cap.cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK)) { -- switch (arg->peer_vht_rates.rx_max_rate) { -- case 1560: -- /* Must be 2x2 at 160Mhz is all it can do. */ -- arg->peer_bw_rxnss_override = 2; -- break; -- case 780: -- /* Can only do 1x1 at 160Mhz (Long Guard Interval) */ -- arg->peer_bw_rxnss_override = 1; -- break; -- } -+ if (ar->cfg_rx_chainmask == 15) -+ nss160 = arg->peer_num_spatial_streams <= 2 ? 1 : 2; -+ -+ /* if peer provides 1x1 nss160 information using max rate -+ * vht information, we reduce local nss160 to 1x1. -+ * consider that it has been observed that some client -+ * devices provide zero here, no matter which transmission -+ * rate is possible. in that case the local nss configuration -+ * will be used at maxmimum configuration possible. (see above) -+ */ -+ -+ if (arg->peer_vht_rates.rx_max_rate == 780) -+ nss160 = 1; -+ -+ /* in case if peer is connected with vht160 or vht80+80, -+ * we need to properly adjust rxnss parameters otherwise -+ * firmware will raise a assert -+ */ -+ switch (arg->peer_phymode) { -+ case MODE_11AC_VHT80_80: -+ arg->peer_bw_rxnss_override = BW_NSS_FWCONF_80_80(nss160); -+ /* fall through */ -+ case MODE_11AC_VHT160: -+ arg->peer_bw_rxnss_override |= BW_NSS_FWCONF_160(nss160); -+ break; -+ default: -+ break; - } -+ -+ ath10k_dbg(ar, ATH10K_DBG_MAC, "mac vht peer %pM max_mpdu %d flags 0x%x peer_bw_rxnss_override 0x%x\n", -+ sta->addr, arg->peer_max_mpdu, arg->peer_flags, -+ arg->peer_bw_rxnss_override); - } - - static void ath10k_peer_assoc_h_qos(struct ath10k *ar, -@@ -2743,9 +2802,9 @@ static int ath10k_peer_assoc_prepare(struct ath10k *ar, - ath10k_peer_assoc_h_crypto(ar, vif, sta, arg); - ath10k_peer_assoc_h_rates(ar, vif, sta, arg); - ath10k_peer_assoc_h_ht(ar, vif, sta, arg); -+ ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); - ath10k_peer_assoc_h_vht(ar, vif, sta, arg); - ath10k_peer_assoc_h_qos(ar, vif, sta, arg); -- ath10k_peer_assoc_h_phymode(ar, vif, sta, arg); - - return 0; - } -@@ -3145,7 +3204,8 @@ static int ath10k_update_channel_list(struct ath10k *ar) +@@ -3254,7 +3291,8 @@ static int ath10k_update_channel_list(struct ath10k *ar) ch->min_power = 0; ch->max_power = channel->max_power * 2; ch->max_reg_power = channel->max_reg_power * 2; @@ -665,21 +586,7 @@ index aad1bda..7946d3b 100644 ch->reg_class_id = 0; /* FIXME */ /* FIXME: why use only legacy modes, why not any -@@ -4553,13 +4613,6 @@ static struct ieee80211_sta_vht_cap ath10k_create_vht_cap(struct ath10k *ar) - vht_cap.cap |= val; - } - -- /* Currently the firmware seems to be buggy, don't enable 80+80 -- * mode until that's resolved. -- */ -- if ((ar->vht_cap_info & IEEE80211_VHT_CAP_SHORT_GI_160) && -- (ar->vht_cap_info & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_MASK) == 0) -- vht_cap.cap |= IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ; -- - mcs_map = 0; - for (i = 0; i < 8; i++) { - if ((i < ar->num_rf_chains) && (ar->cfg_tx_chainmask & BIT(i))) -@@ -8673,6 +8726,21 @@ static int ath10k_mac_init_rd(struct ath10k *ar) +@@ -9713,6 +9751,21 @@ static int ath10k_mac_init_rd(struct ath10k *ar) return 0; } @@ -701,7 +608,7 @@ index aad1bda..7946d3b 100644 int ath10k_mac_register(struct ath10k *ar) { static const u32 cipher_suites[] = { -@@ -9000,6 +9068,12 @@ int ath10k_mac_register(struct ath10k *ar) +@@ -10062,6 +10115,12 @@ int ath10k_mac_register(struct ath10k *ar) ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER; @@ -728,13 +635,13 @@ index 5fdb020..d76c307 100644 void ath10k_thermal_unregister(struct ath10k *ar); void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature); diff --git a/drivers/net/wireless/ath/ath10k/wmi-ops.h b/drivers/net/wireless/ath/ath10k/wmi-ops.h -index 1491c25..a274dc4 100644 +index aa57d80..f3f6b59 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-ops.h +++ b/drivers/net/wireless/ath/ath10k/wmi-ops.h -@@ -216,7 +216,10 @@ struct wmi_ops { - struct sk_buff *(*gen_bb_timing) - (struct ath10k *ar, +@@ -226,7 +226,10 @@ struct wmi_ops { const struct wmi_bb_timing_cfg_arg *arg); + struct sk_buff *(*gen_per_peer_per_tid_cfg)(struct ath10k *ar, + const struct wmi_per_peer_per_tid_cfg_arg *arg); + struct sk_buff *(*gen_gpio_config)(struct ath10k *ar, u32 gpio_num, + u32 input, u32 pull_type, u32 intr_mode); @@ -742,7 +649,7 @@ index 1491c25..a274dc4 100644 }; int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id); -@@ -1080,6 +1083,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *ar, +@@ -1122,6 +1125,35 @@ ath10k_wmi_force_fw_hang(struct ath10k *ar, return ath10k_wmi_cmd_send(ar, skb, ar->wmi.cmd->force_fw_hang_cmdid); } @@ -779,10 +686,10 @@ index 1491c25..a274dc4 100644 ath10k_wmi_dbglog_cfg(struct ath10k *ar, u64 module_enable, u32 log_level) { diff --git a/drivers/net/wireless/ath/ath10k/wmi-tlv.c b/drivers/net/wireless/ath/ath10k/wmi-tlv.c -index eb0c963..e0239f4 100644 +index 7b58341..802d443 100644 --- a/drivers/net/wireless/ath/ath10k/wmi-tlv.c +++ b/drivers/net/wireless/ath/ath10k/wmi-tlv.c -@@ -4367,6 +4367,8 @@ static const struct wmi_ops wmi_tlv_ops = { +@@ -4585,6 +4585,8 @@ static const struct wmi_ops wmi_tlv_ops = { .gen_echo = ath10k_wmi_tlv_op_gen_echo, .gen_vdev_spectral_conf = ath10k_wmi_tlv_op_gen_vdev_spectral_conf, .gen_vdev_spectral_enable = ath10k_wmi_tlv_op_gen_vdev_spectral_enable, @@ -792,32 +699,10 @@ index eb0c963..e0239f4 100644 static const struct wmi_peer_flags_map wmi_tlv_peer_flags_map = { diff --git a/drivers/net/wireless/ath/ath10k/wmi.c b/drivers/net/wireless/ath/ath10k/wmi.c -index 8a2cee3..5d32e88 100644 +index b2f3db5..b4506ed 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.c +++ b/drivers/net/wireless/ath/ath10k/wmi.c -@@ -1700,13 +1700,18 @@ void ath10k_wmi_put_wmi_channel(struct wmi_channel *ch, - flags |= WMI_CHAN_FLAG_HT40_PLUS; - if (arg->chan_radar) - flags |= WMI_CHAN_FLAG_DFS; -- -+ ch->band_center_freq2 = 0; - ch->mhz = __cpu_to_le32(arg->freq); - ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1); - if (arg->mode == MODE_11AC_VHT80_80) - ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq2); -- else -- ch->band_center_freq2 = 0; -+ if (arg->mode == MODE_11AC_VHT160) { -+ if (arg->freq < arg->band_center_freq1) -+ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 - 40); -+ else -+ ch->band_center_freq1 = __cpu_to_le32(arg->band_center_freq1 + 40); -+ ch->band_center_freq2 = __cpu_to_le32(arg->band_center_freq1); -+ } - ch->min_power = arg->min_power; - ch->max_power = arg->max_power; - ch->reg_power = arg->max_reg_power; -@@ -7367,6 +7372,49 @@ ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, +@@ -7468,6 +7468,49 @@ ath10k_wmi_op_gen_peer_set_param(struct ath10k *ar, u32 vdev_id, return skb; } @@ -867,21 +752,7 @@ index 8a2cee3..5d32e88 100644 static struct sk_buff * ath10k_wmi_op_gen_set_psmode(struct ath10k *ar, u32 vdev_id, enum wmi_sta_ps_mode psmode) -@@ -7552,12 +7600,7 @@ ath10k_wmi_peer_assoc_fill_10_4(struct ath10k *ar, void *buf, - struct wmi_10_4_peer_assoc_complete_cmd *cmd = buf; - - ath10k_wmi_peer_assoc_fill_10_2(ar, buf, arg); -- if (arg->peer_bw_rxnss_override) -- cmd->peer_bw_rxnss_override = -- __cpu_to_le32((arg->peer_bw_rxnss_override - 1) | -- BIT(PEER_BW_RXNSS_OVERRIDE_OFFSET)); -- else -- cmd->peer_bw_rxnss_override = 0; -+ cmd->peer_bw_rxnss_override = __cpu_to_le32(arg->peer_bw_rxnss_override); - } - - static int -@@ -9029,6 +9072,9 @@ static const struct wmi_ops wmi_ops = { +@@ -9156,6 +9199,9 @@ static const struct wmi_ops wmi_ops = { .fw_stats_fill = ath10k_wmi_main_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, .gen_echo = ath10k_wmi_op_gen_echo, @@ -891,7 +762,7 @@ index 8a2cee3..5d32e88 100644 /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ -@@ -9099,6 +9145,8 @@ static const struct wmi_ops wmi_10_1_ops = { +@@ -9226,6 +9272,8 @@ static const struct wmi_ops wmi_10_1_ops = { .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, .gen_echo = ath10k_wmi_op_gen_echo, @@ -900,7 +771,7 @@ index 8a2cee3..5d32e88 100644 /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ -@@ -9171,6 +9219,8 @@ static const struct wmi_ops wmi_10_2_ops = { +@@ -9298,6 +9346,8 @@ static const struct wmi_ops wmi_10_2_ops = { .gen_delba_send = ath10k_wmi_op_gen_delba_send, .fw_stats_fill = ath10k_wmi_10x_op_fw_stats_fill, .get_vdev_subtype = ath10k_wmi_op_get_vdev_subtype, @@ -909,7 +780,7 @@ index 8a2cee3..5d32e88 100644 /* .gen_pdev_enable_adaptive_cca not implemented */ }; -@@ -9242,6 +9292,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { +@@ -9369,6 +9419,8 @@ static const struct wmi_ops wmi_10_2_4_ops = { ath10k_wmi_op_gen_pdev_enable_adaptive_cca, .get_vdev_subtype = ath10k_wmi_10_2_4_op_get_vdev_subtype, .gen_bb_timing = ath10k_wmi_10_2_4_op_gen_bb_timing, @@ -918,7 +789,7 @@ index 8a2cee3..5d32e88 100644 /* .gen_bcn_tmpl not implemented */ /* .gen_prb_tmpl not implemented */ /* .gen_p2p_go_bcn_ie not implemented */ -@@ -9322,6 +9374,8 @@ static const struct wmi_ops wmi_10_4_ops = { +@@ -9450,6 +9502,8 @@ static const struct wmi_ops wmi_10_4_ops = { .gen_pdev_bss_chan_info_req = ath10k_wmi_10_2_op_gen_pdev_bss_chan_info, .gen_echo = ath10k_wmi_op_gen_echo, .gen_pdev_get_tpc_config = ath10k_wmi_10_2_4_op_gen_pdev_get_tpc_config, @@ -928,10 +799,10 @@ index 8a2cee3..5d32e88 100644 int ath10k_wmi_attach(struct ath10k *ar) diff --git a/drivers/net/wireless/ath/ath10k/wmi.h b/drivers/net/wireless/ath/ath10k/wmi.h -index e80dbe7..1c819a5 100644 +index 66ecf09..41796e3 100644 --- a/drivers/net/wireless/ath/ath10k/wmi.h +++ b/drivers/net/wireless/ath/ath10k/wmi.h -@@ -3005,6 +3005,41 @@ enum wmi_10_4_feature_mask { +@@ -3027,6 +3027,41 @@ enum wmi_10_4_feature_mask { }; @@ -973,29 +844,8 @@ index e80dbe7..1c819a5 100644 struct wmi_ext_resource_config_10_4_cmd { /* contains enum wmi_host_platform_type */ __le32 host_platform_config; -@@ -6478,7 +6513,19 @@ struct wmi_10_2_peer_assoc_complete_cmd { - __le32 info0; /* WMI_PEER_ASSOC_INFO0_ */ - } __packed; - --#define PEER_BW_RXNSS_OVERRIDE_OFFSET 31 -+#define BW_NSS_FWCONF_MAP_ENABLE BIT(31) -+#define BW_NSS_FWCONF_MAP_160MHZ_LSB (0) -+#define BW_NSS_FWCONF_MAP_160MHZ_MASK (0x00000007) -+#define BW_NSS_FWCONF_MAP_80_80MHZ_LSB (3) -+#define BW_NSS_FWCONF_MAP_80_80MHZ_MASK (0x00000038) -+#define BW_NSS_FWCONF_MAP_MASK (0x0000003F) -+ -+#define GET_BW_NSS_FWCONF_160(x) (MS(x, BW_NSS_FWCONF_MAP_160MHZ) + 1) -+#define GET_BW_NSS_FWCONF_80_80(x) (MS(x, BW_NSS_FWCONF_MAP_80_80MHZ) + 1) -+ -+/* Values defined to set 160 MHz Bandwidth NSS Mapping into FW*/ -+#define BW_NSS_FWCONF_160(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_160MHZ)) -+#define BW_NSS_FWCONF_80_80(x) (BW_NSS_FWCONF_MAP_ENABLE | SM(x - 1, BW_NSS_FWCONF_MAP_80_80MHZ)) - - struct wmi_10_4_peer_assoc_complete_cmd { - struct wmi_10_2_peer_assoc_complete_cmd cmd; diff --git a/drivers/net/wireless/ath/ath5k/ath5k.h b/drivers/net/wireless/ath/ath5k/ath5k.h -index f73c794..211a8d9 100644 +index 0433631..cff4f6f 100644 --- a/drivers/net/wireless/ath/ath5k/ath5k.h +++ b/drivers/net/wireless/ath/ath5k/ath5k.h @@ -1372,6 +1372,7 @@ struct ath5k_hw { @@ -1007,7 +857,7 @@ index f73c794..211a8d9 100644 /* Antenna Control */ diff --git a/drivers/net/wireless/ath/ath5k/base.c b/drivers/net/wireless/ath/ath5k/base.c -index c15f4dc..d546e52 100644 +index 0575ca7..7b70bc1 100644 --- a/drivers/net/wireless/ath/ath5k/base.c +++ b/drivers/net/wireless/ath/ath5k/base.c @@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, struct cfg80211_chan_def *chandef) @@ -1047,10 +897,10 @@ index c15f4dc..d546e52 100644 static const struct ieee80211_iface_combination if_comb = { diff --git a/drivers/net/wireless/ath/ath5k/debug.c b/drivers/net/wireless/ath/ath5k/debug.c -index 94f7004..c325081 100644 +index 4b41160..257101e 100644 --- a/drivers/net/wireless/ath/ath5k/debug.c +++ b/drivers/net/wireless/ath/ath5k/debug.c -@@ -822,6 +822,97 @@ static const struct file_operations fops_ani = { +@@ -803,6 +803,97 @@ static const struct file_operations fops_ani = { .llseek = default_llseek, }; @@ -1148,7 +998,7 @@ index 94f7004..c325081 100644 /* debugfs: queues etc */ -@@ -1016,6 +1107,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah) +@@ -997,6 +1088,8 @@ ath5k_debug_init_device(struct ath5k_hw *ah) debugfs_create_file("queue", 0600, phydir, ah, &fops_queue); debugfs_create_bool("32khz_clock", 0600, phydir, &ah->ah_use_32khz_clock); @@ -1220,7 +1070,7 @@ index 5e866a1..47dd580 100644 ret = -ELNRNG; goto end; diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c -index d5ee32c..9dcf379 100644 +index 43b4ae8..9c0a2e2 100644 --- a/drivers/net/wireless/ath/ath5k/pci.c +++ b/drivers/net/wireless/ath/ath5k/pci.c @@ -20,6 +20,7 @@ @@ -1287,7 +1137,7 @@ index d5ee32c..9dcf379 100644 for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) { diff --git a/drivers/net/wireless/ath/ath5k/reset.c b/drivers/net/wireless/ath/ath5k/reset.c -index 56d7925..baf0b9d 100644 +index 9fdb528..eabf225 100644 --- a/drivers/net/wireless/ath/ath5k/reset.c +++ b/drivers/net/wireless/ath/ath5k/reset.c @@ -1154,6 +1154,7 @@ ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, @@ -1307,7 +1157,7 @@ index 56d7925..baf0b9d 100644 /* Disable sleep clock operation diff --git a/drivers/net/wireless/ath/ath9k/Kconfig b/drivers/net/wireless/ath/ath9k/Kconfig -index ba8f1a0..3d8dfe3 100644 +index 491c54a..01e7f0d 100644 --- a/drivers/net/wireless/ath/ath9k/Kconfig +++ b/drivers/net/wireless/ath/ath9k/Kconfig @@ -60,6 +60,19 @@ config ATH9K_AHB @@ -1343,7 +1193,7 @@ index 847c8a8..6427bc6 100644 ath9k-$(CPTCFG_ATH9K_DEBUGFS) += debug.o diff --git a/drivers/net/wireless/ath/ath9k/ahb.c b/drivers/net/wireless/ath/ath9k/ahb.c -index 63019c3..5ea040a 100644 +index cdefb8e..762de53 100644 --- a/drivers/net/wireless/ath/ath9k/ahb.c +++ b/drivers/net/wireless/ath/ath9k/ahb.c @@ -20,7 +20,15 @@ @@ -1675,10 +1525,10 @@ index c40965b..f66f7ed 100644 #define ATH9K_SIG_FIRSTEP_SETTING_MIN 0 #define ATH9K_SIG_FIRSTEP_SETTING_MAX 20 diff --git a/drivers/net/wireless/ath/ath9k/ar5008_phy.c b/drivers/net/wireless/ath/ath9k/ar5008_phy.c -index dae9540..8e903d8 100644 +index 2fa3083..38750de 100644 --- a/drivers/net/wireless/ath/ath9k/ar5008_phy.c +++ b/drivers/net/wireless/ath/ath9k/ar5008_phy.c -@@ -949,55 +949,6 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, +@@ -978,55 +978,6 @@ static bool ar5008_hw_ani_control_new(struct ath_hw *ah, * on == 0 means more noise imm */ u32 on = param ? 1 : 0; @@ -1734,7 +1584,7 @@ index dae9540..8e903d8 100644 if (on) REG_SET_BIT(ah, AR_PHY_SFCORR_LOW, -@@ -1320,9 +1271,30 @@ void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, +@@ -1349,9 +1300,30 @@ void ar5008_hw_init_rate_txpower(struct ath_hw *ah, int16_t *rate_array, } } @@ -1765,7 +1615,7 @@ index dae9540..8e903d8 100644 static const u32 ar5416_cca_regs[6] = { AR_PHY_CCA, AR_PHY_CH1_CCA, -@@ -1337,6 +1309,8 @@ int ar5008_hw_attach_phy_ops(struct ath_hw *ah) +@@ -1366,6 +1338,8 @@ int ar5008_hw_attach_phy_ops(struct ath_hw *ah) if (ret) return ret; @@ -1945,7 +1795,7 @@ index 7ec5610..6f1a46d 100644 ops->antdiv_comb_conf_set = ar9003_hw_antdiv_comb_conf_set; ops->spectral_scan_config = ar9003_hw_spectral_scan_config; diff --git a/drivers/net/wireless/ath/ath9k/ath9k.h b/drivers/net/wireless/ath/ath9k/ath9k.h -index 6a35765..6601631 100644 +index ff591e2..b24ea28 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k.h +++ b/drivers/net/wireless/ath/ath9k/ath9k.h @@ -24,6 +24,8 @@ @@ -1966,7 +1816,17 @@ index 6a35765..6601631 100644 #define ATH_TXBUF 512 #define ATH_TXBUF_RESERVE 5 #define ATH_TXMAXTRY 13 -@@ -843,6 +845,9 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) +@@ -177,7 +179,8 @@ struct ath_frame_info { + s8 txq; + u8 keyix; + u8 rtscts_rate; +- u8 retries : 7; ++ u8 retries : 6; ++ u8 dyn_smps : 1; + u8 baw_tracked : 1; + u8 tx_power; + enum ath9k_key_type keytype:2; +@@ -843,6 +846,9 @@ static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size) #ifdef CPTCFG_MAC80211_LEDS void ath_init_leds(struct ath_softc *sc); void ath_deinit_leds(struct ath_softc *sc); @@ -1976,7 +1836,7 @@ index 6a35765..6601631 100644 #else static inline void ath_init_leds(struct ath_softc *sc) { -@@ -979,6 +984,21 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); +@@ -979,6 +985,21 @@ void ath_ant_comb_scan(struct ath_softc *sc, struct ath_rx_status *rs); #define ATH9K_NUM_CHANCTX 2 /* supports 2 operating channels */ @@ -1998,7 +1858,7 @@ index 6a35765..6601631 100644 struct ath_softc { struct ieee80211_hw *hw; struct device *dev; -@@ -992,6 +1012,9 @@ struct ath_softc { +@@ -992,6 +1013,9 @@ struct ath_softc { struct ath_hw *sc_ah; void __iomem *mem; int irq; @@ -2008,7 +1868,7 @@ index 6a35765..6601631 100644 spinlock_t sc_serial_rw; spinlock_t sc_pm_lock; spinlock_t sc_pcu_lock; -@@ -1032,9 +1055,12 @@ struct ath_softc { +@@ -1032,9 +1056,12 @@ struct ath_softc { spinlock_t chan_lock; #ifdef CPTCFG_MAC80211_LEDS @@ -2025,10 +1885,10 @@ index 6a35765..6601631 100644 #ifdef CPTCFG_ATH9K_DEBUGFS diff --git a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c -index 60731e0..e78699d 100644 +index 56d1a77..8160e72 100644 --- a/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c +++ b/drivers/net/wireless/ath/ath9k/ath9k_pci_owl_loader.c -@@ -104,6 +104,7 @@ static void owl_fw_cb(const struct firmware *fw, void *context) +@@ -103,6 +103,7 @@ static void owl_fw_cb(const struct firmware *fw, void *context) { struct pci_dev *pdev = (struct pci_dev *)context; struct owl_ctx *ctx = (struct owl_ctx *)pci_get_drvdata(pdev); @@ -2036,7 +1896,7 @@ index 60731e0..e78699d 100644 struct pci_bus *bus; complete(&ctx->eeprom_load); -@@ -119,6 +120,16 @@ static void owl_fw_cb(const struct firmware *fw, void *context) +@@ -118,6 +119,16 @@ static void owl_fw_cb(const struct firmware *fw, void *context) goto release; } @@ -2053,7 +1913,7 @@ index 60731e0..e78699d 100644 if (ath9k_pci_fixup(pdev, (const u16 *)fw->data, fw->size)) goto release; -@@ -138,8 +149,14 @@ release: +@@ -137,8 +148,14 @@ release: static const char *owl_get_eeprom_name(struct pci_dev *pdev) { struct device *dev = &pdev->dev; @@ -2069,31 +1929,30 @@ index 60731e0..e78699d 100644 eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL); diff --git a/drivers/net/wireless/ath/ath9k/channel.c b/drivers/net/wireless/ath/ath9k/channel.c -index a03c7d4..2fd5309 100644 +index 1a926fc..a37f270 100644 --- a/drivers/net/wireless/ath/ath9k/channel.c +++ b/drivers/net/wireless/ath/ath9k/channel.c -@@ -15,6 +15,8 @@ +@@ -15,6 +15,7 @@ */ #include "ath9k.h" -+#include +#include "hsr.h" /* Set/change channels. If the channel is really being changed, it's done * by reseting the chip. To accomplish this we must first cleanup any pending -@@ -22,6 +24,7 @@ +@@ -22,6 +23,7 @@ */ static int ath_set_channel(struct ath_softc *sc) { -+ struct ath9k_platform_data *pdata = sc->dev->platform_data; ++ struct device_node *np = sc->dev->of_node; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_hw *hw = sc->hw; -@@ -42,6 +45,11 @@ static int ath_set_channel(struct ath_softc *sc) +@@ -42,6 +44,11 @@ static int ath_set_channel(struct ath_softc *sc) ath_dbg(common, CONFIG, "Set channel: %d MHz width: %d\n", chan->center_freq, chandef->width); -+ if (pdata && pdata->ubnt_hsr) { ++ if (of_property_read_bool(np, "ubnt,hsr")) { + ath9k_hsr_enable(ah, chandef->width, chan->center_freq); + ath9k_hsr_status(ah); + } @@ -3116,7 +2975,7 @@ index 174d716..605abe1 100644 static inline void ath9k_hw_set_bt_ant_diversity(struct ath_hw *ah, bool enable) diff --git a/drivers/net/wireless/ath/ath9k/hw.c b/drivers/net/wireless/ath/ath9k/hw.c -index 9c1018a..85f65e0 100644 +index 7caa55e..eb57558 100644 --- a/drivers/net/wireless/ath/ath9k/hw.c +++ b/drivers/net/wireless/ath/ath9k/hw.c @@ -248,6 +248,19 @@ void ath9k_hw_get_channel_centers(struct ath_hw *ah, @@ -3389,7 +3248,7 @@ index 9c1018a..85f65e0 100644 void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test) diff --git a/drivers/net/wireless/ath/ath9k/hw.h b/drivers/net/wireless/ath/ath9k/hw.h -index 6566400..015fe02 100644 +index d65c4c4..559609d 100644 --- a/drivers/net/wireless/ath/ath9k/hw.h +++ b/drivers/net/wireless/ath/ath9k/hw.h @@ -36,6 +36,7 @@ @@ -3400,7 +3259,7 @@ index 6566400..015fe02 100644 #define AR5416_DEVID_PCI 0x0023 #define AR5416_DEVID_PCIE 0x0024 #define AR9160_DEVID_PCI 0x0027 -@@ -520,6 +521,12 @@ enum { +@@ -521,6 +522,12 @@ enum { ATH9K_RESET_COLD, }; @@ -3413,7 +3272,7 @@ index 6566400..015fe02 100644 struct ath9k_hw_version { u32 magic; u16 devid; -@@ -715,6 +722,7 @@ struct ath_spec_scan { +@@ -716,6 +723,7 @@ struct ath_spec_scan { * @config_pci_powersave: * @calibrate: periodic calibration for NF, ANI, IQ, ADC gain, ADC-DC * @@ -3421,7 +3280,7 @@ index 6566400..015fe02 100644 * @spectral_scan_config: set parameters for spectral scan and enable/disable it * @spectral_scan_trigger: trigger a spectral scan run * @spectral_scan_wait: wait for a spectral scan run to finish -@@ -737,6 +745,7 @@ struct ath_hw_ops { +@@ -738,6 +746,7 @@ struct ath_hw_ops { struct ath_hw_antcomb_conf *antconf); void (*antdiv_comb_conf_set)(struct ath_hw *ah, struct ath_hw_antcomb_conf *antconf); @@ -3429,7 +3288,7 @@ index 6566400..015fe02 100644 void (*spectral_scan_config)(struct ath_hw *ah, struct ath_spec_scan *param); void (*spectral_scan_trigger)(struct ath_hw *ah); -@@ -808,6 +817,8 @@ struct ath_hw { +@@ -809,6 +818,8 @@ struct ath_hw { u32 ah_flags; s16 nf_override; @@ -3438,7 +3297,7 @@ index 6566400..015fe02 100644 bool reset_power_on; bool htc_reset_init; -@@ -1073,6 +1084,7 @@ void ath9k_hw_check_nav(struct ath_hw *ah); +@@ -1075,6 +1086,7 @@ void ath9k_hw_check_nav(struct ath_hw *ah); bool ath9k_hw_check_alive(struct ath_hw *ah); bool ath9k_hw_setpower(struct ath_hw *ah, enum ath9k_power_mode mode); @@ -3447,7 +3306,7 @@ index 6566400..015fe02 100644 /* Generic hw timer primitives */ struct ath_gen_timer *ath_gen_timer_alloc(struct ath_hw *ah, diff --git a/drivers/net/wireless/ath/ath9k/init.c b/drivers/net/wireless/ath/ath9k/init.c -index e202d2f..0890e90 100644 +index f47c4ce..3162fc2 100644 --- a/drivers/net/wireless/ath/ath9k/init.c +++ b/drivers/net/wireless/ath/ath9k/init.c @@ -48,7 +48,7 @@ int ath9k_modparam_nohwcrypt; @@ -3485,7 +3344,7 @@ index e202d2f..0890e90 100644 static int ath9k_init_softc(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { -@@ -752,6 +764,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, +@@ -751,6 +763,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, if (ret) goto err_hw; @@ -3495,7 +3354,7 @@ index e202d2f..0890e90 100644 ret = ath9k_init_queues(sc); if (ret) goto err_queues; -@@ -819,7 +834,8 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) +@@ -818,7 +833,8 @@ static void ath9k_init_txpower_limits(struct ath_softc *sc) if (ah->caps.hw_caps & ATH9K_HW_CAP_5GHZ) ath9k_init_band_txpower(sc, NL80211_BAND_5GHZ); @@ -3505,7 +3364,7 @@ index e202d2f..0890e90 100644 } static const struct ieee80211_iface_limit if_limits[] = { -@@ -831,6 +847,7 @@ static const struct ieee80211_iface_limit if_limits[] = { +@@ -830,6 +846,7 @@ static const struct ieee80211_iface_limit if_limits[] = { BIT(NL80211_IFTYPE_AP) }, { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_CLIENT) | BIT(NL80211_IFTYPE_P2P_GO) }, @@ -3513,8 +3372,26 @@ index e202d2f..0890e90 100644 }; #ifdef CPTCFG_WIRELESS_WDS -@@ -1014,6 +1031,18 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) - wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_AIRTIME_FAIRNESS); +@@ -926,6 +943,7 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) + ieee80211_hw_set(hw, HOST_BROADCAST_PS_BUFFERING); + ieee80211_hw_set(hw, SUPPORT_FAST_XMIT); + ieee80211_hw_set(hw, SUPPORTS_CLONED_SKBS); ++ ieee80211_hw_set(hw, MFP_CAPABLE); + + if (ath9k_ps_enable) + ieee80211_hw_set(hw, SUPPORTS_PS); +@@ -938,9 +956,6 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) + IEEE80211_RADIOTAP_MCS_HAVE_STBC; + } + +- if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || ath9k_modparam_nohwcrypt) +- ieee80211_hw_set(hw, MFP_CAPABLE); +- + hw->wiphy->features |= NL80211_FEATURE_ACTIVE_MONITOR | + NL80211_FEATURE_AP_MODE_CHAN_WIDTH_CHANGE | + NL80211_FEATURE_P2P_GO_CTWIN; +@@ -1016,6 +1031,18 @@ static void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw) + wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CAN_REPLACE_PTK0); } +static void ath_get_initial_entropy(struct ath_softc *sc) @@ -3532,7 +3409,7 @@ index e202d2f..0890e90 100644 int ath9k_init_device(u16 devid, struct ath_softc *sc, const struct ath_bus_ops *bus_ops) { -@@ -1054,11 +1083,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, +@@ -1056,11 +1083,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, #ifdef CPTCFG_MAC80211_LEDS /* must be initialized before ieee80211_register_hw */ @@ -3547,7 +3424,7 @@ index e202d2f..0890e90 100644 /* Register with mac80211 */ error = ieee80211_register_hw(hw); if (error) -@@ -1142,25 +1173,25 @@ static int __init ath9k_init(void) +@@ -1144,25 +1173,25 @@ static int __init ath9k_init(void) { int error; @@ -3605,21 +3482,18 @@ index 58d02c1..c9d2bf3 100644 ath9k_hw_disable_mib_counters(ah); } diff --git a/drivers/net/wireless/ath/ath9k/main.c b/drivers/net/wireless/ath/ath9k/main.c -index 1c81611..17418f9 100644 +index 7f2a633..093eafd 100644 --- a/drivers/net/wireless/ath/ath9k/main.c +++ b/drivers/net/wireless/ath/ath9k/main.c -@@ -16,8 +16,10 @@ - - #include +@@ -18,6 +18,7 @@ #include -+#include #include "ath9k.h" #include "btcoex.h" +#include "hsr.h" - u8 ath9k_parse_mpdudensity(u8 mpdudensity) - { -@@ -528,6 +530,11 @@ irqreturn_t ath_isr(int irq, void *dev) + static void ath9k_flush(struct ieee80211_hw *hw, struct ieee80211_vif *vif, + u32 queues, bool drop); +@@ -531,6 +532,11 @@ irqreturn_t ath_isr(int irq, void *dev) if (test_bit(ATH_OP_HW_RESET, &common->op_flags)) return IRQ_HANDLED; @@ -3631,19 +3505,19 @@ index 1c81611..17418f9 100644 /* * If there are no status bits set, then this interrupt was not * for me (should have been caught above). -@@ -644,6 +651,7 @@ void ath_reset_work(struct work_struct *work) +@@ -647,6 +653,7 @@ void ath_reset_work(struct work_struct *work) static int ath9k_start(struct ieee80211_hw *hw) { struct ath_softc *sc = hw->priv; -+ struct ath9k_platform_data *pdata = sc->dev->platform_data; ++ struct device_node *np = sc->dev->of_node; struct ath_hw *ah = sc->sc_ah; struct ath_common *common = ath9k_hw_common(ah); struct ieee80211_channel *curchan = sc->cur_chan->chandef.chan; -@@ -722,6 +730,11 @@ static int ath9k_start(struct ieee80211_hw *hw) +@@ -725,6 +732,11 @@ static int ath9k_start(struct ieee80211_hw *hw) AR_GPIO_OUTPUT_MUX_AS_OUTPUT); } -+ if (pdata && pdata->ubnt_hsr) { ++ if (of_property_read_bool(np, "ubnt,hsr")) { + ath9k_hsr_init(ah); + ath9k_hsr_disable(ah); + } @@ -3652,7 +3526,7 @@ index 1c81611..17418f9 100644 * Reset key cache to sane defaults (all entries cleared) instead of * semi-random values after suspend/resume. diff --git a/drivers/net/wireless/ath/ath9k/pci.c b/drivers/net/wireless/ath/ath9k/pci.c -index caca0ac..119f1ab 100644 +index c7826aa..23c06bf 100644 --- a/drivers/net/wireless/ath/ath9k/pci.c +++ b/drivers/net/wireless/ath/ath9k/pci.c @@ -774,6 +774,7 @@ static const struct pci_device_id ath_pci_id_table[] = { @@ -3677,8 +3551,32 @@ index 4a1b992..af667a3 100644 enum ath9k_ant_div_comb_lna_conf { ATH_ANT_DIV_COMB_LNA1_MINUS_LNA2, ATH_ANT_DIV_COMB_LNA2, +diff --git a/drivers/net/wireless/ath/ath9k/xmit.c b/drivers/net/wireless/ath/ath9k/xmit.c +index 2c97786..6776da5 100644 +--- a/drivers/net/wireless/ath/ath9k/xmit.c ++++ b/drivers/net/wireless/ath/ath9k/xmit.c +@@ -1271,6 +1271,11 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, + is_40, is_sgi, is_sp); + if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC)) + info->rates[i].RateFlags |= ATH9K_RATESERIES_STBC; ++ if (rix >= 8 && fi->dyn_smps) { ++ info->rates[i].RateFlags |= ++ ATH9K_RATESERIES_RTS_CTS; ++ info->flags |= ATH9K_TXDESC_CTSENA; ++ } + + info->txpower[i] = ath_get_rate_txpower(sc, bf, rix, + is_40, false); +@@ -2114,6 +2119,7 @@ static void setup_frame_info(struct ieee80211_hw *hw, + fi->keyix = an->ps_key; + else + fi->keyix = ATH9K_TXKEYIX_INVALID; ++ fi->dyn_smps = sta && sta->smps_mode == IEEE80211_SMPS_DYNAMIC; + fi->keytype = keytype; + fi->framelen = framelen; + fi->tx_power = txpower; diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c -index ca2392c..e263400 100644 +index f263349..0042ea9 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -24,6 +24,7 @@ @@ -3693,15 +3591,15 @@ index ca2392c..e263400 100644 NL80211_RRF_NO_OFDM) /* We allow IBSS on these on a case by case basis by regulatory domain */ --#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ -+#define ATH9K_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ +-#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5350+10, 80, 0, 30,\ ++#define ATH_5GHZ_5150_5350 REG_RULE(5150-10, 5240+10, 80, 0, 30, 0),\ + REG_RULE(5260-10, 5350+10, 80, 0, 30,\ NL80211_RRF_NO_IR) - #define ATH9K_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ + #define ATH_5GHZ_5470_5850 REG_RULE(5470-10, 5850+10, 80, 0, 30,\ NL80211_RRF_NO_IR) @@ -61,64 +63,79 @@ static int __ath_regd_init(struct ath_regulatory *reg); - #define ATH9K_5GHZ_NO_MIDBAND ATH9K_5GHZ_5150_5350, \ - ATH9K_5GHZ_5725_5850 + #define ATH_5GHZ_NO_MIDBAND ATH_5GHZ_5150_5350, \ + ATH_5GHZ_5725_5850 +#define REGD_RULES(...) \ + .reg_rules = { __VA_ARGS__ }, \ @@ -3714,8 +3612,8 @@ index ca2392c..e263400 100644 .alpha2 = "99", - .reg_rules = { + REGD_RULES( - ATH9K_2GHZ_ALL, - ATH9K_5GHZ_ALL, + ATH_2GHZ_ALL, + ATH_5GHZ_ALL, - } + ) }; @@ -3726,9 +3624,9 @@ index ca2392c..e263400 100644 .alpha2 = "99", - .reg_rules = { + REGD_RULES( - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_NO_MIDBAND, + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_NO_MIDBAND, - } + ) }; @@ -3739,8 +3637,8 @@ index ca2392c..e263400 100644 .alpha2 = "99", - .reg_rules = { + REGD_RULES( - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_NO_MIDBAND, + ATH_2GHZ_CH01_11, + ATH_5GHZ_NO_MIDBAND, - } + ) }; @@ -3751,8 +3649,8 @@ index ca2392c..e263400 100644 .alpha2 = "99", - .reg_rules = { + REGD_RULES( - ATH9K_2GHZ_CH01_11, - ATH9K_5GHZ_ALL, + ATH_2GHZ_CH01_11, + ATH_5GHZ_ALL, - } + ) }; @@ -3763,9 +3661,9 @@ index ca2392c..e263400 100644 .alpha2 = "99", - .reg_rules = { + REGD_RULES( - ATH9K_2GHZ_CH01_11, - ATH9K_2GHZ_CH12_13, - ATH9K_5GHZ_ALL, + ATH_2GHZ_CH01_11, + ATH_2GHZ_CH12_13, + ATH_5GHZ_ALL, - } + ) }; @@ -3924,10 +3822,10 @@ index 0000000..ec85224 + +#endif /* _LINUX_ATH5K_PLATFORM_H */ diff --git a/include/linux/ath9k_platform.h b/include/linux/ath9k_platform.h -index 76860a4..f1f2ad4 100644 +index 76860a4..e210108 100644 --- a/include/linux/ath9k_platform.h +++ b/include/linux/ath9k_platform.h -@@ -46,6 +46,15 @@ struct ath9k_platform_data { +@@ -46,6 +46,13 @@ struct ath9k_platform_data { int (*external_reset)(void); bool use_eeprom; @@ -3938,13 +3836,11 @@ index 76860a4..f1f2ad4 100644 + unsigned num_btns; + const struct gpio_keys_button *btns; + unsigned btn_poll_interval; -+ -+ bool ubnt_hsr; }; #endif /* _LINUX_ATH9K_PLATFORM_H */ diff --git a/local-symbols b/local-symbols -index e7064fd..24b8388 100644 +index d5a2bfd..7565b2b 100644 --- a/local-symbols +++ b/local-symbols @@ -85,6 +85,7 @@ ADM8211= @@ -3973,10 +3869,10 @@ index e7064fd..24b8388 100644 ATH10K_DFS_CERTIFIED= WCN36XX= diff --git a/net/wireless/reg.c b/net/wireless/reg.c -index b001608..a2908b8 100644 +index 0e28e68..b6caa2b 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c -@@ -3039,6 +3039,8 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum nl80211_band band, +@@ -3252,6 +3252,8 @@ void regulatory_hint_country_ie(struct wiphy *wiphy, enum nl80211_band band, enum environment_cap env = ENVIRON_ANY; struct regulatory_request *request = NULL, *lr; @@ -3985,7 +3881,7 @@ index b001608..a2908b8 100644 /* IE len must be evenly divisible by 2 */ if (country_ie_len & 0x01) return; -@@ -3290,6 +3292,7 @@ static bool is_wiphy_all_set_reg_flag(enum ieee80211_regulatory_flags flag) +@@ -3503,6 +3505,7 @@ static bool is_wiphy_all_set_reg_flag(enum ieee80211_regulatory_flags flag) void regulatory_hint_disconnect(void) { diff --git a/recipes-kernel/mac80211/mac80211/0004-backport-of-rt2x00-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0004-backport-of-rt2x00-patches-from-openwrt.patch index bcb8c3a..1a8658a 100644 --- a/recipes-kernel/mac80211/mac80211/0004-backport-of-rt2x00-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0004-backport-of-rt2x00-patches-from-openwrt.patch @@ -1,29 +1,32 @@ -From 6811ae0fbf7e5bba287284b9d1f7e0ed9edc49e6 Mon Sep 17 00:00:00 2001 +From 5c357cfd354584cd728d5fc7b09c1fd5a9adaba8 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:20:33 +0200 -Subject: [PATCH] FIX: [mac80211] backport of rt2x00 patches from openwrt +Date: Mon, 22 Mar 2021 16:38:14 +0100 +Subject: [PATCH] 0004 backport of rt2x00 patches from openwrt --- drivers/net/wireless/ralink/rt2x00/Kconfig | 23 +- drivers/net/wireless/ralink/rt2x00/Makefile | 1 + - drivers/net/wireless/ralink/rt2x00/rt2800.h | 1 + - drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 1649 ++++++++++++++++++++- - drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 21 + - drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 21 +- - drivers/net/wireless/ralink/rt2x00/rt2x00.h | 8 + - drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 59 +- - drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c | 187 +++ + drivers/net/wireless/ralink/rt2x00/rt2800.h | 6 + + drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2025 +++++++++++++++++++-- + drivers/net/wireless/ralink/rt2x00/rt2800lib.h | 46 + + drivers/net/wireless/ralink/rt2x00/rt2800pci.c | 8 + + drivers/net/wireless/ralink/rt2x00/rt2800soc.c | 52 +- + drivers/net/wireless/ralink/rt2x00/rt2800usb.c | 7 + + drivers/net/wireless/ralink/rt2x00/rt2x00.h | 19 + + drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 67 +- + drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c | 187 ++ drivers/net/wireless/ralink/rt2x00/rt2x00leds.c | 3 + drivers/net/wireless/ralink/rt2x00/rt2x00lib.h | 16 + + drivers/net/wireless/ralink/rt2x00/rt2x00mac.c | 9 + drivers/net/wireless/ralink/rt2x00/rt2x00soc.c | 1 + include/linux/rt2x00_platform.h | 23 + local-symbols | 1 + - 14 files changed, 1990 insertions(+), 24 deletions(-) + 17 files changed, 2315 insertions(+), 179 deletions(-) create mode 100644 drivers/net/wireless/ralink/rt2x00/rt2x00eeprom.c create mode 100644 include/linux/rt2x00_platform.h diff --git a/drivers/net/wireless/ralink/rt2x00/Kconfig b/drivers/net/wireless/ralink/rt2x00/Kconfig -index 0bf5243..c6a7701 100644 +index c94a53b..58abe9a 100644 --- a/drivers/net/wireless/ralink/rt2x00/Kconfig +++ b/drivers/net/wireless/ralink/rt2x00/Kconfig @@ -70,6 +70,7 @@ config RT2800PCI @@ -48,7 +51,7 @@ index 0bf5243..c6a7701 100644 select RT2800_LIB select RT2800_LIB_MMIO + select MTD if SOC_RT288X || SOC_RT305X - ---help--- + help This adds support for Ralink WiSoC devices. Supported chips: RT2880, RT3050, RT3052, RT3350, RT3352. @@ -226,36 +229,37 @@ config RT2800SOC @@ -119,10 +122,22 @@ index 4a2156b..94335ec 100644 obj-$(CPTCFG_RT2X00_LIB) += rt2x00lib.o obj-$(CPTCFG_RT2X00_LIB_MMIO) += rt2x00mmio.o diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800.h b/drivers/net/wireless/ralink/rt2x00/rt2800.h -index d758e88..dfe2542 100644 +index d758e88..cdc69c4 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h -@@ -2739,6 +2739,7 @@ enum rt2800_eeprom_word { +@@ -1042,6 +1042,11 @@ + #define MIMO_PS_CFG_RX_STBY_POL FIELD32(0x00000010) + #define MIMO_PS_CFG_RX_RX_STBY0 FIELD32(0x00000020) + ++#define BB_PA_MODE_CFG0 0x1214 ++#define BB_PA_MODE_CFG1 0x1218 ++#define RF_PA_MODE_CFG0 0x121C ++#define RF_PA_MODE_CFG1 0x1220 ++ + /* + * EDCA_AC0_CFG: + */ +@@ -2739,6 +2744,7 @@ enum rt2800_eeprom_word { #define EEPROM_NIC_CONF2_RX_STREAM FIELD16(0x000f) #define EEPROM_NIC_CONF2_TX_STREAM FIELD16(0x00f0) #define EEPROM_NIC_CONF2_CRYSTAL FIELD16(0x0600) @@ -131,7 +146,7 @@ index d758e88..dfe2542 100644 /* * EEPROM LNA diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c -index dd7de57..3600b9e 100644 +index 024e2b3..5cd16ce 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c @@ -25,6 +25,7 @@ @@ -142,7 +157,141 @@ index dd7de57..3600b9e 100644 #include "rt2x00.h" #include "rt2800lib.h" -@@ -4358,6 +4359,45 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, +@@ -1237,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) + if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) + return; + ++ rt2800_update_survey(rt2x00dev); ++ + queue_for_each(rt2x00dev, queue) { + switch (queue->qid) { + case QID_AC_VO: +@@ -1273,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *rt2x00dev) + } + EXPORT_SYMBOL_GPL(rt2800_watchdog); + ++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev) ++{ ++ struct ieee80211_channel *chan = rt2x00dev->hw->conf.chandef.chan; ++ struct rt2x00_chan_survey *chan_survey = ++ &rt2x00dev->chan_survey[chan->hw_value]; ++ ++ chan_survey->time_idle += rt2800_register_read(rt2x00dev, CH_IDLE_STA); ++ chan_survey->time_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA); ++ chan_survey->time_ext_busy += rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); ++} ++EXPORT_SYMBOL_GPL(rt2800_update_survey); ++ + static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev, + unsigned int index) + { +@@ -3684,14 +3699,16 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, + rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4); + rt2800_rfcsr_write(rt2x00dev, 19, rfcsr); + +- /* Default: XO=20MHz , SDM mode */ +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); +- rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80); +- rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ /* Default: XO=20MHz , SDM mode */ ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 16); ++ rt2x00_set_field8(&rfcsr, RFCSR16_SDM_MODE_MT7620, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 16, rfcsr); + +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); +- rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); +- rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 21); ++ rt2x00_set_field8(&rfcsr, RFCSR21_BIT8, 1); ++ rt2800_rfcsr_write(rt2x00dev, 21, rfcsr); ++ } + + rfcsr = rt2800_rfcsr_read(rt2x00dev, 1); + rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620, +@@ -3725,18 +3742,23 @@ static void rt2800_config_channel_rf7620(struct rt2x00_dev *rt2x00dev, + rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20); + } + +- if (conf_is_ht40(conf)) { +- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08); +- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08); +- } else { +- rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28); +- rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ if (conf_is_ht40(conf)) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x08); ++ } else { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 58, 0x28); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x28); ++ } + } + +- rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); +- rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, +- conf_is_ht40(conf) && (rf->channel == 11)); +- rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) == 2) { ++ rfcsr = rt2800_rfcsr_read(rt2x00dev, 28); ++ rt2x00_set_field8(&rfcsr, RFCSR28_CH11_HT40, ++ conf_is_ht40(conf) && (rf->channel == 11)); ++ rt2800_rfcsr_write(rt2x00dev, 28, rfcsr); ++ } + + if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) { + if (conf_is_ht40(conf)) { +@@ -3836,25 +3858,29 @@ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev, + if (i == 10000) + rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n"); + +- if (chan->center_freq > 2457) { +- bbp = rt2800_bbp_read(rt2x00dev, 30); +- bbp = 0x40; +- rt2800_bbp_write(rt2x00dev, 30, bbp); +- rt2800_rfcsr_write(rt2x00dev, 39, 0); +- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 42, 0xfb); +- else +- rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); +- } else { +- bbp = rt2800_bbp_read(rt2x00dev, 30); +- bbp = 0x1f; +- rt2800_bbp_write(rt2x00dev, 30, bbp); +- rt2800_rfcsr_write(rt2x00dev, 39, 0x80); +- if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 42, 0xdb); +- else +- rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ if (chan->center_freq > 2457) { ++ bbp = rt2800_bbp_read(rt2x00dev, 30); ++ bbp = 0x40; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0); ++ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 42, 0xfb); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x7b); ++ } else { ++ bbp = rt2800_bbp_read(rt2x00dev, 30); ++ bbp = 0x1f; ++ rt2800_bbp_write(rt2x00dev, 30, bbp); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 42, 0xdb); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 42, 0x5b); ++ } + } ++ + rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl); + + rt2800_vco_calibration(rt2x00dev); +@@ -4355,6 +4381,45 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev, rt2800_iq_calibrate(rt2x00dev, rf->channel); } @@ -188,7 +337,78 @@ index dd7de57..3600b9e 100644 bbp = rt2800_bbp_read(rt2x00dev, 4); rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf)); rt2800_bbp_write(rt2x00dev, 4, bbp); -@@ -8382,6 +8422,1584 @@ static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev) +@@ -5847,18 +5912,33 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev) + } else if (rt2x00_rt(rt2x00dev, RT5350)) { + rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404); + } else if (rt2x00_rt(rt2x00dev, RT6352)) { +- rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); +- rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000); +- rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); +- rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); +- rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); +- rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0); +- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, 0x6C6C666C); +- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, 0x6C6C666C); +- rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, +- 0x3630363A); +- rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, +- 0x3630363A); ++ if (rt2800_hw_get_chipver(rt2x00dev) <= 1) { ++ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, ++ 0x00000000); ++ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG0, ++ 0x000055FF); ++ rt2800_register_write(rt2x00dev, BB_PA_MODE_CFG1, ++ 0x00550055); ++ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG0, ++ 0x000055FF); ++ rt2800_register_write(rt2x00dev, RF_PA_MODE_CFG1, ++ 0x00550055); ++ } else { ++ rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000); ++ rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000000); ++ rt2800_register_write(rt2x00dev, TX_ALC_VGA3, 0x00000000); ++ rt2800_register_write(rt2x00dev, TX0_BB_GAIN_ATTEN, 0x0); ++ rt2800_register_write(rt2x00dev, TX1_BB_GAIN_ATTEN, 0x0); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN, ++ 0x6C6C666C); ++ rt2800_register_write(rt2x00dev, TX0_RF_GAIN_CORRECT, ++ 0x3630363A); ++ rt2800_register_write(rt2x00dev, TX1_RF_GAIN_CORRECT, ++ 0x3630363A); ++ } + reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1); + rt2x00_set_field32(®, TX_ALC_CFG_1_ROS_BUSY_EN, 0); + rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg); +@@ -7002,14 +7082,16 @@ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev) + rt2800_bbp_write(rt2x00dev, 188, 0x00); + rt2800_bbp_write(rt2x00dev, 189, 0x00); + +- rt2800_bbp_write(rt2x00dev, 91, 0x06); +- rt2800_bbp_write(rt2x00dev, 92, 0x04); +- rt2800_bbp_write(rt2x00dev, 93, 0x54); +- rt2800_bbp_write(rt2x00dev, 99, 0x50); +- rt2800_bbp_write(rt2x00dev, 148, 0x84); +- rt2800_bbp_write(rt2x00dev, 167, 0x80); +- rt2800_bbp_write(rt2x00dev, 178, 0xFF); +- rt2800_bbp_write(rt2x00dev, 106, 0x13); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_bbp_write(rt2x00dev, 91, 0x06); ++ rt2800_bbp_write(rt2x00dev, 92, 0x04); ++ rt2800_bbp_write(rt2x00dev, 93, 0x54); ++ rt2800_bbp_write(rt2x00dev, 99, 0x50); ++ rt2800_bbp_write(rt2x00dev, 148, 0x84); ++ rt2800_bbp_write(rt2x00dev, 167, 0x80); ++ rt2800_bbp_write(rt2x00dev, 178, 0xFF); ++ rt2800_bbp_write(rt2x00dev, 106, 0x13); ++ } + + /* BBP for G band GLRT function (BBP_128 ~ BBP_221) */ + rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00); +@@ -8379,6 +8461,1584 @@ static void rt2800_init_rfcsr_5592(struct rt2x00_dev *rt2x00dev) rt2800_led_open_drain_enable(rt2x00dev); } @@ -1773,9 +1993,216 @@ index dd7de57..3600b9e 100644 static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev, bool set_bw, bool is_ht40) { -@@ -8989,8 +10607,13 @@ static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev) - rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); - rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); +@@ -8770,31 +10430,36 @@ static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev) + rt2800_rfcsr_write(rt2x00dev, 42, 0x5B); + rt2800_rfcsr_write(rt2x00dev, 43, 0x00); + +- rt2800_rfcsr_write(rt2x00dev, 11, 0x21); +- if (rt2800_clk_is_20mhz(rt2x00dev)) +- rt2800_rfcsr_write(rt2x00dev, 13, 0x03); +- else +- rt2800_rfcsr_write(rt2x00dev, 13, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 14, 0x7C); +- rt2800_rfcsr_write(rt2x00dev, 16, 0x80); +- rt2800_rfcsr_write(rt2x00dev, 17, 0x99); +- rt2800_rfcsr_write(rt2x00dev, 18, 0x99); +- rt2800_rfcsr_write(rt2x00dev, 19, 0x09); +- rt2800_rfcsr_write(rt2x00dev, 20, 0x50); +- rt2800_rfcsr_write(rt2x00dev, 21, 0xB0); +- rt2800_rfcsr_write(rt2x00dev, 22, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 23, 0x06); +- rt2800_rfcsr_write(rt2x00dev, 24, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 25, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 26, 0x5D); +- rt2800_rfcsr_write(rt2x00dev, 27, 0x00); +- rt2800_rfcsr_write(rt2x00dev, 28, 0x61); +- rt2800_rfcsr_write(rt2x00dev, 29, 0xB5); +- rt2800_rfcsr_write(rt2x00dev, 43, 0x02); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write(rt2x00dev, 11, 0x21); ++ if (rt2800_clk_is_20mhz(rt2x00dev)) ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x03); ++ else ++ rt2800_rfcsr_write(rt2x00dev, 13, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 14, 0x7C); ++ rt2800_rfcsr_write(rt2x00dev, 16, 0x80); ++ rt2800_rfcsr_write(rt2x00dev, 17, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 18, 0x99); ++ rt2800_rfcsr_write(rt2x00dev, 19, 0x09); ++ rt2800_rfcsr_write(rt2x00dev, 20, 0x50); ++ rt2800_rfcsr_write(rt2x00dev, 21, 0xB0); ++ rt2800_rfcsr_write(rt2x00dev, 22, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 23, 0x06); ++ rt2800_rfcsr_write(rt2x00dev, 24, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 25, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 26, 0x5D); ++ rt2800_rfcsr_write(rt2x00dev, 27, 0x00); ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x61); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xB5); ++ rt2800_rfcsr_write(rt2x00dev, 43, 0x02); ++ } + +- rt2800_rfcsr_write(rt2x00dev, 28, 0x62); +- rt2800_rfcsr_write(rt2x00dev, 29, 0xAD); +- rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write(rt2x00dev, 28, 0x62); ++ rt2800_rfcsr_write(rt2x00dev, 29, 0xAD); ++ rt2800_rfcsr_write(rt2x00dev, 39, 0x80); ++ } + + /* Initialize RF channel register to default value */ + rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03); +@@ -8860,63 +10525,71 @@ static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev) + + rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5); + +- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); +- rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67); +- rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); +- rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27); +- rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09); +- +- rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); +- +- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); +- +- /* Initialize RF channel register for DRQFN */ +- rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02); +- rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x47); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x71); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x33); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x0E); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x23); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 20, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 21, 0x12); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 29, 0xEB); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 32, 0x7D); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 34, 0xD6); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 36, 0x08); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 38, 0xB4); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xB3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xD5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 46, 0x27); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 47, 0x67); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 47, 0x69); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFF); ++ rt2800_rfcsr_write_bank(rt2x00dev, 4, 54, 0x27); ++ rt2800_rfcsr_write_bank(rt2x00dev, 6, 54, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xFF); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 57, 0x1C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x20); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 61, 0x09); ++ } ++ ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 10, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x06); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 19, 0xA7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 28, 0x2C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x64); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 8, 0x51); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 9, 0x36); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 11, 0x53); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x16); ++ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x6C); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 48, 0xFC); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 49, 0x1F); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 54, 0x27); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x66); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 59, 0x6B); ++ } ++ ++ if (rt2800_hw_get_chippkg(rt2x00dev) == 0 && ++ rt2800_hw_get_chipver(rt2x00dev) == 1) { ++ /* Initialize RF channel register for DRQFN */ ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 43, 0xD3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 44, 0xE3); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 45, 0xE5); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 47, 0x28); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 55, 0x68); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 56, 0xF7); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 58, 0x02); ++ rt2800_rfcsr_write_chanreg(rt2x00dev, 60, 0xC7); ++ } + + /* Initialize RF DC calibration register to default value */ + rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47); +@@ -8979,15 +10652,25 @@ static void rt2800_init_rfcsr_6352(struct rt2x00_dev *rt2x00dev) + rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00); + rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00); + +- rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08); +- rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04); +- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x08); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x04); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x20); ++ } + +- rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); +- rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); ++ if (rt2800_hw_get_chipver(rt2x00dev) > 1 && ++ rt2800_hw_get_chipeco(rt2x00dev) >= 2) { ++ rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00); ++ rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C); ++ } + rt2800_r_calibration(rt2x00dev); + rt2800_rf_self_txdc_cal(rt2x00dev); @@ -1787,7 +2214,16 @@ index dd7de57..3600b9e 100644 } static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev) -@@ -9531,6 +11154,17 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) +@@ -9416,6 +11099,8 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) + rf = RF3853; + else if (rt2x00_rt(rt2x00dev, RT5350)) + rf = RF5350; ++ else if (rt2x00_rt(rt2x00dev, RT5592)) ++ rf = RF5592; + else + rf = rt2x00_get_field16(eeprom, EEPROM_NIC_CONF0_RF_TYPE); + +@@ -9528,6 +11213,17 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC); rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY); @@ -1805,7 +2241,7 @@ index dd7de57..3600b9e 100644 rt2x00dev->led_mcu_reg = eeprom; #endif /* CPTCFG_RT2X00_LIB_LEDS */ -@@ -9548,7 +11182,8 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) +@@ -9545,7 +11241,8 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) */ eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1); @@ -1815,7 +2251,7 @@ index dd7de57..3600b9e 100644 if (rt2x00_get_field16(eeprom, EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352)) __set_bit(CAPABILITY_EXTERNAL_PA_TX0, -@@ -9559,6 +11194,18 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) +@@ -9556,6 +11253,18 @@ static int rt2800_init_eeprom(struct rt2x00_dev *rt2x00dev) &rt2x00dev->cap_flags); } @@ -1834,8 +2270,53 @@ index dd7de57..3600b9e 100644 return 0; } +@@ -10504,26 +12213,30 @@ int rt2800_get_survey(struct ieee80211_hw *hw, int idx, + { + struct rt2x00_dev *rt2x00dev = hw->priv; + struct ieee80211_conf *conf = &hw->conf; +- u32 idle, busy, busy_ext; ++ struct rt2x00_chan_survey *chan_survey = ++ &rt2x00dev->chan_survey[idx]; ++ enum nl80211_band band = NL80211_BAND_2GHZ; + +- if (idx != 0) ++ if (idx >= rt2x00dev->bands[band].n_channels) { ++ idx -= rt2x00dev->bands[band].n_channels; ++ band = NL80211_BAND_5GHZ; ++ } ++ ++ if (idx >= rt2x00dev->bands[band].n_channels) + return -ENOENT; + +- survey->channel = conf->chandef.chan; ++ if (idx == 0) ++ rt2800_update_survey(rt2x00dev); + +- idle = rt2800_register_read(rt2x00dev, CH_IDLE_STA); +- busy = rt2800_register_read(rt2x00dev, CH_BUSY_STA); +- busy_ext = rt2800_register_read(rt2x00dev, CH_BUSY_STA_SEC); ++ survey->channel = &rt2x00dev->bands[band].channels[idx]; + +- if (idle || busy) { +- survey->filled = SURVEY_INFO_TIME | +- SURVEY_INFO_TIME_BUSY | +- SURVEY_INFO_TIME_EXT_BUSY; ++ survey->filled = SURVEY_INFO_TIME | ++ SURVEY_INFO_TIME_BUSY | ++ SURVEY_INFO_TIME_EXT_BUSY; + +- survey->time = (idle + busy) / 1000; +- survey->time_busy = busy / 1000; +- survey->time_ext_busy = busy_ext / 1000; +- } ++ survey->time = div_u64(chan_survey->time_idle + chan_survey->time_busy, 1000); ++ survey->time_busy = div_u64(chan_survey->time_busy, 1000); ++ survey->time_ext_busy = div_u64(chan_survey->time_ext_busy, 1000); + + if (!(hw->conf.flags & IEEE80211_CONF_OFFCHANNEL)) + survey->filled |= SURVEY_INFO_IN_USE; diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h -index 1139405..5a5391c 100644 +index 1139405..bab82de 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h @@ -17,6 +17,16 @@ @@ -1864,7 +2345,17 @@ index 1139405..5a5391c 100644 struct rt2800_ops { u32 (*register_read)(struct rt2x00_dev *rt2x00dev, const unsigned int offset); -@@ -135,6 +147,15 @@ static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) +@@ -66,6 +78,9 @@ struct rt2800_ops { + int (*drv_init_registers)(struct rt2x00_dev *rt2x00dev); + __le32 *(*drv_get_txwi)(struct queue_entry *entry); + unsigned int (*drv_get_dma_done)(struct data_queue *queue); ++ int (*hw_get_chippkg)(void); ++ int (*hw_get_chipver)(void); ++ int (*hw_get_chipeco)(void); + }; + + static inline u32 rt2800_register_read(struct rt2x00_dev *rt2x00dev, +@@ -135,6 +150,15 @@ static inline int rt2800_read_eeprom(struct rt2x00_dev *rt2x00dev) { const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; @@ -1880,11 +2371,93 @@ index 1139405..5a5391c 100644 return rt2800ops->read_eeprom(rt2x00dev); } +@@ -174,6 +198,27 @@ static inline unsigned int rt2800_drv_get_dma_done(struct data_queue *queue) + return rt2800ops->drv_get_dma_done(queue); + } + ++static inline int rt2800_hw_get_chippkg(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chippkg(); ++} ++ ++static inline int rt2800_hw_get_chipver(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chipver(); ++} ++ ++static inline int rt2800_hw_get_chipeco(struct rt2x00_dev *rt2x00dev) ++{ ++ const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv; ++ ++ return rt2800ops->hw_get_chipeco(); ++} ++ + void rt2800_mcu_request(struct rt2x00_dev *rt2x00dev, + const u8 command, const u8 token, + const u8 arg0, const u8 arg1); +@@ -198,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x00_dev *rt2x00dev); + bool rt2800_txstatus_pending(struct rt2x00_dev *rt2x00dev); + + void rt2800_watchdog(struct rt2x00_dev *rt2x00dev); ++void rt2800_update_survey(struct rt2x00_dev *rt2x00dev); + + void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc); + void rt2800_clear_beacon(struct queue_entry *entry); +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +index dbce86b..7c41c49 100644 +--- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c +@@ -286,6 +286,10 @@ static int rt2800pci_read_eeprom(struct rt2x00_dev *rt2x00dev) + return retval; + } + ++static int rt2800pci_get_chippkg(void) { return 0; } ++static int rt2800pci_get_chipver(void) { return 0; } ++static int rt2800pci_get_chipeco(void) { return 0; } ++ + static const struct ieee80211_ops rt2800pci_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, +@@ -328,6 +332,9 @@ static const struct rt2800_ops rt2800pci_rt2800_ops = { + .drv_init_registers = rt2800mmio_init_registers, + .drv_get_txwi = rt2800mmio_get_txwi, + .drv_get_dma_done = rt2800mmio_get_dma_done, ++ .hw_get_chippkg = rt2800pci_get_chippkg, ++ .hw_get_chipver = rt2800pci_get_chipver, ++ .hw_get_chipeco = rt2800pci_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { +@@ -353,6 +360,7 @@ static const struct rt2x00lib_ops rt2800pci_rt2x00_ops = { + .gain_calibration = rt2800_gain_calibration, + .vco_calibration = rt2800_vco_calibration, + .watchdog = rt2800_watchdog, ++ .update_survey = rt2800_update_survey, + .start_queue = rt2800mmio_start_queue, + .kick_queue = rt2800mmio_kick_queue, + .stop_queue = rt2800mmio_stop_queue, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c -index e634621..5958a79 100644 +index 472a1fc..564c27d 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c -@@ -90,19 +90,6 @@ static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev, +@@ -27,6 +27,12 @@ + #include "rt2800lib.h" + #include "rt2800mmio.h" + ++/* Needed to probe CHIP_VER register on MT7620 */ ++#ifdef CONFIG_SOC_MT7620 ++#include ++#include ++#endif ++ + /* Allow hardware encryption to be disabled. */ + static bool modparam_nohwcrypt; + module_param_named(nohwcrypt, modparam_nohwcrypt, bool, 0444); +@@ -90,19 +96,6 @@ static int rt2800soc_set_device_state(struct rt2x00_dev *rt2x00dev, return retval; } @@ -1904,7 +2477,35 @@ index e634621..5958a79 100644 /* Firmware functions */ static char *rt2800soc_get_firmware_name(struct rt2x00_dev *rt2x00dev) { -@@ -166,7 +153,6 @@ static const struct rt2800_ops rt2800soc_rt2800_ops = { +@@ -131,6 +124,27 @@ static int rt2800soc_write_firmware(struct rt2x00_dev *rt2x00dev, + return 0; + } + ++#ifdef CONFIG_SOC_MT7620 ++static int rt2800soc_get_chippkg(void) ++{ ++ return mt7620_get_pkg(); ++} ++ ++static int rt2800soc_get_chipver(void) ++{ ++ return mt7620_get_chipver(); ++} ++ ++static int rt2800soc_get_chipeco(void) ++{ ++ return mt7620_get_eco(); ++} ++#else ++static int rt2800soc_get_chippkg(void) { return 0; } ++static int rt2800soc_get_chipver(void) { return 0; } ++static int rt2800soc_get_chipeco(void) { return 0; } ++#endif ++ + static const struct ieee80211_ops rt2800soc_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, +@@ -167,12 +181,14 @@ static const struct rt2800_ops rt2800soc_rt2800_ops = { .register_multiread = rt2x00mmio_register_multiread, .register_multiwrite = rt2x00mmio_register_multiwrite, .regbusy_read = rt2x00mmio_regbusy_read, @@ -1912,7 +2513,23 @@ index e634621..5958a79 100644 .hwcrypt_disabled = rt2800soc_hwcrypt_disabled, .drv_write_firmware = rt2800soc_write_firmware, .drv_init_registers = rt2800mmio_init_registers, -@@ -237,10 +223,17 @@ static int rt2800soc_probe(struct platform_device *pdev) + .drv_get_txwi = rt2800mmio_get_txwi, + .drv_get_dma_done = rt2800mmio_get_dma_done, ++ .hw_get_chippkg = rt2800soc_get_chippkg, ++ .hw_get_chipver = rt2800soc_get_chipver, ++ .hw_get_chipeco = rt2800soc_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = { +@@ -198,6 +214,7 @@ static const struct rt2x00lib_ops rt2800soc_rt2x00_ops = { + .gain_calibration = rt2800_gain_calibration, + .vco_calibration = rt2800_vco_calibration, + .watchdog = rt2800_watchdog, ++ .update_survey = rt2800_update_survey, + .start_queue = rt2800mmio_start_queue, + .kick_queue = rt2800mmio_kick_queue, + .stop_queue = rt2800mmio_stop_queue, +@@ -238,10 +255,17 @@ static int rt2800soc_probe(struct platform_device *pdev) return rt2x00soc_probe(pdev, &rt2800soc_ops); } @@ -1930,8 +2547,33 @@ index e634621..5958a79 100644 }, .probe = rt2800soc_probe, .remove = rt2x00soc_remove, +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +index 3f7df30..0183890 100644 +--- a/drivers/net/wireless/ralink/rt2x00/rt2800usb.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2800usb.c +@@ -628,6 +628,10 @@ static int rt2800usb_probe_hw(struct rt2x00_dev *rt2x00dev) + return 0; + } + ++static int rt2800usb_get_chippkg(void) { return 0; } ++static int rt2800usb_get_chipver(void) { return 0; } ++static int rt2800usb_get_chipeco(void) { return 0; } ++ + static const struct ieee80211_ops rt2800usb_mac80211_ops = { + .tx = rt2x00mac_tx, + .start = rt2x00mac_start, +@@ -671,6 +675,9 @@ static const struct rt2800_ops rt2800usb_rt2800_ops = { + .drv_init_registers = rt2800usb_init_registers, + .drv_get_txwi = rt2800usb_get_txwi, + .drv_get_dma_done = rt2800usb_get_dma_done, ++ .hw_get_chippkg = rt2800usb_get_chippkg, ++ .hw_get_chipver = rt2800usb_get_chipver, ++ .hw_get_chipeco = rt2800usb_get_chipeco, + }; + + static const struct rt2x00lib_ops rt2800usb_rt2x00_ops = { diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00.h b/drivers/net/wireless/ralink/rt2x00/rt2x00.h -index b8cf099..87c431d 100644 +index ef5b0ae..58be7b3 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h @@ -28,6 +28,7 @@ @@ -1942,7 +2584,23 @@ index b8cf099..87c431d 100644 #include -@@ -398,6 +399,7 @@ struct hw_mode_spec { +@@ -182,6 +183,15 @@ struct rf_channel { + }; + + /* ++ * Information structure for channel survey. ++ */ ++struct rt2x00_chan_survey { ++ u64 time_idle; ++ u64 time_busy; ++ u64 time_ext_busy; ++}; ++ ++/* + * Channel information structure + */ + struct channel_info { +@@ -398,6 +408,7 @@ struct hw_mode_spec { unsigned int supported_bands; #define SUPPORT_BAND_2GHZ 0x00000001 #define SUPPORT_BAND_5GHZ 0x00000002 @@ -1950,7 +2608,15 @@ index b8cf099..87c431d 100644 unsigned int supported_rates; #define SUPPORT_RATE_CCK 0x00000001 -@@ -693,6 +695,7 @@ enum rt2x00_capability_flags { +@@ -565,6 +576,7 @@ struct rt2x00lib_ops { + * Data queue handlers. + */ + void (*watchdog) (struct rt2x00_dev *rt2x00dev); ++ void (*update_survey) (struct rt2x00_dev *rt2x00dev); + void (*start_queue) (struct data_queue *queue); + void (*kick_queue) (struct data_queue *queue); + void (*stop_queue) (struct data_queue *queue); +@@ -693,6 +705,7 @@ enum rt2x00_capability_flags { REQUIRE_HT_TX_DESC, REQUIRE_PS_AUTOWAKE, REQUIRE_DELAYED_RFKILL, @@ -1958,7 +2624,15 @@ index b8cf099..87c431d 100644 /* * Capabilities -@@ -969,6 +972,11 @@ struct rt2x00_dev { +@@ -752,6 +765,7 @@ struct rt2x00_dev { + */ + struct ieee80211_hw *hw; + struct ieee80211_supported_band bands[NUM_NL80211_BANDS]; ++ struct rt2x00_chan_survey *chan_survey; + enum nl80211_band curr_band; + int curr_freq; + +@@ -969,6 +983,11 @@ struct rt2x00_dev { const struct firmware *fw; /* @@ -1971,7 +2645,7 @@ index b8cf099..87c431d 100644 */ DECLARE_KFIFO_PTR(txstatus_fifo, u32); diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c -index 77eb630..c477030 100644 +index f0f9d2e..5148f8a 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c @@ -990,8 +990,13 @@ static void rt2x00lib_rate(struct ieee80211_rate *entry, @@ -2021,7 +2695,29 @@ index 77eb630..c477030 100644 num_rates = 0; if (spec->supported_rates & SUPPORT_RATE_CCK) -@@ -1098,6 +1129,19 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) +@@ -1026,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, + if (!rates) + goto exit_free_channels; + ++ rt2x00dev->chan_survey = ++ kcalloc(spec->num_channels, sizeof(struct rt2x00_chan_survey), ++ GFP_KERNEL); ++ if (!rt2x00dev->chan_survey) ++ goto exit_free_rates; ++ + /* + * Initialize Rate list. + */ +@@ -1077,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(struct rt2x00_dev *rt2x00dev, + + return 0; + ++ exit_free_rates: ++ kfree(rates); + exit_free_channels: + kfree(channels); + rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n"); +@@ -1098,6 +1137,19 @@ static void rt2x00lib_remove_hw(struct rt2x00_dev *rt2x00dev) kfree(rt2x00dev->spec.channels_info); } @@ -2041,7 +2737,7 @@ index 77eb630..c477030 100644 static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) { struct hw_mode_spec *spec = &rt2x00dev->spec; -@@ -1180,6 +1224,10 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) +@@ -1179,6 +1231,10 @@ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev) #undef RT2X00_TASKLET_INIT @@ -2052,7 +2748,7 @@ index 77eb630..c477030 100644 /* * Register HW. */ -@@ -1325,7 +1373,7 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) +@@ -1313,7 +1369,7 @@ static inline void rt2x00lib_set_if_combinations(struct rt2x00_dev *rt2x00dev) */ if_limit = &rt2x00dev->if_limits_ap; if_limit->max = rt2x00dev->ops->max_ap_intf; @@ -2061,7 +2757,7 @@ index 77eb630..c477030 100644 #ifdef CPTCFG_MAC80211_MESH if_limit->types |= BIT(NL80211_IFTYPE_MESH_POINT); #endif -@@ -1418,6 +1466,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) +@@ -1406,6 +1462,10 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev) INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup); INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep); @@ -2072,7 +2768,7 @@ index 77eb630..c477030 100644 /* * Let the driver probe the device to detect the capabilities. */ -@@ -1561,6 +1613,11 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) +@@ -1549,6 +1609,11 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev) * Free the driver data. */ kfree(rt2x00dev->drv_data); @@ -2318,8 +3014,28 @@ index 776046c..b08ca7c 100644 * Debugfs handlers. */ #ifdef CPTCFG_RT2X00_LIB_DEBUGFS +diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +index 10c0548..6415b8c 100644 +--- a/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c ++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00mac.c +@@ -317,6 +317,15 @@ int rt2x00mac_config(struct ieee80211_hw *hw, u32 changed) + return 0; + + /* ++ * To provide correct survey data for survey-based ACS algorithm ++ * we have to save survey data for current channel before switching. ++ */ ++ if (rt2x00dev->ops->lib->update_survey && ++ (changed & IEEE80211_CONF_CHANGE_CHANNEL)) { ++ rt2x00dev->ops->lib->update_survey(rt2x00dev); ++ } ++ ++ /* + * Some configuration parameters (e.g. channel and antenna values) can + * only be set when the radio is enabled, but do require the RX to + * be off. During this period we should keep link tuning enabled, diff --git a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c -index 596b8a4..ec27a91 100644 +index eface61..eb9b514 100644 --- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c @@ -86,6 +86,7 @@ int rt2x00soc_probe(struct platform_device *pdev, const struct rt2x00_ops *ops) @@ -2360,10 +3076,10 @@ index 0000000..e10377e + +#endif /* _RT2X00_PLATFORM_H */ diff --git a/local-symbols b/local-symbols -index 24b8388..d6c55d2 100644 +index 7565b2b..2dd225b 100644 --- a/local-symbols +++ b/local-symbols -@@ -313,6 +313,7 @@ RT2X00_LIB_FIRMWARE= +@@ -332,6 +332,7 @@ RT2X00_LIB_FIRMWARE= RT2X00_LIB_CRYPTO= RT2X00_LIB_LEDS= RT2X00_LIB_DEBUGFS= diff --git a/recipes-kernel/mac80211/mac80211/0005-backport-of-mwl-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0005-backport-of-mwl-patches-from-openwrt.patch index 8bd3236..f13ccd6 100644 --- a/recipes-kernel/mac80211/mac80211/0005-backport-of-mwl-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0005-backport-of-mwl-patches-from-openwrt.patch @@ -1,7 +1,7 @@ -From a47e171c23025cb6b2f4afb6eccd59b3cb13c73c Mon Sep 17 00:00:00 2001 +From 03cb19a3d185defe5b22d5c83833de4847b15d29 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:45:07 +0200 -Subject: [PATCH] backport of mwl patches from openwrt +Date: Mon, 22 Mar 2021 16:39:42 +0100 +Subject: [PATCH] 0005 backport of mwl patches from openwrt --- drivers/net/wireless/marvell/libertas/cfg.c | 4 ++++ @@ -32,7 +32,7 @@ index 4e3de68..c861532 100644 if (ret < 0) pr_err("cannot register wiphy device\n"); diff --git a/drivers/net/wireless/marvell/libertas/main.c b/drivers/net/wireless/marvell/libertas/main.c -index 2233b59..e0b8e36 100644 +index ee4cf34..2ed6228 100644 --- a/drivers/net/wireless/marvell/libertas/main.c +++ b/drivers/net/wireless/marvell/libertas/main.c @@ -935,6 +935,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev) @@ -44,7 +44,7 @@ index 2233b59..e0b8e36 100644 dev->ml_priv = priv; SET_NETDEV_DEV(dev, dmdev); diff --git a/drivers/net/wireless/marvell/mwl8k.c b/drivers/net/wireless/marvell/mwl8k.c -index c4db641..4b7d2cb 100644 +index 23efd70..e8985c7 100644 --- a/drivers/net/wireless/marvell/mwl8k.c +++ b/drivers/net/wireless/marvell/mwl8k.c @@ -5694,6 +5694,7 @@ MODULE_FIRMWARE("mwl8k/fmimage_8366.fw"); diff --git a/recipes-kernel/mac80211/mac80211/0006-backport-of-brcm-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0006-backport-of-brcm-patches-from-openwrt.patch index abf7c18..7aeb06a 100644 --- a/recipes-kernel/mac80211/mac80211/0006-backport-of-brcm-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0006-backport-of-brcm-patches-from-openwrt.patch @@ -1,40 +1,27 @@ -From 17567e991d152bf7ff700c460aed7425918085d4 Mon Sep 17 00:00:00 2001 +From 103bfc86c246ba529893dfc54b7ceb19ec1a03c5 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Wed, 27 May 2020 19:45:36 +0200 -Subject: [PATCH] backport of brcm patches from openwrt +Date: Mon, 22 Mar 2021 16:40:53 +0100 +Subject: [PATCH] 0006 backport of brcm patches from openwrt --- drivers/net/wireless/broadcom/b43/Kconfig | 2 +- drivers/net/wireless/broadcom/b43/Makefile | 2 +- drivers/net/wireless/broadcom/b43/b43.h | 3 + drivers/net/wireless/broadcom/b43/dma.h | 2 +- - drivers/net/wireless/broadcom/b43/main.c | 82 ++++++- - drivers/net/wireless/broadcom/b43/pio.h | 34 ++- + drivers/net/wireless/broadcom/b43/main.c | 82 ++++++++++++++--- + drivers/net/wireless/broadcom/b43/pio.h | 34 ++++++- drivers/net/wireless/broadcom/brcm80211/Kconfig | 2 +- - .../wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c | 71 ++++-- - .../broadcom/brcm80211/brcmfmac/cfg80211.c | 267 ++++++++++++++++++--- - .../wireless/broadcom/brcm80211/brcmfmac/chip.c | 60 ++++- - .../wireless/broadcom/brcm80211/brcmfmac/chip.h | 1 + + .../broadcom/brcm80211/brcmfmac/cfg80211.c | 102 +++++++++++++++++++++ .../wireless/broadcom/brcm80211/brcmfmac/common.c | 4 + - .../wireless/broadcom/brcm80211/brcmfmac/core.c | 88 ++++++- - .../wireless/broadcom/brcm80211/brcmfmac/core.h | 10 + - .../wireless/broadcom/brcm80211/brcmfmac/feature.c | 1 + - .../wireless/broadcom/brcm80211/brcmfmac/feature.h | 2 + - .../broadcom/brcm80211/brcmfmac/firmware.c | 14 ++ - .../wireless/broadcom/brcm80211/brcmfmac/fwil.h | 2 + - .../broadcom/brcm80211/brcmfmac/fwsignal.c | 2 +- - .../wireless/broadcom/brcm80211/brcmfmac/msgbuf.c | 2 +- - .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 32 +++ - .../wireless/broadcom/brcm80211/brcmfmac/pcie.c | 2 +- - .../net/wireless/broadcom/brcm80211/brcmfmac/pno.c | 4 + - .../wireless/broadcom/brcm80211/brcmfmac/sdio.c | 17 ++ - .../wireless/broadcom/brcm80211/brcmfmac/sdio.h | 1 - - .../wireless/broadcom/brcm80211/brcmsmac/channel.c | 19 +- - include/linux/mmc/sdio_ids.h | 2 + - 27 files changed, 641 insertions(+), 87 deletions(-) + .../wireless/broadcom/brcm80211/brcmfmac/core.c | 9 ++ + .../wireless/broadcom/brcm80211/brcmfmac/core.h | 8 ++ + .../broadcom/brcm80211/brcmfmac/firmware.c | 14 +++ + .../net/wireless/broadcom/brcm80211/brcmfmac/of.c | 32 +++++++ + .../wireless/broadcom/brcm80211/brcmsmac/channel.c | 19 ++-- + 14 files changed, 286 insertions(+), 29 deletions(-) diff --git a/drivers/net/wireless/broadcom/b43/Kconfig b/drivers/net/wireless/broadcom/b43/Kconfig -index b8f1262..428f40e 100644 +index ffdf951..c43d931 100644 --- a/drivers/net/wireless/broadcom/b43/Kconfig +++ b/drivers/net/wireless/broadcom/b43/Kconfig @@ -100,7 +100,7 @@ config B43_BCMA_PIO @@ -87,7 +74,7 @@ index dfebc64..ec72414 100644 #define B43_DMA0_RX_FW351_BUFSIZE (B43_DMA0_RX_FW351_FO + IEEE80211_MAX_FRAME_LEN) diff --git a/drivers/net/wireless/broadcom/b43/main.c b/drivers/net/wireless/broadcom/b43/main.c -index 99d0b4a..df37945 100644 +index 2ef3263..8062ded 100644 --- a/drivers/net/wireless/broadcom/b43/main.c +++ b/drivers/net/wireless/broadcom/b43/main.c @@ -72,6 +72,11 @@ MODULE_FIRMWARE("b43/ucode40.fw"); @@ -111,7 +98,7 @@ index 99d0b4a..df37945 100644 module_param_named(allhwsupport, modparam_allhwsupport, int, 0444); MODULE_PARM_DESC(allhwsupport, "Enable support for all hardware (even it if overlaps with the brcmsmac driver)"); -@@ -1637,7 +1642,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, +@@ -1638,7 +1643,7 @@ static void b43_write_beacon_template(struct b43_wldev *dev, len, ram_offset, shm_size_offset, rate); /* Write the PHY TX control parameters. */ @@ -120,7 +107,7 @@ index 99d0b4a..df37945 100644 antenna = b43_antenna_to_phyctl(antenna); ctl = b43_shm_read16(dev, B43_SHM_SHARED, B43_SHM_SH_BEACPHYCTL); /* We can't send beacons with short preamble. Would get PHY errors. */ -@@ -1995,10 +2000,12 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) +@@ -1996,10 +2001,12 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev) dma_reason[0], dma_reason[1], dma_reason[2], dma_reason[3], dma_reason[4], dma_reason[5]); @@ -133,7 +120,7 @@ index 99d0b4a..df37945 100644 b43_controller_restart(dev, "DMA error"); return; } -@@ -2867,16 +2874,24 @@ static int b43_gpio_init(struct b43_wldev *dev) +@@ -2869,16 +2876,24 @@ static int b43_gpio_init(struct b43_wldev *dev) u32 mask, set; b43_maskset32(dev, B43_MMIO_MACCTL, ~B43_MACCTL_GPOUTSMSK, 0); @@ -160,7 +147,7 @@ index 99d0b4a..df37945 100644 } if (0 /* FIXME: conditional unknown */ ) { -@@ -3275,8 +3290,8 @@ static int b43_chip_init(struct b43_wldev *dev) +@@ -3277,8 +3292,8 @@ static int b43_chip_init(struct b43_wldev *dev) /* Select the antennae */ if (phy->ops->set_rx_antenna) @@ -171,7 +158,7 @@ index 99d0b4a..df37945 100644 if (phy->type == B43_PHYTYPE_B) { value16 = b43_read16(dev, 0x005E); -@@ -3976,7 +3991,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) +@@ -3978,7 +3993,6 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) struct b43_wldev *dev = wl->current_dev; struct b43_phy *phy = &dev->phy; struct ieee80211_conf *conf = &hw->conf; @@ -179,7 +166,7 @@ index 99d0b4a..df37945 100644 int err = 0; mutex_lock(&wl->mutex); -@@ -4019,11 +4033,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) +@@ -4021,11 +4035,9 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed) } /* Antennas for RX and management frame TX. */ @@ -193,7 +180,7 @@ index 99d0b4a..df37945 100644 if (wl->radio_enabled != phy->radio_on) { if (wl->radio_enabled) { -@@ -5167,6 +5179,47 @@ static int b43_op_get_survey(struct ieee80211_hw *hw, int idx, +@@ -5169,6 +5181,47 @@ static int b43_op_get_survey(struct ieee80211_hw *hw, int idx, return 0; } @@ -241,7 +228,7 @@ index 99d0b4a..df37945 100644 static const struct ieee80211_ops b43_hw_ops = { .tx = b43_op_tx, .conf_tx = b43_op_conf_tx, -@@ -5188,6 +5241,8 @@ static const struct ieee80211_ops b43_hw_ops = { +@@ -5190,6 +5243,8 @@ static const struct ieee80211_ops b43_hw_ops = { .sw_scan_complete = b43_op_sw_scan_complete_notifier, .get_survey = b43_op_get_survey, .rfkill_poll = b43_rfkill_poll, @@ -250,7 +237,7 @@ index 99d0b4a..df37945 100644 }; /* Hard-reset the chip. Do not call this directly. -@@ -5489,6 +5544,8 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) +@@ -5491,6 +5546,8 @@ static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl) if (!wldev) goto out; @@ -259,7 +246,7 @@ index 99d0b4a..df37945 100644 wldev->use_pio = b43_modparam_pio; wldev->dev = dev; wldev->wl = wl; -@@ -5583,6 +5640,9 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) +@@ -5585,6 +5642,9 @@ static struct b43_wl *b43_wireless_init(struct b43_bus_dev *dev) wiphy_ext_feature_set(hw->wiphy, NL80211_EXT_FEATURE_CQM_RSSI_LIST); @@ -321,7 +308,7 @@ index ffbfec6..a3742b7 100644 #endif /* B43_PIO_H_ */ diff --git a/drivers/net/wireless/broadcom/brcm80211/Kconfig b/drivers/net/wireless/broadcom/brcm80211/Kconfig -index 2c426b5..57e1ffc 100644 +index ae090a4..2dc7cab 100644 --- a/drivers/net/wireless/broadcom/brcm80211/Kconfig +++ b/drivers/net/wireless/broadcom/brcm80211/Kconfig @@ -1,6 +1,6 @@ @@ -332,249 +319,11 @@ index 2c426b5..57e1ffc 100644 depends on m config BRCMSMAC -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -index 58fffb9..2add956 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcmsdh.c -@@ -43,6 +43,7 @@ - - #define SDIO_FUNC1_BLOCKSIZE 64 - #define SDIO_FUNC2_BLOCKSIZE 512 -+#define SDIO_4359_FUNC2_BLOCKSIZE 256 - /* Maximum milliseconds to wait for F2 to come up */ - #define SDIO_WAIT_F2RDY 3000 - -@@ -119,7 +120,7 @@ int brcmf_sdiod_intr_register(struct brcmf_sdio_dev *sdiodev) - brcmf_err("enable_irq_wake failed %d\n", ret); - return ret; - } -- sdiodev->irq_wake = true; -+ disable_irq_wake(pdata->oob_irq_nr); - - sdio_claim_host(sdiodev->func1); - -@@ -178,10 +179,6 @@ void brcmf_sdiod_intr_unregister(struct brcmf_sdio_dev *sdiodev) - sdio_release_host(sdiodev->func1); - - sdiodev->oob_irq_requested = false; -- if (sdiodev->irq_wake) { -- disable_irq_wake(pdata->oob_irq_nr); -- sdiodev->irq_wake = false; -- } - free_irq(pdata->oob_irq_nr, &sdiodev->func1->dev); - sdiodev->irq_en = false; - sdiodev->oob_irq_requested = false; -@@ -903,6 +900,7 @@ static void brcmf_sdiod_host_fixup(struct mmc_host *host) - static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) - { - int ret = 0; -+ unsigned int f2_blksz = SDIO_FUNC2_BLOCKSIZE; - - sdio_claim_host(sdiodev->func1); - -@@ -912,7 +910,9 @@ static int brcmf_sdiod_probe(struct brcmf_sdio_dev *sdiodev) - sdio_release_host(sdiodev->func1); - goto out; - } -- ret = sdio_set_block_size(sdiodev->func2, SDIO_FUNC2_BLOCKSIZE); -+ if (sdiodev->func2->device == SDIO_DEVICE_ID_BROADCOM_4359) -+ f2_blksz = SDIO_4359_FUNC2_BLOCKSIZE; -+ ret = sdio_set_block_size(sdiodev->func2, f2_blksz); - if (ret) { - brcmf_err("Failed to set F2 blocksize\n"); - sdio_release_host(sdiodev->func1); -@@ -969,8 +969,10 @@ static const struct sdio_device_id brcmf_sdmmc_ids[] = { - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_43455), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4354), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4356), -+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_BROADCOM_4359), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_4373), - BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_43012), -+ BRCMF_SDIO_DEVICE(SDIO_DEVICE_ID_CYPRESS_89359), - { /* end: all zeroes */ } - }; - MODULE_DEVICE_TABLE(sdio, brcmf_sdmmc_ids); -@@ -1108,7 +1110,8 @@ static int brcmf_ops_sdio_suspend(struct device *dev) - struct sdio_func *func; - struct brcmf_bus *bus_if; - struct brcmf_sdio_dev *sdiodev; -- mmc_pm_flag_t sdio_flags; -+ mmc_pm_flag_t pm_caps, sdio_flags; -+ int ret = 0; - - func = container_of(dev, struct sdio_func, dev); - brcmf_dbg(SDIO, "Enter: F%d\n", func->num); -@@ -1119,19 +1122,33 @@ static int brcmf_ops_sdio_suspend(struct device *dev) - bus_if = dev_get_drvdata(dev); - sdiodev = bus_if->bus_priv.sdio; - -- brcmf_sdiod_freezer_on(sdiodev); -- brcmf_sdio_wd_timer(sdiodev->bus, 0); -+ pm_caps = sdio_get_host_pm_caps(func); -+ -+ if (pm_caps & MMC_PM_KEEP_POWER) { -+ /* preserve card power during suspend */ -+ brcmf_sdiod_freezer_on(sdiodev); -+ brcmf_sdio_wd_timer(sdiodev->bus, 0); -+ -+ sdio_flags = MMC_PM_KEEP_POWER; -+ if (sdiodev->wowl_enabled) { -+ if (sdiodev->settings->bus.sdio.oob_irq_supported) -+ enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); -+ else -+ sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; -+ } - -- sdio_flags = MMC_PM_KEEP_POWER; -- if (sdiodev->wowl_enabled) { -- if (sdiodev->settings->bus.sdio.oob_irq_supported) -- enable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); -- else -- sdio_flags |= MMC_PM_WAKE_SDIO_IRQ; -+ if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) -+ brcmf_err("Failed to set pm_flags %x\n", sdio_flags); -+ -+ } else { -+ /* power will be cut so remove device, probe again in resume */ -+ brcmf_sdiod_intr_unregister(sdiodev); -+ ret = brcmf_sdiod_remove(sdiodev); -+ if (ret) -+ brcmf_err("Failed to remove device on suspend\n"); - } -- if (sdio_set_host_pm_flags(sdiodev->func1, sdio_flags)) -- brcmf_err("Failed to set pm_flags %x\n", sdio_flags); -- return 0; -+ -+ return ret; - } - - static int brcmf_ops_sdio_resume(struct device *dev) -@@ -1139,13 +1156,27 @@ static int brcmf_ops_sdio_resume(struct device *dev) - struct brcmf_bus *bus_if = dev_get_drvdata(dev); - struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio; - struct sdio_func *func = container_of(dev, struct sdio_func, dev); -+ mmc_pm_flag_t pm_caps = sdio_get_host_pm_caps(func); -+ int ret = 0; - - brcmf_dbg(SDIO, "Enter: F%d\n", func->num); - if (func->num != 2) - return 0; - -- brcmf_sdiod_freezer_off(sdiodev); -- return 0; -+ if (!(pm_caps & MMC_PM_KEEP_POWER)) { -+ /* bus was powered off and device removed, probe again */ -+ ret = brcmf_sdiod_probe(sdiodev); -+ if (ret) -+ brcmf_err("Failed to probe device on resume\n"); -+ } else { -+ if (sdiodev->wowl_enabled && -+ sdiodev->settings->bus.sdio.oob_irq_supported) -+ disable_irq_wake(sdiodev->settings->bus.sdio.oob_irq_nr); -+ -+ brcmf_sdiod_freezer_off(sdiodev); -+ } -+ -+ return ret; - } - - static const struct dev_pm_ops brcmf_sdio_pm_ops = { diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -index e3ebb7a..4412a63 100644 +index 7e1d6f9..0373fac 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c -@@ -11,6 +11,7 @@ - #include - #include - #include -+#include - - #include - #include -@@ -619,6 +620,82 @@ static bool brcmf_is_ibssmode(struct brcmf_cfg80211_vif *vif) - return vif->wdev.iftype == NL80211_IFTYPE_ADHOC; - } - -+/** -+ * brcmf_mon_add_vif() - create monitor mode virtual interface -+ * -+ * @wiphy: wiphy device of new interface. -+ * @name: name of the new interface. -+ */ -+static struct wireless_dev *brcmf_mon_add_vif(struct wiphy *wiphy, -+ const char *name) -+{ -+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -+ struct brcmf_cfg80211_vif *vif; -+ struct net_device *ndev; -+ struct brcmf_if *ifp; -+ int err; -+ -+ if (cfg->pub->mon_if) { -+ err = -EEXIST; -+ goto err_out; -+ } -+ -+ vif = brcmf_alloc_vif(cfg, NL80211_IFTYPE_MONITOR); -+ if (IS_ERR(vif)) { -+ err = PTR_ERR(vif); -+ goto err_out; -+ } -+ -+ ndev = alloc_netdev(sizeof(*ifp), name, NET_NAME_UNKNOWN, ether_setup); -+ if (!ndev) { -+ err = -ENOMEM; -+ goto err_free_vif; -+ } -+ ndev->type = ARPHRD_IEEE80211_RADIOTAP; -+ ndev->ieee80211_ptr = &vif->wdev; -+ ndev->needs_free_netdev = true; -+ ndev->priv_destructor = brcmf_cfg80211_free_netdev; -+ SET_NETDEV_DEV(ndev, wiphy_dev(cfg->wiphy)); -+ -+ ifp = netdev_priv(ndev); -+ ifp->vif = vif; -+ ifp->ndev = ndev; -+ ifp->drvr = cfg->pub; -+ -+ vif->ifp = ifp; -+ vif->wdev.netdev = ndev; -+ -+ err = brcmf_net_mon_attach(ifp); -+ if (err) { -+ brcmf_err("Failed to attach %s device\n", ndev->name); -+ free_netdev(ndev); -+ goto err_free_vif; -+ } -+ -+ cfg->pub->mon_if = ifp; -+ -+ return &vif->wdev; -+ -+err_free_vif: -+ brcmf_free_vif(vif); -+err_out: -+ return ERR_PTR(err); -+} -+ -+static int brcmf_mon_del_vif(struct wiphy *wiphy, struct wireless_dev *wdev) -+{ -+ struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); -+ struct net_device *ndev = wdev->netdev; -+ -+ ndev->netdev_ops->ndo_stop(ndev); -+ -+ brcmf_net_detach(ndev, true); -+ -+ cfg->pub->mon_if = NULL; -+ -+ return 0; -+} -+ - static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, - const char *name, - unsigned char name_assign_type, -@@ -628,8 +705,36 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, +@@ -715,8 +715,36 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy); struct brcmf_pub *drvr = cfg->pub; struct wireless_dev *wdev; @@ -611,31 +360,7 @@ index e3ebb7a..4412a63 100644 brcmf_dbg(TRACE, "enter: %s type %d\n", name, type); err = brcmf_vif_add_validate(wiphy_to_cfg(wiphy), type); if (err) { -@@ -641,9 +746,10 @@ static struct wireless_dev *brcmf_cfg80211_add_iface(struct wiphy *wiphy, - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: -- case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return ERR_PTR(-EOPNOTSUPP); -+ case NL80211_IFTYPE_MONITOR: -+ return brcmf_mon_add_vif(wiphy, name); - case NL80211_IFTYPE_AP: - wdev = brcmf_ap_add_vif(wiphy, name, params); - break; -@@ -826,9 +932,10 @@ int brcmf_cfg80211_del_iface(struct wiphy *wiphy, struct wireless_dev *wdev) - case NL80211_IFTYPE_STATION: - case NL80211_IFTYPE_AP_VLAN: - case NL80211_IFTYPE_WDS: -- case NL80211_IFTYPE_MONITOR: - case NL80211_IFTYPE_MESH_POINT: - return -EOPNOTSUPP; -+ case NL80211_IFTYPE_MONITOR: -+ return brcmf_mon_del_vif(wiphy, wdev); - case NL80211_IFTYPE_AP: - return brcmf_cfg80211_del_ap_iface(wiphy, wdev); - case NL80211_IFTYPE_P2P_CLIENT: -@@ -2719,6 +2826,63 @@ done: +@@ -2882,6 +2910,63 @@ done: } static int @@ -699,7 +424,7 @@ index e3ebb7a..4412a63 100644 brcmf_cfg80211_dump_station(struct wiphy *wiphy, struct net_device *ndev, int idx, u8 *mac, struct station_info *sinfo) { -@@ -2767,6 +2931,10 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, +@@ -2930,6 +3015,10 @@ brcmf_cfg80211_set_power_mgmt(struct wiphy *wiphy, struct net_device *ndev, * preference in cfg struct to apply this to * FW later while initializing the dongle */ @@ -710,7 +435,7 @@ index e3ebb7a..4412a63 100644 cfg->pwr_save = enabled; if (!check_vif_up(ifp->vif)) { -@@ -2804,6 +2972,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, +@@ -2973,6 +3062,7 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, struct brcmu_chan ch; u16 channel; u32 freq; @@ -718,7 +443,7 @@ index e3ebb7a..4412a63 100644 u16 notify_capability; u16 notify_interval; u8 *notify_ie; -@@ -2828,6 +2997,17 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, +@@ -2997,6 +3087,17 @@ static s32 brcmf_inform_single_bss(struct brcmf_cfg80211_info *cfg, band = NL80211_BAND_5GHZ; freq = ieee80211_channel_to_frequency(channel, band); @@ -736,7 +461,7 @@ index e3ebb7a..4412a63 100644 bss_data.chan = ieee80211_get_channel(wiphy, freq); bss_data.scan_width = NL80211_BSS_CHAN_WIDTH_20; bss_data.boottime_ns = ktime_to_ns(ktime_get_boottime()); -@@ -5245,6 +5425,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { +@@ -5483,6 +5584,7 @@ static struct cfg80211_ops brcmf_cfg80211_ops = { .leave_ibss = brcmf_cfg80211_leave_ibss, .get_station = brcmf_cfg80211_get_station, .dump_station = brcmf_cfg80211_dump_station, @@ -744,335 +469,8 @@ index e3ebb7a..4412a63 100644 .set_tx_power = brcmf_cfg80211_set_tx_power, .get_tx_power = brcmf_cfg80211_get_tx_power, .add_key = brcmf_cfg80211_add_key, -@@ -5301,6 +5482,7 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - struct brcmf_cfg80211_vif *vif_walk; - struct brcmf_cfg80211_vif *vif; - bool mbss; -+ struct brcmf_if *ifp = brcmf_get_ifp(cfg->pub, 0); - - brcmf_dbg(TRACE, "allocating virtual interface (size=%zu)\n", - sizeof(*vif)); -@@ -5313,7 +5495,8 @@ struct brcmf_cfg80211_vif *brcmf_alloc_vif(struct brcmf_cfg80211_info *cfg, - - brcmf_init_prof(&vif->profile); - -- if (type == NL80211_IFTYPE_AP) { -+ if (type == NL80211_IFTYPE_AP && -+ brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS)) { - mbss = false; - list_for_each_entry(vif_walk, &cfg->vif_list, list) { - if (vif_walk->wdev.iftype == NL80211_IFTYPE_AP) { -@@ -5944,19 +6127,17 @@ static s32 brcmf_dongle_roam(struct brcmf_if *ifp) - roamtrigger[1] = cpu_to_le32(BRCM_BAND_ALL); - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_TRIGGER, - (void *)roamtrigger, sizeof(roamtrigger)); -- if (err) { -+ if (err) - bphy_err(drvr, "WLC_SET_ROAM_TRIGGER error (%d)\n", err); -- goto roam_setup_done; -- } - - roam_delta[0] = cpu_to_le32(WL_ROAM_DELTA); - roam_delta[1] = cpu_to_le32(BRCM_BAND_ALL); - err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SET_ROAM_DELTA, - (void *)roam_delta, sizeof(roam_delta)); -- if (err) { -+ if (err) - bphy_err(drvr, "WLC_SET_ROAM_DELTA error (%d)\n", err); -- goto roam_setup_done; -- } -+ -+ return 0; - - roam_setup_done: - return err; -@@ -6454,6 +6635,9 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { - * #STA <= 1, #AP <= 1, channels = 1, 2 total - * #AP <= 4, matching BI, channels = 1, 4 total - * -+ * no p2p and rsdb: -+ * #STA <= 2, #AP <= 2, channels = 2, 4 total -+ * - * p2p, no mchan, and mbss: - * - * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 1, 3 total -@@ -6465,6 +6649,10 @@ brcmf_txrx_stypes[NUM_NL80211_IFTYPES] = { - * #STA <= 1, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 1, channels = 2, 3 total - * #STA <= 1, #P2P-DEV <= 1, #AP <= 1, #P2P-CL <= 1, channels = 1, 4 total - * #AP <= 4, matching BI, channels = 1, 4 total -+ * -+ * p2p, rsdb, and no mbss: -+ * #STA <= 2, #P2P-DEV <= 1, #{P2P-CL, P2P-GO} <= 2, AP <= 2, -+ * channels = 2, 4 total - */ - static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) - { -@@ -6472,13 +6660,16 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) - struct ieee80211_iface_limit *c0_limits = NULL; - struct ieee80211_iface_limit *p2p_limits = NULL; - struct ieee80211_iface_limit *mbss_limits = NULL; -- bool mbss, p2p; -- int i, c, n_combos; -+ bool mon_flag, mbss, p2p, rsdb, mchan; -+ int i, c, n_combos, n_limits; - -+ mon_flag = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MONITOR_FLAG); - mbss = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MBSS); - p2p = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_P2P); -+ rsdb = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_RSDB); -+ mchan = brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN); - -- n_combos = 1 + !!p2p + !!mbss; -+ n_combos = 1 + !!(p2p && !rsdb) + !!mbss; - combo = kcalloc(n_combos, sizeof(*combo), GFP_KERNEL); - if (!combo) - goto err; -@@ -6486,37 +6677,53 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) - wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) | - BIT(NL80211_IFTYPE_ADHOC) | - BIT(NL80211_IFTYPE_AP); -+ if (mon_flag) -+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR); -+ if (p2p) -+ wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | -+ BIT(NL80211_IFTYPE_P2P_GO) | -+ BIT(NL80211_IFTYPE_P2P_DEVICE); - - c = 0; - i = 0; -- c0_limits = kcalloc(p2p ? 3 : 2, sizeof(*c0_limits), GFP_KERNEL); -+ n_limits = 1 + mon_flag + (p2p ? 2 : 0) + (rsdb || !p2p); -+ c0_limits = kcalloc(n_limits, sizeof(*c0_limits), GFP_KERNEL); - if (!c0_limits) - goto err; -- c0_limits[i].max = 1; -+ -+ combo[c].num_different_channels = 1 + (rsdb || (p2p && mchan)); -+ c0_limits[i].max = 1 + rsdb; - c0_limits[i++].types = BIT(NL80211_IFTYPE_STATION); -+ if (mon_flag) { -+ c0_limits[i].max = 1; -+ c0_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR); -+ } - if (p2p) { -- if (brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MCHAN)) -- combo[c].num_different_channels = 2; -- else -- combo[c].num_different_channels = 1; -- wiphy->interface_modes |= BIT(NL80211_IFTYPE_P2P_CLIENT) | -- BIT(NL80211_IFTYPE_P2P_GO) | -- BIT(NL80211_IFTYPE_P2P_DEVICE); - c0_limits[i].max = 1; - c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_DEVICE); -- c0_limits[i].max = 1; -+ c0_limits[i].max = 1 + rsdb; - c0_limits[i++].types = BIT(NL80211_IFTYPE_P2P_CLIENT) | - BIT(NL80211_IFTYPE_P2P_GO); -+ } -+ if (p2p && rsdb) { -+ c0_limits[i].max = 2; -+ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); -+ combo[c].max_interfaces = 5; -+ } else if (p2p) { -+ combo[c].max_interfaces = i; -+ } else if (rsdb) { -+ c0_limits[i].max = 2; -+ c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); -+ combo[c].max_interfaces = 3; - } else { -- combo[c].num_different_channels = 1; - c0_limits[i].max = 1; - c0_limits[i++].types = BIT(NL80211_IFTYPE_AP); -+ combo[c].max_interfaces = i; - } -- combo[c].max_interfaces = i; - combo[c].n_limits = i; - combo[c].limits = c0_limits; - -- if (p2p) { -+ if (p2p && !rsdb) { - c++; - i = 0; - p2p_limits = kcalloc(4, sizeof(*p2p_limits), GFP_KERNEL); -@@ -6539,14 +6746,20 @@ static int brcmf_setup_ifmodes(struct wiphy *wiphy, struct brcmf_if *ifp) - if (mbss) { - c++; - i = 0; -- mbss_limits = kcalloc(1, sizeof(*mbss_limits), GFP_KERNEL); -+ n_limits = 1 + mon_flag; -+ mbss_limits = kcalloc(n_limits, sizeof(*mbss_limits), -+ GFP_KERNEL); - if (!mbss_limits) - goto err; - mbss_limits[i].max = 4; - mbss_limits[i++].types = BIT(NL80211_IFTYPE_AP); -+ if (mon_flag) { -+ mbss_limits[i].max = 1; -+ mbss_limits[i++].types = BIT(NL80211_IFTYPE_MONITOR); -+ } - combo[c].beacon_int_infra_match = true; - combo[c].num_different_channels = 1; -- combo[c].max_interfaces = 4; -+ combo[c].max_interfaces = 4 + mon_flag; - combo[c].n_limits = i; - combo[c].limits = mbss_limits; - } -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c -index dd586a9..282d0bc 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.c -@@ -433,11 +433,25 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, - { - struct brcmf_chip_priv *ci; - int count; -+ struct brcmf_core *d11core2 = NULL; -+ struct brcmf_core_priv *d11priv2 = NULL; - - ci = core->chip; - -+ /* special handle two D11 cores reset */ -+ if (core->pub.id == BCMA_CORE_80211) { -+ d11core2 = brcmf_chip_get_d11core(&ci->pub, 1); -+ if (d11core2) { -+ brcmf_dbg(INFO, "found two d11 cores, reset both\n"); -+ d11priv2 = container_of(d11core2, -+ struct brcmf_core_priv, pub); -+ } -+ } -+ - /* must disable first to work for arbitrary current core state */ - brcmf_chip_ai_coredisable(core, prereset, reset); -+ if (d11priv2) -+ brcmf_chip_ai_coredisable(d11priv2, prereset, reset); - - count = 0; - while (ci->ops->read32(ci->ctx, core->wrapbase + BCMA_RESET_CTL) & -@@ -449,9 +463,30 @@ static void brcmf_chip_ai_resetcore(struct brcmf_core_priv *core, u32 prereset, - usleep_range(40, 60); - } - -+ if (d11priv2) { -+ count = 0; -+ while (ci->ops->read32(ci->ctx, -+ d11priv2->wrapbase + BCMA_RESET_CTL) & -+ BCMA_RESET_CTL_RESET) { -+ ci->ops->write32(ci->ctx, -+ d11priv2->wrapbase + BCMA_RESET_CTL, -+ 0); -+ count++; -+ if (count > 50) -+ break; -+ usleep_range(40, 60); -+ } -+ } -+ - ci->ops->write32(ci->ctx, core->wrapbase + BCMA_IOCTL, - postreset | BCMA_IOCTL_CLK); - ci->ops->read32(ci->ctx, core->wrapbase + BCMA_IOCTL); -+ -+ if (d11priv2) { -+ ci->ops->write32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL, -+ postreset | BCMA_IOCTL_CLK); -+ ci->ops->read32(ci->ctx, d11priv2->wrapbase + BCMA_IOCTL); -+ } - } - - char *brcmf_chip_name(u32 id, u32 rev, char *buf, uint len) -@@ -677,7 +712,6 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) - case BRCM_CC_43569_CHIP_ID: - case BRCM_CC_43570_CHIP_ID: - case BRCM_CC_4358_CHIP_ID: -- case BRCM_CC_4359_CHIP_ID: - case BRCM_CC_43602_CHIP_ID: - case BRCM_CC_4371_CHIP_ID: - return 0x180000; -@@ -687,6 +721,8 @@ static u32 brcmf_chip_tcm_rambase(struct brcmf_chip_priv *ci) - case BRCM_CC_4366_CHIP_ID: - case BRCM_CC_43664_CHIP_ID: - return 0x200000; -+ case BRCM_CC_4359_CHIP_ID: -+ return (ci->pub.chiprev < 9) ? 0x180000 : 0x160000; - case CY_CC_4373_CHIP_ID: - return 0x160000; - default: -@@ -778,7 +814,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, - { - u8 desc; - u32 val, szdesc; -- u8 mpnum = 0; - u8 stype, sztype, wraptype; - - *regbase = 0; -@@ -786,7 +821,6 @@ static int brcmf_chip_dmp_get_regaddr(struct brcmf_chip_priv *ci, u32 *eromaddr, - - val = brcmf_chip_dmp_get_desc(ci, eromaddr, &desc); - if (desc == DMP_DESC_MASTER_PORT) { -- mpnum = (val & DMP_MASTER_PORT_NUM) >> DMP_MASTER_PORT_NUM_S; - wraptype = DMP_SLAVE_TYPE_MWRAP; - } else if (desc == DMP_DESC_ADDRESS) { - /* revert erom address */ -@@ -854,7 +888,7 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) - u8 desc_type = 0; - u32 val; - u16 id; -- u8 nmp, nsp, nmw, nsw, rev; -+ u8 nmw, nsw, rev; - u32 base, wrap; - int err; - -@@ -880,8 +914,6 @@ int brcmf_chip_dmp_erom_scan(struct brcmf_chip_priv *ci) - return -EFAULT; - - /* only look at cores with master port(s) */ -- nmp = (val & DMP_COMP_NUM_MPORT) >> DMP_COMP_NUM_MPORT_S; -- nsp = (val & DMP_COMP_NUM_SPORT) >> DMP_COMP_NUM_SPORT_S; - nmw = (val & DMP_COMP_NUM_MWRAP) >> DMP_COMP_NUM_MWRAP_S; - nsw = (val & DMP_COMP_NUM_SWRAP) >> DMP_COMP_NUM_SWRAP_S; - rev = (val & DMP_COMP_REVISION) >> DMP_COMP_REVISION_S; -@@ -1113,6 +1145,21 @@ void brcmf_chip_detach(struct brcmf_chip *pub) - kfree(chip); - } - -+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit) -+{ -+ struct brcmf_chip_priv *chip; -+ struct brcmf_core_priv *core; -+ -+ chip = container_of(pub, struct brcmf_chip_priv, pub); -+ list_for_each_entry(core, &chip->cores, list) { -+ if (core->pub.id == BCMA_CORE_80211) { -+ if (unit-- == 0) -+ return &core->pub; -+ } -+ } -+ return NULL; -+} -+ - struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *pub, u16 coreid) - { - struct brcmf_chip_priv *chip; -@@ -1361,6 +1408,7 @@ bool brcmf_chip_sr_capable(struct brcmf_chip *pub) - addr = CORE_CC_REG(base, sr_control0); - reg = chip->ops->read32(chip->ctx, addr); - return (reg & CC_SR_CTL0_ENABLE_MASK) != 0; -+ case BRCM_CC_4359_CHIP_ID: - case CY_CC_43012_CHIP_ID: - addr = CORE_CC_REG(pmu->base, retention_ctl); - reg = chip->ops->read32(chip->ctx, addr); -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h -index 7b00f6a..8fa3865 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/chip.h -@@ -74,6 +74,7 @@ struct brcmf_chip *brcmf_chip_attach(void *ctx, - const struct brcmf_buscore_ops *ops); - void brcmf_chip_detach(struct brcmf_chip *chip); - struct brcmf_core *brcmf_chip_get_core(struct brcmf_chip *chip, u16 coreid); -+struct brcmf_core *brcmf_chip_get_d11core(struct brcmf_chip *pub, u8 unit); - struct brcmf_core *brcmf_chip_get_chipcommon(struct brcmf_chip *chip); - struct brcmf_core *brcmf_chip_get_pmu(struct brcmf_chip *pub); - bool brcmf_chip_iscoreup(struct brcmf_core *core); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c -index 6d3c9ad..1d9c6f1 100644 +index 3512a3f..41b1a8b 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c @@ -59,7 +59,11 @@ static int brcmf_fcmode; @@ -1088,110 +486,10 @@ index 6d3c9ad..1d9c6f1 100644 MODULE_PARM_DESC(roamoff, "Do not use internal roaming engine"); diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -index e688fd2..498f993 100644 +index 011f9fa..4309ad7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c -@@ -678,6 +678,8 @@ int brcmf_net_attach(struct brcmf_if *ifp, bool rtnl_locked) - goto fail; - } - -+ netif_carrier_off(ndev); -+ - netdev_set_priv_destructor(ndev, brcmf_cfg80211_free_netdev); - brcmf_dbg(INFO, "%s: Broadcom Dongle Host Driver\n", ndev->name); - return 0; -@@ -688,7 +690,7 @@ fail: - return -EBADE; - } - --static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) -+void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) - { - if (ndev->reg_state == NETREG_REGISTERED) { - if (rtnl_locked) -@@ -701,6 +703,81 @@ static void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked) - } - } - -+static int brcmf_net_mon_open(struct net_device *ndev) -+{ -+ struct brcmf_if *ifp = netdev_priv(ndev); -+ struct brcmf_pub *drvr = ifp->drvr; -+ u32 monitor; -+ int err; -+ -+ brcmf_dbg(TRACE, "Enter\n"); -+ -+ err = brcmf_fil_cmd_int_get(ifp, BRCMF_C_GET_MONITOR, &monitor); -+ if (err) { -+ bphy_err(drvr, "BRCMF_C_GET_MONITOR error (%d)\n", err); -+ return err; -+ } else if (monitor) { -+ bphy_err(drvr, "Monitor mode is already enabled\n"); -+ return -EEXIST; -+ } -+ -+ monitor = 3; -+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor); -+ if (err) -+ bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err); -+ -+ return err; -+} -+ -+static int brcmf_net_mon_stop(struct net_device *ndev) -+{ -+ struct brcmf_if *ifp = netdev_priv(ndev); -+ struct brcmf_pub *drvr = ifp->drvr; -+ u32 monitor; -+ int err; -+ -+ brcmf_dbg(TRACE, "Enter\n"); -+ -+ monitor = 0; -+ err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_MONITOR, monitor); -+ if (err) -+ bphy_err(drvr, "BRCMF_C_SET_MONITOR error (%d)\n", err); -+ -+ return err; -+} -+ -+static netdev_tx_t brcmf_net_mon_start_xmit(struct sk_buff *skb, -+ struct net_device *ndev) -+{ -+ dev_kfree_skb_any(skb); -+ -+ return NETDEV_TX_OK; -+} -+ -+static const struct net_device_ops brcmf_netdev_ops_mon = { -+ .ndo_open = brcmf_net_mon_open, -+ .ndo_stop = brcmf_net_mon_stop, -+ .ndo_start_xmit = brcmf_net_mon_start_xmit, -+}; -+ -+int brcmf_net_mon_attach(struct brcmf_if *ifp) -+{ -+ struct brcmf_pub *drvr = ifp->drvr; -+ struct net_device *ndev; -+ int err; -+ -+ brcmf_dbg(TRACE, "Enter\n"); -+ -+ ndev = ifp->ndev; -+ ndev->netdev_ops = &brcmf_netdev_ops_mon; -+ -+ err = register_netdevice(ndev); -+ if (err) -+ bphy_err(drvr, "Failed to register %s device\n", ndev->name); -+ -+ return err; -+} -+ - void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on) - { - struct net_device *ndev; -@@ -1275,6 +1352,8 @@ int brcmf_attach(struct device *dev) +@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev) /* Link to bus module */ drvr->hdrlen = 0; @@ -1200,7 +498,7 @@ index e688fd2..498f993 100644 /* Attach and link in the protocol */ ret = brcmf_proto_attach(drvr); -@@ -1357,6 +1436,12 @@ void brcmf_detach(struct device *dev) +@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev) if (drvr == NULL) return; @@ -1213,7 +511,7 @@ index e688fd2..498f993 100644 #ifdef CONFIG_INET unregister_inetaddr_notifier(&drvr->inetaddr_notifier); #endif -@@ -1477,6 +1562,7 @@ int __init brcmf_core_init(void) +@@ -1557,6 +1565,7 @@ int __init brcmf_core_init(void) { if (!schedule_work(&brcmf_driver_work)) return -EBUSY; @@ -1222,7 +520,7 @@ index e688fd2..498f993 100644 return 0; } diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h -index 6699637..0df727e 100644 +index 5767d66..0ae1cc2 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h @@ -91,6 +91,11 @@ struct brcmf_rev_info { @@ -1247,49 +545,8 @@ index 6699637..0df727e 100644 /* Internal brcmf items */ uint hdrlen; /* Total BRCMF header length (proto + bus) */ -@@ -210,6 +218,8 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp, - void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success); - void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb); - void brcmf_netif_mon_rx(struct brcmf_if *ifp, struct sk_buff *skb); -+void brcmf_net_detach(struct net_device *ndev, bool rtnl_locked); -+int brcmf_net_mon_attach(struct brcmf_if *ifp); - void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on); - int __init brcmf_core_init(void); - void __exit brcmf_core_exit(void); -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c -index 2c3526a..0901b4d 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.c -@@ -38,6 +38,7 @@ static const struct brcmf_feat_fwcap brcmf_fwcap_map[] = { - { BRCMF_FEAT_MCHAN, "mchan" }, - { BRCMF_FEAT_P2P, "p2p" }, - { BRCMF_FEAT_MONITOR, "monitor" }, -+ { BRCMF_FEAT_MONITOR_FLAG, "rtap" }, - { BRCMF_FEAT_MONITOR_FMT_RADIOTAP, "rtap" }, - { BRCMF_FEAT_DOT11H, "802.11h" } - }; -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h -index 736a817..7a9f92a 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/feature.h -@@ -23,6 +23,7 @@ - * GSCAN: enhanced scan offload feature. - * FWSUP: Firmware supplicant. - * MONITOR: firmware can pass monitor packets to host. -+ * MONITOR_FLAG: firmware flags monitor packets. - * MONITOR_FMT_RADIOTAP: firmware provides monitor packets with radiotap header - * MONITOR_FMT_HW_RX_HDR: firmware provides monitor packets with hw/ucode header - * DOT11H: firmware supports 802.11h -@@ -43,6 +44,7 @@ - BRCMF_FEAT_DEF(GSCAN) \ - BRCMF_FEAT_DEF(FWSUP) \ - BRCMF_FEAT_DEF(MONITOR) \ -+ BRCMF_FEAT_DEF(MONITOR_FLAG) \ - BRCMF_FEAT_DEF(MONITOR_FMT_RADIOTAP) \ - BRCMF_FEAT_DEF(MONITOR_FMT_HW_RX_HDR) \ - BRCMF_FEAT_DEF(DOT11H) diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c -index 3aed4c4..c33ddd2 100644 +index d821a47..47f72f7 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c @@ -431,6 +431,7 @@ struct brcmf_fw { @@ -1341,47 +598,8 @@ index 3aed4c4..c33ddd2 100644 return 0; } -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h -index 0ff6f52..ae4cf43 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h -@@ -49,6 +49,8 @@ - #define BRCMF_C_GET_PM 85 - #define BRCMF_C_SET_PM 86 - #define BRCMF_C_GET_REVINFO 98 -+#define BRCMF_C_GET_MONITOR 107 -+#define BRCMF_C_SET_MONITOR 108 - #define BRCMF_C_GET_CURR_RATESET 114 - #define BRCMF_C_GET_AP 117 - #define BRCMF_C_SET_AP 118 -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c -index 2bd892d..5e1a11c 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c -@@ -908,7 +908,7 @@ static u8 brcmf_fws_hdrpush(struct brcmf_fws_info *fws, struct sk_buff *skb) - wlh += wlh[1] + 2; - - if (entry->send_tim_signal) { -- entry->send_tim_signal = 0; -+ entry->send_tim_signal = false; - wlh[0] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP; - wlh[1] = BRCMF_FWS_TYPE_PENDING_TRAFFIC_BMP_LEN; - wlh[2] = entry->mac_handle; -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c -index e3dd862..8bb4f1f 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c -@@ -365,7 +365,7 @@ brcmf_msgbuf_get_pktid(struct device *dev, struct brcmf_msgbuf_pktids *pktids, - struct brcmf_msgbuf_pktid *pktid; - struct sk_buff *skb; - -- if (idx < 0 || idx >= pktids->array_size) { -+ if (idx >= pktids->array_size) { - brcmf_err("Invalid packet id %d (max %d)\n", idx, - pktids->array_size); - return NULL; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c -index b886b56..ae1f436 100644 +index a755426..e9c23c4 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c @@ -12,6 +12,36 @@ @@ -1421,7 +639,7 @@ index b886b56..ae1f436 100644 void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, struct brcmf_mp_device *settings) { -@@ -30,6 +60,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, +@@ -43,6 +73,8 @@ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type, of_node_put(root); } @@ -1430,97 +648,8 @@ index b886b56..ae1f436 100644 if (!np || bus_type != BRCMF_BUSTYPE_SDIO || !of_device_is_compatible(np, "brcm,bcm4329-fmac")) return; -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -index 759f27a..0da6845 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pcie.c -@@ -78,7 +78,7 @@ static const struct brcmf_firmware_mapping brcmf_pcie_fwnames[] = { - BRCMF_FW_ENTRY(BRCM_CC_4371_CHIP_ID, 0xFFFFFFFF, 4371), - }; - --#define BRCMF_PCIE_FW_UP_TIMEOUT 2000 /* msec */ -+#define BRCMF_PCIE_FW_UP_TIMEOUT 5000 /* msec */ - - #define BRCMF_PCIE_REG_MAP_SIZE (32 * 1024) - -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -index 14e5306..fabfbb0 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/pno.c -@@ -57,6 +57,10 @@ static int brcmf_pno_remove_request(struct brcmf_pno_info *pi, u64 reqid) - - mutex_lock(&pi->req_lock); - -+ /* Nothing to do if we have no requests */ -+ if (pi->n_reqs == 0) -+ goto done; -+ - /* find request */ - for (i = 0; i < pi->n_reqs; i++) { - if (pi->reqs[i]->reqid == reqid) -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -index a935993..f9047db 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c -@@ -42,6 +42,8 @@ - #define DEFAULT_F2_WATERMARK 0x8 - #define CY_4373_F2_WATERMARK 0x40 - #define CY_43012_F2_WATERMARK 0x60 -+#define CY_4359_F2_WATERMARK 0x40 -+#define CY_4359_F1_MESBUSYCTRL (CY_4359_F2_WATERMARK | SBSDIO_MESBUSYCTRL_ENAB) - - #ifdef DEBUG - -@@ -614,6 +616,7 @@ BRCMF_FW_DEF(43455, "brcmfmac43455-sdio"); - BRCMF_FW_DEF(43456, "brcmfmac43456-sdio"); - BRCMF_FW_DEF(4354, "brcmfmac4354-sdio"); - BRCMF_FW_DEF(4356, "brcmfmac4356-sdio"); -+BRCMF_FW_DEF(4359, "brcmfmac4359-sdio"); - BRCMF_FW_DEF(4373, "brcmfmac4373-sdio"); - BRCMF_FW_DEF(43012, "brcmfmac43012-sdio"); - -@@ -636,6 +639,7 @@ static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = { - BRCMF_FW_ENTRY(BRCM_CC_4345_CHIP_ID, 0xFFFFFDC0, 43455), - BRCMF_FW_ENTRY(BRCM_CC_4354_CHIP_ID, 0xFFFFFFFF, 4354), - BRCMF_FW_ENTRY(BRCM_CC_4356_CHIP_ID, 0xFFFFFFFF, 4356), -+ BRCMF_FW_ENTRY(BRCM_CC_4359_CHIP_ID, 0xFFFFFFFF, 4359), - BRCMF_FW_ENTRY(CY_CC_4373_CHIP_ID, 0xFFFFFFFF, 4373), - BRCMF_FW_ENTRY(CY_CC_43012_CHIP_ID, 0xFFFFFFFF, 43012) - }; -@@ -4206,6 +4210,19 @@ static void brcmf_sdio_firmware_callback(struct device *dev, int err, - brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, - &err); - break; -+ case SDIO_DEVICE_ID_BROADCOM_4359: -+ brcmf_dbg(INFO, "set F2 watermark to 0x%x*4 bytes\n", -+ CY_4359_F2_WATERMARK); -+ brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, -+ CY_4359_F2_WATERMARK, &err); -+ devctl = brcmf_sdiod_readb(sdiod, SBSDIO_DEVICE_CTL, -+ &err); -+ devctl |= SBSDIO_DEVCTL_F2WM_ENAB; -+ brcmf_sdiod_writeb(sdiod, SBSDIO_DEVICE_CTL, devctl, -+ &err); -+ brcmf_sdiod_writeb(sdiod, SBSDIO_FUNC1_MESBUSYCTRL, -+ CY_4359_F1_MESBUSYCTRL, &err); -+ break; - default: - brcmf_sdiod_writeb(sdiod, SBSDIO_WATERMARK, - DEFAULT_F2_WATERMARK, &err); -diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h -index 0bd47c1..163fd66 100644 ---- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h -+++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.h -@@ -178,7 +178,6 @@ struct brcmf_sdio_dev { - bool sd_irq_requested; - bool irq_en; /* irq enable flags */ - spinlock_t irq_en_lock; -- bool irq_wake; /* irq wake enable flags */ - bool sg_support; - uint max_request_size; - ushort max_segment_count; diff --git a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c -index db783e9..021383a 100644 +index 5a6d9c8..dbf197f 100644 --- a/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c +++ b/drivers/net/wireless/broadcom/brcm80211/brcmsmac/channel.c @@ -58,19 +58,12 @@ @@ -1549,18 +678,3 @@ index db783e9..021383a 100644 static const struct ieee80211_regdomain brcms_regdom_x2 = { .n_reg_rules = 6, -diff --git a/include/linux/mmc/sdio_ids.h b/include/linux/mmc/sdio_ids.h -index 08b25c0..2e9a6e4 100644 ---- a/include/linux/mmc/sdio_ids.h -+++ b/include/linux/mmc/sdio_ids.h -@@ -41,8 +41,10 @@ - #define SDIO_DEVICE_ID_BROADCOM_43455 0xa9bf - #define SDIO_DEVICE_ID_BROADCOM_4354 0x4354 - #define SDIO_DEVICE_ID_BROADCOM_4356 0x4356 -+#define SDIO_DEVICE_ID_BROADCOM_4359 0x4359 - #define SDIO_DEVICE_ID_CYPRESS_4373 0x4373 - #define SDIO_DEVICE_ID_CYPRESS_43012 43012 -+#define SDIO_DEVICE_ID_CYPRESS_89359 0x4355 - - #define SDIO_VENDOR_ID_INTEL 0x0089 - #define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402 diff --git a/recipes-kernel/mac80211/mac80211/0007-backport-of-rtl-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0007-backport-of-rtl-patches-from-openwrt.patch new file mode 100644 index 0000000..d7c9cd2 --- /dev/null +++ b/recipes-kernel/mac80211/mac80211/0007-backport-of-rtl-patches-from-openwrt.patch @@ -0,0 +1,811 @@ +From 5219cf1f08755b8d8ca8019a47ccc29cba9f69ef Mon Sep 17 00:00:00 2001 +From: Patrick Walther +Date: Mon, 22 Mar 2021 16:44:09 +0100 +Subject: [PATCH] 0007 backport of rtl patches from openwrt + +--- + .../net/wireless/realtek/rtlwifi/rtl8821ae/table.c | 500 +++++++++++++++------ + 1 file changed, 370 insertions(+), 130 deletions(-) + +diff --git a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.c b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.c +index 85093b3..ed72a2a 100644 +--- a/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.c ++++ b/drivers/net/wireless/realtek/rtlwifi/rtl8821ae/table.c +@@ -249,7 +249,7 @@ u32 RTL8821AE_PHY_REG_ARRAY[] = { + 0x824, 0x00030FE0, + 0x828, 0x00000000, + 0x82C, 0x002081DD, +- 0x830, 0x2AAA8E24, ++ 0x830, 0x2AAAEEC8, + 0x834, 0x0037A706, + 0x838, 0x06489B44, + 0x83C, 0x0000095B, +@@ -324,10 +324,10 @@ u32 RTL8821AE_PHY_REG_ARRAY[] = { + 0x9D8, 0x00000000, + 0x9DC, 0x00000000, + 0x9E0, 0x00005D00, +- 0x9E4, 0x00000002, ++ 0x9E4, 0x00000003, + 0x9E8, 0x00000001, + 0xA00, 0x00D047C8, +- 0xA04, 0x01FF000C, ++ 0xA04, 0x01FF800C, + 0xA08, 0x8C8A8300, + 0xA0C, 0x2E68000F, + 0xA10, 0x9500BB78, +@@ -1320,7 +1320,11 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x083, 0x00021800, + 0x084, 0x00028000, + 0x085, 0x00048000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, ++ 0x086, 0x0009483A, ++ 0xA0000000, 0x00000000, + 0x086, 0x00094838, ++ 0xB0000000, 0x00000000, + 0x087, 0x00044980, + 0x088, 0x00048000, + 0x089, 0x0000D480, +@@ -1409,36 +1413,32 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x03C, 0x000CA000, + 0x0EF, 0x00000000, + 0x0EF, 0x00001100, +- 0xFF0F0104, 0xABCD, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF3, + 0x034, 0x00049DF0, +- 0xFF0F0404, 0xCDEF, +- 0x034, 0x0004ADF3, +- 0x034, 0x00049DF0, +- 0xFF0F0200, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004ADF5, + 0x034, 0x00049DF2, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0004A0F3, ++ 0x034, 0x000490B1, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0004A0F3, + 0x034, 0x000490B1, +- 0xCDCDCDCD, 0xCDCD, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0004ADF5, ++ 0x034, 0x00049DF2, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0004ADF3, ++ 0x034, 0x00049DF0, ++ 0xA0000000, 0x00000000, + 0x034, 0x0004ADF7, + 0x034, 0x00049DF3, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, +- 0x034, 0x00048DED, +- 0x034, 0x00047DEA, +- 0x034, 0x00046DE7, +- 0x034, 0x00045CE9, +- 0x034, 0x00044CE6, +- 0x034, 0x000438C6, +- 0x034, 0x00042886, +- 0x034, 0x00041486, +- 0x034, 0x00040447, +- 0xFF0F0204, 0xCDEF, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, +@@ -1448,7 +1448,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, +- 0xFF0F0404, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00048DED, + 0x034, 0x00047DEA, + 0x034, 0x00046DE7, +@@ -1458,7 +1458,17 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00042886, + 0x034, 0x00041486, + 0x034, 0x00040447, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x000480AE, ++ 0x034, 0x000470AB, ++ 0x034, 0x0004608B, ++ 0x034, 0x00045069, ++ 0x034, 0x00044048, ++ 0x034, 0x00043045, ++ 0x034, 0x00042026, ++ 0x034, 0x00041023, ++ 0x034, 0x00040002, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000480AE, + 0x034, 0x000470AB, + 0x034, 0x0004608B, +@@ -1468,7 +1478,17 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00042026, + 0x034, 0x00041023, + 0x034, 0x00040002, +- 0xCDCDCDCD, 0xCDCD, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x00048DED, ++ 0x034, 0x00047DEA, ++ 0x034, 0x00046DE7, ++ 0x034, 0x00045CE9, ++ 0x034, 0x00044CE6, ++ 0x034, 0x000438C6, ++ 0x034, 0x00042886, ++ 0x034, 0x00041486, ++ 0x034, 0x00040447, ++ 0xA0000000, 0x00000000, + 0x034, 0x00048DEF, + 0x034, 0x00047DEC, + 0x034, 0x00046DE9, +@@ -1478,38 +1498,36 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x0004248A, + 0x034, 0x0004108D, + 0x034, 0x0004008A, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0200, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002ADF4, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0002A0F3, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0002A0F3, +- 0xCDCDCDCD, 0xCDCD, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0002ADF4, ++ 0xA0000000, 0x00000000, + 0x034, 0x0002ADF7, +- 0xFF0F0200, 0xDEAD, +- 0xFF0F0104, 0xABCD, +- 0x034, 0x00029DF4, +- 0xFF0F0204, 0xCDEF, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, +- 0xFF0F0404, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF4, +- 0xFF0F0200, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00029DF1, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x000290F0, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000290F0, +- 0xCDCDCDCD, 0xCDCD, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x00029DF1, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x00029DF4, ++ 0xA0000000, 0x00000000, + 0x034, 0x00029DF2, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, +- 0x034, 0x00028DF1, +- 0x034, 0x00027DEE, +- 0x034, 0x00026DEB, +- 0x034, 0x00025CEC, +- 0x034, 0x00024CE9, +- 0x034, 0x000238CA, +- 0x034, 0x00022889, +- 0x034, 0x00021489, +- 0x034, 0x0002044A, +- 0xFF0F0204, 0xCDEF, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, +@@ -1519,7 +1537,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, +- 0xFF0F0404, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00028DF1, + 0x034, 0x00027DEE, + 0x034, 0x00026DEB, +@@ -1529,7 +1547,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00022889, + 0x034, 0x00021489, + 0x034, 0x0002044A, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x000280AF, + 0x034, 0x000270AC, + 0x034, 0x0002608B, +@@ -1539,7 +1557,27 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00022026, + 0x034, 0x00021023, + 0x034, 0x00020002, +- 0xCDCDCDCD, 0xCDCD, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x000280AF, ++ 0x034, 0x000270AC, ++ 0x034, 0x0002608B, ++ 0x034, 0x00025069, ++ 0x034, 0x00024048, ++ 0x034, 0x00023045, ++ 0x034, 0x00022026, ++ 0x034, 0x00021023, ++ 0x034, 0x00020002, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x00028DF1, ++ 0x034, 0x00027DEE, ++ 0x034, 0x00026DEB, ++ 0x034, 0x00025CEC, ++ 0x034, 0x00024CE9, ++ 0x034, 0x000238CA, ++ 0x034, 0x00022889, ++ 0x034, 0x00021489, ++ 0x034, 0x0002044A, ++ 0xA0000000, 0x00000000, + 0x034, 0x00028DEE, + 0x034, 0x00027DEB, + 0x034, 0x00026CCD, +@@ -1549,27 +1587,24 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00022849, + 0x034, 0x00021449, + 0x034, 0x0002004D, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F02C0, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x8000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0000A0D7, ++ 0x034, 0x000090D3, ++ 0x034, 0x000080B1, ++ 0x034, 0x000070AE, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000A0D7, + 0x034, 0x000090D3, + 0x034, 0x000080B1, + 0x034, 0x000070AE, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x034, 0x0000ADF7, + 0x034, 0x00009DF4, + 0x034, 0x00008DF1, + 0x034, 0x00007DEE, +- 0xFF0F02C0, 0xDEAD, +- 0xFF0F0104, 0xABCD, +- 0x034, 0x00006DEB, +- 0x034, 0x00005CEC, +- 0x034, 0x00004CE9, +- 0x034, 0x000038CA, +- 0x034, 0x00002889, +- 0x034, 0x00001489, +- 0x034, 0x0000044A, +- 0xFF0F0204, 0xCDEF, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, +@@ -1577,7 +1612,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, +- 0xFF0F0404, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x00006DEB, + 0x034, 0x00005CEC, + 0x034, 0x00004CE9, +@@ -1585,7 +1620,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00002889, + 0x034, 0x00001489, + 0x034, 0x0000044A, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x034, 0x0000608D, + 0x034, 0x0000506B, + 0x034, 0x0000404A, +@@ -1593,7 +1628,23 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00002044, + 0x034, 0x00001025, + 0x034, 0x00000004, +- 0xCDCDCDCD, 0xCDCD, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x0000608D, ++ 0x034, 0x0000506B, ++ 0x034, 0x0000404A, ++ 0x034, 0x00003047, ++ 0x034, 0x00002044, ++ 0x034, 0x00001025, ++ 0x034, 0x00000004, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x034, 0x00006DEB, ++ 0x034, 0x00005CEC, ++ 0x034, 0x00004CE9, ++ 0x034, 0x000038CA, ++ 0x034, 0x00002889, ++ 0x034, 0x00001489, ++ 0x034, 0x0000044A, ++ 0xA0000000, 0x00000000, + 0x034, 0x00006DCD, + 0x034, 0x00005CCD, + 0x034, 0x00004CCA, +@@ -1601,11 +1652,11 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x034, 0x00002888, + 0x034, 0x00001488, + 0x034, 0x00000486, +- 0xFF0F0104, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000040, +- 0xFF0F0104, 0xABCD, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, +@@ -1615,7 +1666,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, +@@ -1625,7 +1676,37 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x035, 0x00000128, ++ 0x035, 0x00008128, ++ 0x035, 0x00010128, ++ 0x035, 0x000201C8, ++ 0x035, 0x000281C8, ++ 0x035, 0x000301C8, ++ 0x035, 0x000401C8, ++ 0x035, 0x000481C8, ++ 0x035, 0x000501C8, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x035, 0x00000145, ++ 0x035, 0x00008145, ++ 0x035, 0x00010145, ++ 0x035, 0x00020196, ++ 0x035, 0x00028196, ++ 0x035, 0x00030196, ++ 0x035, 0x000401C7, ++ 0x035, 0x000481C7, ++ 0x035, 0x000501C7, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x035, 0x00000128, ++ 0x035, 0x00008128, ++ 0x035, 0x00010128, ++ 0x035, 0x000201C8, ++ 0x035, 0x000281C8, ++ 0x035, 0x000301C8, ++ 0x035, 0x000401C8, ++ 0x035, 0x000481C8, ++ 0x035, 0x000501C8, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x035, 0x00000187, + 0x035, 0x00008187, + 0x035, 0x00010187, +@@ -1635,7 +1716,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x035, 0x00040188, + 0x035, 0x00048188, + 0x035, 0x00050188, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x035, 0x00000145, + 0x035, 0x00008145, + 0x035, 0x00010145, +@@ -1645,11 +1726,11 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x035, 0x000401C7, + 0x035, 0x000481C7, + 0x035, 0x000501C7, +- 0xFF0F0104, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000010, +- 0xFF0F0104, 0xABCD, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, +@@ -1662,7 +1743,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, +@@ -1675,7 +1756,46 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x036, 0x000063B5, ++ 0x036, 0x0000E3B5, ++ 0x036, 0x000163B5, ++ 0x036, 0x0001E3B5, ++ 0x036, 0x000263B5, ++ 0x036, 0x0002E3B5, ++ 0x036, 0x000363B5, ++ 0x036, 0x0003E3B5, ++ 0x036, 0x000463B5, ++ 0x036, 0x0004E3B5, ++ 0x036, 0x000563B5, ++ 0x036, 0x0005E3B5, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x036, 0x000056B3, ++ 0x036, 0x0000D6B3, ++ 0x036, 0x000156B3, ++ 0x036, 0x0001D6B3, ++ 0x036, 0x00026634, ++ 0x036, 0x0002E634, ++ 0x036, 0x00036634, ++ 0x036, 0x0003E634, ++ 0x036, 0x000467B4, ++ 0x036, 0x0004E7B4, ++ 0x036, 0x000567B4, ++ 0x036, 0x0005E7B4, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x036, 0x000063B5, ++ 0x036, 0x0000E3B5, ++ 0x036, 0x000163B5, ++ 0x036, 0x0001E3B5, ++ 0x036, 0x000263B5, ++ 0x036, 0x0002E3B5, ++ 0x036, 0x000363B5, ++ 0x036, 0x0003E3B5, ++ 0x036, 0x000463B5, ++ 0x036, 0x0004E3B5, ++ 0x036, 0x000563B5, ++ 0x036, 0x0005E3B5, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x036, 0x00085733, + 0x036, 0x0008D733, + 0x036, 0x00095733, +@@ -1688,7 +1808,7 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x036, 0x000CE4B4, + 0x036, 0x000D64B4, + 0x036, 0x000DE4B4, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x036, 0x000056B3, + 0x036, 0x0000D6B3, + 0x036, 0x000156B3, +@@ -1701,103 +1821,162 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x036, 0x0004E7B4, + 0x036, 0x000567B4, + 0x036, 0x0005E7B4, +- 0xFF0F0104, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0EF, 0x00000008, +- 0xFF0F0104, 0xABCD, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x000001B6, ++ 0x03C, 0x00000492, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x0000022A, ++ 0x03C, 0x00000594, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x000001B6, ++ 0x03C, 0x00000492, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x000001C8, + 0x03C, 0x00000492, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x03C, 0x0000022A, + 0x03C, 0x00000594, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000800, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x03C, 0x00000820, +- 0xCDCDCDCD, 0xCDCD, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x00000820, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x00000800, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x03C, 0x00000800, ++ 0xA0000000, 0x00000000, + 0x03C, 0x00000900, +- 0xFF0F0104, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x018, 0x0001712A, + 0x0EF, 0x00000002, +- 0xFF0F0104, 0xABCD, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x008, 0x00002000, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x008, 0x00002000, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x008, 0x00002000, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x008, 0x00002000, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x008, 0x0004E400, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x008, 0x00002000, +- 0xFF0F0104, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x0EF, 0x00000000, + 0x0DF, 0x000000C0, +- 0x01F, 0x00040064, +- 0xFF0F0104, 0xABCD, ++ 0x01F, 0x00000064, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, +- 0xFF0F0404, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x058, 0x00081184, ++ 0x059, 0x0006016C, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x058, 0x00081184, ++ 0x059, 0x0006016C, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x058, 0x00081184, ++ 0x059, 0x0006016C, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x058, 0x000A7284, + 0x059, 0x000600EC, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x058, 0x00081184, + 0x059, 0x0006016C, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x061, 0x000EFD83, ++ 0x062, 0x00093FCC, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x061, 0x000EAD53, ++ 0x062, 0x00093BC4, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x061, 0x000EFD83, ++ 0x062, 0x00093FCC, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x061, 0x000E8D73, + 0x062, 0x00093FC5, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x061, 0x000EAD53, + 0x062, 0x00093BC4, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, +- 0xFF0F0204, 0xCDEF, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, +- 0xFF0F0404, 0xCDEF, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, ++ 0x063, 0x000110EB, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, +- 0xFF0F0200, 0xCDEF, +- 0x063, 0x000710E9, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x063, 0x000110E9, +- 0xCDCDCDCD, 0xCDCD, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x063, 0x000110EB, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, ++ 0x063, 0x000110E9, ++ 0xA0000000, 0x00000000, + 0x063, 0x000714E9, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0104, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, ++ 0x064, 0x0001C27C, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, ++ 0x064, 0x0001C27C, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, +- 0xFF0F0204, 0xCDEF, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x064, 0x0001C67C, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, +- 0xFF0F0404, 0xCDEF, ++ 0x90000410, 0x00000000, 0x40000000, 0x00000000, + 0x064, 0x0001C27C, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x064, 0x0001C67C, +- 0xFF0F0104, 0xDEAD, +- 0xFF0F0200, 0xABCD, ++ 0xB0000000, 0x00000000, ++ 0x80000111, 0x00000000, 0x40000000, 0x00000000, ++ 0x065, 0x00091016, ++ 0x90000110, 0x00000000, 0x40000000, 0x00000000, ++ 0x065, 0x00091016, ++ 0x90000210, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093016, +- 0xFF0F02C0, 0xCDEF, ++ 0x9000020c, 0x00000000, 0x40000000, 0x00000000, + 0x065, 0x00093015, +- 0xCDCDCDCD, 0xCDCD, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, ++ 0x065, 0x00093015, ++ 0x90000200, 0x00000000, 0x40000000, 0x00000000, ++ 0x065, 0x00093016, ++ 0xA0000000, 0x00000000, + 0x065, 0x00091016, +- 0xFF0F0200, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x018, 0x00000006, + 0x0EF, 0x00002000, + 0x03B, 0x0003824B, +@@ -1895,9 +2074,10 @@ u32 RTL8821AE_RADIOA_ARRAY[] = { + 0x0B4, 0x0001214C, + 0x0B7, 0x0003000C, + 0x01C, 0x000539D2, ++ 0x0C4, 0x000AFE00, + 0x018, 0x0001F12A, +- 0x0FE, 0x00000000, +- 0x0FE, 0x00000000, ++ 0xFFE, 0x00000000, ++ 0xFFE, 0x00000000, + 0x018, 0x0001712A, + + }; +@@ -2017,6 +2197,7 @@ u32 RTL8812AE_MAC_REG_ARRAY[] = { + u32 RTL8812AE_MAC_1T_ARRAYLEN = ARRAY_SIZE(RTL8812AE_MAC_REG_ARRAY); + + u32 RTL8821AE_MAC_REG_ARRAY[] = { ++ 0x421, 0x0000000F, + 0x428, 0x0000000A, + 0x429, 0x00000010, + 0x430, 0x00000000, +@@ -2485,7 +2666,7 @@ u32 RTL8821AE_AGC_TAB_ARRAY[] = { + 0x81C, 0xA6360001, + 0x81C, 0xA5380001, + 0x81C, 0xA43A0001, +- 0x81C, 0xA33C0001, ++ 0x81C, 0x683C0001, + 0x81C, 0x673E0001, + 0x81C, 0x66400001, + 0x81C, 0x65420001, +@@ -2519,7 +2700,66 @@ u32 RTL8821AE_AGC_TAB_ARRAY[] = { + 0x81C, 0x017A0001, + 0x81C, 0x017C0001, + 0x81C, 0x017E0001, +- 0xFF0F02C0, 0xABCD, ++ 0x8000020c, 0x00000000, 0x40000000, 0x00000000, ++ 0x81C, 0xFB000101, ++ 0x81C, 0xFA020101, ++ 0x81C, 0xF9040101, ++ 0x81C, 0xF8060101, ++ 0x81C, 0xF7080101, ++ 0x81C, 0xF60A0101, ++ 0x81C, 0xF50C0101, ++ 0x81C, 0xF40E0101, ++ 0x81C, 0xF3100101, ++ 0x81C, 0xF2120101, ++ 0x81C, 0xF1140101, ++ 0x81C, 0xF0160101, ++ 0x81C, 0xEF180101, ++ 0x81C, 0xEE1A0101, ++ 0x81C, 0xED1C0101, ++ 0x81C, 0xEC1E0101, ++ 0x81C, 0xEB200101, ++ 0x81C, 0xEA220101, ++ 0x81C, 0xE9240101, ++ 0x81C, 0xE8260101, ++ 0x81C, 0xE7280101, ++ 0x81C, 0xE62A0101, ++ 0x81C, 0xE52C0101, ++ 0x81C, 0xE42E0101, ++ 0x81C, 0xE3300101, ++ 0x81C, 0xA5320101, ++ 0x81C, 0xA4340101, ++ 0x81C, 0xA3360101, ++ 0x81C, 0x87380101, ++ 0x81C, 0x863A0101, ++ 0x81C, 0x853C0101, ++ 0x81C, 0x843E0101, ++ 0x81C, 0x69400101, ++ 0x81C, 0x68420101, ++ 0x81C, 0x67440101, ++ 0x81C, 0x66460101, ++ 0x81C, 0x49480101, ++ 0x81C, 0x484A0101, ++ 0x81C, 0x474C0101, ++ 0x81C, 0x2A4E0101, ++ 0x81C, 0x29500101, ++ 0x81C, 0x28520101, ++ 0x81C, 0x27540101, ++ 0x81C, 0x26560101, ++ 0x81C, 0x25580101, ++ 0x81C, 0x245A0101, ++ 0x81C, 0x235C0101, ++ 0x81C, 0x055E0101, ++ 0x81C, 0x04600101, ++ 0x81C, 0x03620101, ++ 0x81C, 0x02640101, ++ 0x81C, 0x01660101, ++ 0x81C, 0x01680101, ++ 0x81C, 0x016A0101, ++ 0x81C, 0x016C0101, ++ 0x81C, 0x016E0101, ++ 0x81C, 0x01700101, ++ 0x81C, 0x01720101, ++ 0x9000040c, 0x00000000, 0x40000000, 0x00000000, + 0x81C, 0xFB000101, + 0x81C, 0xFA020101, + 0x81C, 0xF9040101, +@@ -2578,7 +2818,7 @@ u32 RTL8821AE_AGC_TAB_ARRAY[] = { + 0x81C, 0x016E0101, + 0x81C, 0x01700101, + 0x81C, 0x01720101, +- 0xCDCDCDCD, 0xCDCD, ++ 0xA0000000, 0x00000000, + 0x81C, 0xFF000101, + 0x81C, 0xFF020101, + 0x81C, 0xFE040101, +@@ -2637,7 +2877,7 @@ u32 RTL8821AE_AGC_TAB_ARRAY[] = { + 0x81C, 0x046E0101, + 0x81C, 0x03700101, + 0x81C, 0x02720101, +- 0xFF0F02C0, 0xDEAD, ++ 0xB0000000, 0x00000000, + 0x81C, 0x01740101, + 0x81C, 0x01760101, + 0x81C, 0x01780101, diff --git a/recipes-kernel/mac80211/mac80211/0007-backport-of-netmodule-patches-from-openwrt.patch b/recipes-kernel/mac80211/mac80211/0008-netmodule-patches.patch similarity index 57% rename from recipes-kernel/mac80211/mac80211/0007-backport-of-netmodule-patches-from-openwrt.patch rename to recipes-kernel/mac80211/mac80211/0008-netmodule-patches.patch index cdc13a4..acb1be4 100644 --- a/recipes-kernel/mac80211/mac80211/0007-backport-of-netmodule-patches-from-openwrt.patch +++ b/recipes-kernel/mac80211/mac80211/0008-netmodule-patches.patch @@ -1,35 +1,123 @@ -From 3ec00c7616f20083d3775e28bcf76b660838e9b3 Mon Sep 17 00:00:00 2001 +From 6e5ef0edd3782babdeb47e7cc7b67afd3b225d95 Mon Sep 17 00:00:00 2001 From: Patrick Walther -Date: Fri, 24 Jul 2020 18:56:44 +0200 -Subject: [PATCH] backport of netmodule patches from openwrt +Date: Mon, 22 Mar 2021 17:52:02 +0100 +Subject: [PATCH] 0007 netmodule patches --- - drivers/net/wireless/ath/ath10k/mac.c | 2 +- - drivers/net/wireless/ath/ath10k/pci.c | 2 +- - drivers/net/wireless/ath/regd.c | 2 +- - drivers/net/wireless/ath/regd.h | 3 +- - drivers/net/wireless/ath/regd_common.h | 1 + - drivers/net/wireless/ti/wlcore/cmd.c | 13 +++---- - drivers/net/wireless/ti/wlcore/cmd.h | 3 +- - drivers/net/wireless/ti/wlcore/conf.h | 3 ++ - drivers/net/wireless/ti/wlcore/init.c | 22 +++++++++--- - drivers/net/wireless/ti/wlcore/main.c | 58 ++++++++++++++++++++----------- - drivers/net/wireless/ti/wlcore/wlcore_i.h | 1 + - include/net/cfg80211.h | 10 ++++-- - include/net/mac80211.h | 7 ++-- - include/uapi/linux/nl80211.h | 3 ++ - net/mac80211/cfg.c | 13 +++++++ - net/mac80211/main.c | 4 +-- - net/wireless/core.c | 41 ++++++++++++++++++---- - net/wireless/nl80211.c | 13 +++++++ - net/wireless/reg.c | 23 +++++++++--- - 19 files changed, 167 insertions(+), 57 deletions(-) + drivers/net/wireless/ath/ath10k/htt_rx.c | 6 +++-- + drivers/net/wireless/ath/ath10k/mac.c | 40 ++++++++++++++++++++++++------- + drivers/net/wireless/ath/ath10k/pci.c | 2 +- + drivers/net/wireless/ath/regd.c | 2 +- + drivers/net/wireless/ath/regd.h | 3 ++- + drivers/net/wireless/ath/regd_common.h | 1 + + drivers/net/wireless/ti/wlcore/cmd.c | 7 ------ + drivers/net/wireless/ti/wlcore/cmd.h | 1 + + drivers/net/wireless/ti/wlcore/conf.h | 3 +++ + drivers/net/wireless/ti/wlcore/init.c | 22 +++++++++++++---- + drivers/net/wireless/ti/wlcore/main.c | 27 +++++++++++++++------ + include/net/cfg80211.h | 11 +++++++-- + include/net/mac80211.h | 8 +++++-- + include/uapi/linux/nl80211.h | 3 +++ + net/mac80211/cfg.c | 13 ++++++++++ + net/mac80211/main.c | 4 ++-- + net/wireless/core.c | 41 ++++++++++++++++++++++++++------ + net/wireless/nl80211.c | 13 ++++++++++ + net/wireless/reg.c | 23 ++++++++++++++---- + 19 files changed, 180 insertions(+), 50 deletions(-) +diff --git a/drivers/net/wireless/ath/ath10k/htt_rx.c b/drivers/net/wireless/ath/ath10k/htt_rx.c +index 5c1af20..5f166bc 100644 +--- a/drivers/net/wireless/ath/ath10k/htt_rx.c ++++ b/drivers/net/wireless/ath/ath10k/htt_rx.c +@@ -3683,8 +3683,10 @@ static void ath10k_fetch_10_2_tx_stats(struct ath10k *ar, u8 *data) + spin_lock_bh(&ar->data_lock); + peer = ath10k_peer_find_by_id(ar, peer_id); + if (!peer || !peer->sta) { +- ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n", +- peer_id); ++ if (peer_id != 0xFF) { ++ ath10k_warn(ar, "Invalid peer id %d in peer stats buffer\n", ++ peer_id); ++ } + goto out; + } + diff --git a/drivers/net/wireless/ath/ath10k/mac.c b/drivers/net/wireless/ath/ath10k/mac.c -index 7946d3b..ba289ad 100644 +index d07a4a1..9547476 100644 --- a/drivers/net/wireless/ath/ath10k/mac.c +++ b/drivers/net/wireless/ath/ath10k/mac.c -@@ -8419,7 +8419,7 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { +@@ -5097,11 +5097,13 @@ static int ath10k_start(struct ieee80211_hw *hw) + } + + param = ar->wmi.pdev_param->idle_ps_config; +- ret = ath10k_wmi_pdev_set_param(ar, param, 1); +- if (ret && ret != -EOPNOTSUPP) { +- ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret); +- goto err_core_stop; +- } ++ if (param != WMI_PDEV_PARAM_UNSUPPORTED) { ++ ret = ath10k_wmi_pdev_set_param(ar, param, 1); ++ if (ret && ret != -EOPNOTSUPP) { ++ ath10k_warn(ar, "failed to enable idle_ps_config: %d\n", ret); ++ goto err_core_stop; ++ } ++ } + + __ath10k_set_antenna(ar, ar->cfg_tx_chainmask, ar->cfg_rx_chainmask); + +@@ -5273,10 +5275,11 @@ static int ath10k_mac_txpower_setup(struct ath10k *ar, int txpower) + return 0; + } + ++#define ATH10k_ADJ_POWER_DENSITY 1 + static int ath10k_mac_txpower_recalc(struct ath10k *ar) + { + struct ath10k_vif *arvif; +- int ret, txpower = -1; ++ int ret, txpower = -1, pwr; + + lockdep_assert_held(&ar->conf_mutex); + +@@ -5285,10 +5288,28 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar) + if (arvif->txpower == INT_MIN) + continue; + ++ pwr = arvif->txpower; ++ ++ if (ar && ar->rx_channel ) { ++ if (ar->rx_channel->band == NL80211_BAND_5GHZ) { ++ pwr -= ATH10k_ADJ_POWER_DENSITY; ++ if (ar->rx_channel->flags & IEEE80211_CHAN_RADAR) { ++ pwr -= ATH10k_ADJ_POWER_DENSITY; ++ if (arvif->vif->type == NL80211_IFTYPE_STATION || ++ arvif->vif->type == NL80211_IFTYPE_MESH_POINT) { ++ pwr -= ATH10k_ADJ_POWER_DENSITY; ++ } ++ } ++ } ++ } ++ if (pwr < 0) { ++ pwr = 0; ++ } ++ + if (txpower == -1) +- txpower = arvif->txpower; ++ txpower = pwr; + else +- txpower = min(txpower, arvif->txpower); ++ txpower = min(txpower, pwr); + } + + if (txpower == -1) +@@ -5303,6 +5324,7 @@ static int ath10k_mac_txpower_recalc(struct ath10k *ar) + + return 0; + } ++#undef ATH10k_CLIENT_ADJ_POWER_DENSITY + + static int ath10k_config(struct ieee80211_hw *hw, u32 changed) + { +@@ -9440,7 +9462,7 @@ static const struct ieee80211_iface_limit ath10k_10x_if_limits[] = { #endif }, { @@ -39,7 +127,7 @@ index 7946d3b..ba289ad 100644 }, }; diff --git a/drivers/net/wireless/ath/ath10k/pci.c b/drivers/net/wireless/ath/ath10k/pci.c -index d7435c9..57ec879 100644 +index a7b6b8c..dc8c753 100644 --- a/drivers/net/wireless/ath/ath10k/pci.c +++ b/drivers/net/wireless/ath/ath10k/pci.c @@ -28,7 +28,7 @@ enum ath10k_pci_reset_mode { @@ -52,7 +140,7 @@ index d7435c9..57ec879 100644 module_param_named(irq_mode, ath10k_pci_irq_mode, uint, 0644); diff --git a/drivers/net/wireless/ath/regd.c b/drivers/net/wireless/ath/regd.c -index e263400..c242f00 100644 +index 0042ea9..f7b15cf 100644 --- a/drivers/net/wireless/ath/regd.c +++ b/drivers/net/wireless/ath/regd.c @@ -733,7 +733,7 @@ static int __ath_regd_init(struct ath_regulatory *reg) @@ -91,31 +179,10 @@ index 364011e..4db829c 100644 #endif diff --git a/drivers/net/wireless/ti/wlcore/cmd.c b/drivers/net/wireless/ti/wlcore/cmd.c -index 2a48fc6..888cfd7 100644 +index 32a2e27..a82b0ee 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.c +++ b/drivers/net/wireless/ti/wlcore/cmd.c -@@ -1429,7 +1429,7 @@ out: - int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, -- u16 tx_seq_16) -+ u16 tx_seq_16, bool is_pairwise) - { - struct wl1271_cmd_set_keys *cmd; - int ret = 0; -@@ -1444,8 +1444,10 @@ int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - lid_type = WEP_DEFAULT_LID_TYPE; - else - lid_type = BROADCAST_LID_TYPE; -- } else { -+ } else if (is_pairwise) { - lid_type = UNICAST_LID_TYPE; -+ } else { -+ lid_type = BROADCAST_LID_TYPE; - } - - wl1271_debug(DEBUG_CRYPT, "ap key action: %d id: %d lid: %d type: %d" -@@ -1565,13 +1567,6 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, +@@ -1568,13 +1568,6 @@ int wl12xx_cmd_add_peer(struct wl1271 *wl, struct wl12xx_vif *wlvif, cpu_to_le32(wl1271_tx_enabled_rates_get(wl, sta_rates, wlvif->band)); @@ -130,28 +197,19 @@ index 2a48fc6..888cfd7 100644 cmd->supported_rates, sta->uapsd_queues); diff --git a/drivers/net/wireless/ti/wlcore/cmd.h b/drivers/net/wireless/ti/wlcore/cmd.h -index 084375b..24ee7ab 100644 +index f2609d5..3c091e4 100644 --- a/drivers/net/wireless/ti/wlcore/cmd.h +++ b/drivers/net/wireless/ti/wlcore/cmd.h -@@ -65,7 +65,7 @@ int wl1271_cmd_set_sta_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - int wl1271_cmd_set_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u8 hlid, u32 tx_seq_32, -- u16 tx_seq_16); -+ u16 tx_seq_16, bool is_pairwise); - int wl12xx_cmd_set_peer_state(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 hlid); - int wl12xx_roc(struct wl1271 *wl, struct wl12xx_vif *wlvif, u8 role_id, @@ -458,6 +458,7 @@ enum wl1271_cmd_key_type { KEY_TKIP = 2, KEY_AES = 3, KEY_GEM = 4, -+ KEY_IGTK = 5, ++ KEY_IGTK = 5, }; struct wl1271_cmd_set_keys { diff --git a/drivers/net/wireless/ti/wlcore/conf.h b/drivers/net/wireless/ti/wlcore/conf.h -index 6116383..e33f577 100644 +index 31be425..53d40a2 100644 --- a/drivers/net/wireless/ti/wlcore/conf.h +++ b/drivers/net/wireless/ti/wlcore/conf.h @@ -215,6 +215,9 @@ struct conf_rx_settings { @@ -165,14 +223,14 @@ index 6116383..e33f577 100644 CONF_HW_BIT_RATE_12MBPS | CONF_HW_BIT_RATE_24MBPS | \ CONF_HW_BIT_RATE_36MBPS | CONF_HW_BIT_RATE_48MBPS | \ diff --git a/drivers/net/wireless/ti/wlcore/init.c b/drivers/net/wireless/ti/wlcore/init.c -index 03b49ba..6334351 100644 +index 03b49ba..5275d6b 100644 --- a/drivers/net/wireless/ti/wlcore/init.c +++ b/drivers/net/wireless/ti/wlcore/init.c @@ -425,6 +425,7 @@ int wl1271_init_ap_rates(struct wl1271 *wl, struct wl12xx_vif *wlvif) int i, ret; struct conf_tx_rate_class rc; u32 supported_rates; -+ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); ++ struct ieee80211_vif *vif = wl12xx_wlvif_to_vif(wlvif); wl1271_debug(DEBUG_AP, "AP basic rate set: 0x%x", wlvif->basic_rate_set); @@ -184,20 +242,20 @@ index 03b49ba..6334351 100644 - rc.long_retry_limit = 10; - rc.short_retry_limit = 10; - rc.aflags = 0; -+ /*In order to handle mesh PREQ/PREP loss, increase retry limit -+ and use OFDM basic rates (mgmt policy)*/ -+ if (ieee80211_vif_is_mesh(vif)) { -+ rc.enabled_rates = wlvif->basic_rate_set; -+ rc.long_retry_limit = 30; -+ rc.short_retry_limit = 30; -+ rc.aflags = 0; -+ } -+ else { -+ rc.enabled_rates = wlvif->basic_rate_set; -+ rc.long_retry_limit = 10; -+ rc.short_retry_limit = 10; -+ rc.aflags = 0; -+ } ++ /*In order to handle mesh PREQ/PREP loss, increase retry limit ++ and use OFDM basic rates (mgmt policy)*/ ++ if (ieee80211_vif_is_mesh(vif)) { ++ rc.enabled_rates = wlvif->basic_rate_set; ++ rc.long_retry_limit = 30; ++ rc.short_retry_limit = 30; ++ rc.aflags = 0; ++ } ++ else { ++ rc.enabled_rates = wlvif->basic_rate_set; ++ rc.long_retry_limit = 10; ++ rc.short_retry_limit = 10; ++ rc.aflags = 0; ++ } + ret = wl1271_acx_ap_rate_policy(wl, &rc, wlvif->ap.mgmt_rate_idx); if (ret < 0) @@ -210,25 +268,10 @@ index 03b49ba..6334351 100644 rc.long_retry_limit = 10; rc.aflags = 0; diff --git a/drivers/net/wireless/ti/wlcore/main.c b/drivers/net/wireless/ti/wlcore/main.c -index 6d36cbf..aa6f22c 100644 +index b5e3a42..5cc837e 100644 --- a/drivers/net/wireless/ti/wlcore/main.c +++ b/drivers/net/wireless/ti/wlcore/main.c -@@ -2213,12 +2213,13 @@ static u8 wl12xx_get_role_type(struct wl1271 *wl, struct wl12xx_vif *wlvif) - static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) - { - struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); -+ enum nl80211_iftype iftype = ieee80211_vif_type_p2p(vif); - int i; - - /* clear everything but the persistent data */ - memset(wlvif, 0, offsetof(struct wl12xx_vif, persistent)); - -- switch (ieee80211_vif_type_p2p(vif)) { -+ switch (iftype) { - case NL80211_IFTYPE_P2P_CLIENT: - wlvif->p2p = 1; - /* fall-through */ -@@ -2265,13 +2266,14 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) +@@ -2271,13 +2271,15 @@ static int wl12xx_init_vif_data(struct wl1271 *wl, struct ieee80211_vif *vif) for (i = 0; i < CONF_TX_MAX_AC_COUNT; i++) wl12xx_allocate_rate_policy(wl, &wlvif->ap.ucast_rate_idx[i]); @@ -239,194 +282,74 @@ index 6d36cbf..aa6f22c 100644 - * instead (the same thing for STA above). - */ - wlvif->basic_rate = CONF_TX_ENABLED_RATES; -+ /* For mesh set default basic rate set to OFDM basic rate set only*/ -+ if (iftype == NL80211_IFTYPE_MESH_POINT) -+ wlvif->basic_rate_set = CONF_TX_OFDM_BASIC_RATES; -+ else -+ wlvif->basic_rate_set = CONF_TX_ENABLED_RATES; + -+ wlvif->basic_rate = wl1271_tx_min_rate_get(wl, CONF_TX_ENABLED_RATES); ++ /* For mesh set default basic rate set to OFDM basic rate set only*/ ++ if (ieee80211_vif_type_p2p(vif) == NL80211_IFTYPE_MESH_POINT) ++ wlvif->basic_rate_set = CONF_TX_OFDM_BASIC_RATES; ++ else ++ wlvif->basic_rate_set = CONF_TX_ENABLED_RATES; + ++ wlvif->basic_rate = wl1271_tx_min_rate_get(wl, CONF_TX_ENABLED_RATES); ++ /* TODO: this seems to be used only for STA, check it */ wlvif->rate_set = CONF_TX_ENABLED_RATES; } -@@ -3274,7 +3276,7 @@ out: - static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u8 id, u8 key_type, u8 key_size, - const u8 *key, u8 hlid, u32 tx_seq_32, -- u16 tx_seq_16) -+ u16 tx_seq_16, bool is_pairwise) - { - struct wl1271_ap_key *ap_key; - int i; -@@ -3312,6 +3314,7 @@ static int wl1271_record_ap_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - ap_key->hlid = hlid; - ap_key->tx_seq_32 = tx_seq_32; - ap_key->tx_seq_16 = tx_seq_16; -+ ap_key->is_pairwise = is_pairwise; - - wlvif->ap.recorded_keys[i] = ap_key; - return 0; -@@ -3347,7 +3350,7 @@ static int wl1271_ap_init_hwenc(struct wl1271 *wl, struct wl12xx_vif *wlvif) - key->id, key->key_type, - key->key_size, key->key, - hlid, key->tx_seq_32, -- key->tx_seq_16); -+ key->tx_seq_16, key->is_pairwise); - if (ret < 0) - goto out; - -@@ -3370,7 +3373,8 @@ out: - static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - u16 action, u8 id, u8 key_type, - u8 key_size, const u8 *key, u32 tx_seq_32, -- u16 tx_seq_16, struct ieee80211_sta *sta) -+ u16 tx_seq_16, struct ieee80211_sta *sta, -+ bool is_pairwise) - { - int ret; - bool is_ap = (wlvif->bss_type == BSS_TYPE_AP_BSS); -@@ -3397,12 +3401,12 @@ static int wl1271_set_key(struct wl1271 *wl, struct wl12xx_vif *wlvif, - ret = wl1271_record_ap_key(wl, wlvif, id, - key_type, key_size, - key, hlid, tx_seq_32, -- tx_seq_16); -+ tx_seq_16, is_pairwise); - } else { - ret = wl1271_cmd_set_ap_key(wl, wlvif, action, - id, key_type, key_size, - key, hlid, tx_seq_32, -- tx_seq_16); -+ tx_seq_16, is_pairwise); - } - - if (ret < 0) -@@ -3502,6 +3506,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, - u16 tx_seq_16 = 0; - u8 key_type; - u8 hlid; -+ bool is_pairwise; - - wl1271_debug(DEBUG_MAC80211, "mac80211 set key"); - -@@ -3538,6 +3543,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, - key_type = KEY_TKIP; - key_conf->hw_key_idx = key_conf->keyidx; +@@ -3555,6 +3557,9 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, + key_type = KEY_AES; + key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; break; + case WLAN_CIPHER_SUITE_AES_CMAC: + key_type = KEY_IGTK; + break; - case WLAN_CIPHER_SUITE_CCMP: - key_type = KEY_AES; - key_conf->flags |= IEEE80211_KEY_FLAG_PUT_IV_SPACE; -@@ -3551,12 +3559,14 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, - return -EOPNOTSUPP; - } - -+ is_pairwise = key_conf->flags & IEEE80211_KEY_FLAG_PAIRWISE; -+ - switch (cmd) { - case SET_KEY: - ret = wl1271_set_key(wl, wlvif, KEY_ADD_OR_REPLACE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, -- tx_seq_32, tx_seq_16, sta); -+ tx_seq_32, tx_seq_16, sta, is_pairwise); - if (ret < 0) { - wl1271_error("Could not add or replace key"); - return ret; -@@ -3582,7 +3592,7 @@ int wlcore_set_key(struct wl1271 *wl, enum set_key_cmd cmd, - ret = wl1271_set_key(wl, wlvif, KEY_REMOVE, - key_conf->keyidx, key_type, - key_conf->keylen, key_conf->key, -- 0, 0, sta); -+ 0, 0, sta, is_pairwise); - if (ret < 0) { - wl1271_error("Could not remove key"); - return ret; -@@ -5216,11 +5226,6 @@ static int wl12xx_update_sta_state(struct wl1271 *wl, - if (ret < 0) - return ret; - -- /* reconfigure rates */ -- ret = wl12xx_cmd_add_peer(wl, wlvif, sta, wl_sta->hlid); -- if (ret < 0) -- return ret; -- - ret = wl1271_acx_set_ht_capabilities(wl, &sta->ht_cap, true, - wl_sta->hlid); - if (ret) -@@ -5794,9 +5799,16 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, + case WL1271_CIPHER_SUITE_GEM: + key_type = KEY_GEM; + break; +@@ -5811,9 +5816,16 @@ static void wlcore_op_sta_statistics(struct ieee80211_hw *hw, { struct wl1271 *wl = hw->priv; struct wl12xx_vif *wlvif = wl12xx_vif_to_data(vif); -+ u8 role_type; ++ u8 role_type; s8 rssi_dbm; int ret; + role_type = wl12xx_get_role_type(wl, wlvif); + if (role_type == WL1271_ROLE_AP || + role_type == WL1271_ROLE_MESH_POINT) { -+ return; -+ } ++ return; ++ } + wl1271_debug(DEBUG_MAC80211, "mac80211 get_rssi"); mutex_lock(&wl->mutex); -@@ -6210,6 +6222,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) +@@ -6227,6 +6238,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) WLAN_CIPHER_SUITE_TKIP, WLAN_CIPHER_SUITE_CCMP, WL1271_CIPHER_SUITE_GEM, -+ WLAN_CIPHER_SUITE_AES_CMAC, ++ WLAN_CIPHER_SUITE_AES_CMAC, }; /* The tx descriptor buffer */ -@@ -6224,6 +6237,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) - - ieee80211_hw_set(wl->hw, SUPPORT_FAST_XMIT); - ieee80211_hw_set(wl->hw, CHANCTX_STA_CSA); -+ ieee80211_hw_set(wl->hw, SUPPORTS_PER_STA_GTK); - ieee80211_hw_set(wl->hw, QUEUE_CONTROL); - ieee80211_hw_set(wl->hw, TX_AMPDU_SETUP_IN_HW); - ieee80211_hw_set(wl->hw, AMPDU_AGGREGATION); -@@ -6268,9 +6282,11 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) - - wl->hw->wiphy->flags |= WIPHY_FLAG_AP_UAPSD | - WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL | -- WIPHY_FLAG_HAS_CHANNEL_SWITCH; -+ WIPHY_FLAG_HAS_CHANNEL_SWITCH | -+ WIPHY_FLAG_IBSS_RSN; +@@ -6290,6 +6302,7 @@ static int wl1271_init_ieee80211(struct wl1271 *wl) + WIPHY_FLAG_IBSS_RSN; wl->hw->wiphy->features |= NL80211_FEATURE_AP_SCAN; -+ wl->hw->wiphy->features &= ~NL80211_FEATURE_FULL_AP_CLIENT_STATE; ++ wl->hw->wiphy->features &= ~NL80211_FEATURE_FULL_AP_CLIENT_STATE; /* make sure all our channels fit in the scanned_ch bitmask */ BUILD_BUG_ON(ARRAY_SIZE(wl1271_channels) + -diff --git a/drivers/net/wireless/ti/wlcore/wlcore_i.h b/drivers/net/wireless/ti/wlcore/wlcore_i.h -index 6fab60b..eefae3f 100644 ---- a/drivers/net/wireless/ti/wlcore/wlcore_i.h -+++ b/drivers/net/wireless/ti/wlcore/wlcore_i.h -@@ -212,6 +212,7 @@ struct wl1271_ap_key { - u8 hlid; - u32 tx_seq_32; - u16 tx_seq_16; -+ bool is_pairwise; - }; - - enum wl12xx_flags { diff --git a/include/net/cfg80211.h b/include/net/cfg80211.h -index 8099b10..4849bab 100644 +index 449df09..1acf10c 100644 --- a/include/net/cfg80211.h +++ b/include/net/cfg80211.h -@@ -112,6 +112,7 @@ enum ieee80211_channel_flags { - IEEE80211_CHAN_IR_CONCURRENT = 1<<10, - IEEE80211_CHAN_NO_20MHZ = 1<<11, - IEEE80211_CHAN_NO_10MHZ = 1<<12, -+ IEEE80211_CHAN_SRD = 1<<13, +@@ -129,6 +129,7 @@ enum ieee80211_channel_flags { + IEEE80211_CHAN_4MHZ = 1<<16, + IEEE80211_CHAN_8MHZ = 1<<17, + IEEE80211_CHAN_16MHZ = 1<<18, ++ IEEE80211_CHAN_SRD = 1<<19, }; #define IEEE80211_CHAN_NO_HT40 \ -@@ -3456,6 +3457,8 @@ struct cfg80211_update_owe_info { +@@ -3738,6 +3739,8 @@ struct mgmt_frame_regs { * return 0 if successful * @set_antenna_gain: set antenna gain to reduce maximum tx power if necessary * @@ -435,63 +358,64 @@ index 8099b10..4849bab 100644 * @set_wds_peer: set the WDS peer for a WDS interface * * @rfkill_poll: polls the hw rfkill line, use cfg80211 reporting -@@ -3771,6 +3774,7 @@ struct cfg80211_ops { +@@ -4060,6 +4063,7 @@ struct cfg80211_ops { int (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev, int *dbm); int (*set_antenna_gain)(struct wiphy *wiphy, int dbi); -+ int (*get_antenna_gain)(struct wiphy *wiphy, int *dbi); ++ int (*get_antenna_gain)(struct wiphy *wiphy, int *dbi); int (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev, const u8 *addr); -@@ -4771,6 +4775,8 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) - * @sizeof_priv: The size of the private area to allocate +@@ -5101,6 +5105,9 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) * @requested_name: Request a particular name. * NULL is valid value, and means use the default phy%d naming. + * + * @requested_index: Request a particular index. + * -1 is valid value, and means use the default phy%d naming. - * ++ * * Create a new wiphy and associate the given operations with it. * @sizeof_priv bytes are allocated for private use. -@@ -4779,7 +4785,7 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) + * +@@ -5108,7 +5115,7 @@ static inline const char *wiphy_name(const struct wiphy *wiphy) * assigned to each netdev's ieee80211_ptr for proper operation. */ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, - const char *requested_name); -+ const char *requested_name, const int requested_index); ++ const char *requested_name, const int requested_index); /** * wiphy_new - create a new wiphy for use with cfg80211 -@@ -4796,7 +4802,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, +@@ -5125,7 +5132,7 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, static inline struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv) { - return wiphy_new_nm(ops, sizeof_priv, NULL); -+ return wiphy_new_nm(ops, sizeof_priv, NULL, -1); ++ return wiphy_new_nm(ops, sizeof_priv, NULL, -1); } /** diff --git a/include/net/mac80211.h b/include/net/mac80211.h -index bca141e..ae3316f 100644 +index 9f185ee..f9e10e3 100644 --- a/include/net/mac80211.h +++ b/include/net/mac80211.h -@@ -4087,12 +4087,15 @@ struct ieee80211_ops { - * @ops: callbacks for this device +@@ -4228,11 +4228,15 @@ struct ieee80211_ops { * @requested_name: Requested name for this device. * NULL is valid value, and means use the default naming (phy%d) + * + * @requested_name: Requested index for this device. + * -1 is valid value, and means use the default naming (phy%d) - * ++ * * Return: A pointer to the new hardware device, or %NULL on error. */ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, const struct ieee80211_ops *ops, - const char *requested_name); -+ const char *requested_name, -+ int requested_index); ++ const char *requested_name, ++ int requested_index); /** * ieee80211_alloc_hw - Allocate a new hardware device -@@ -4112,7 +4115,7 @@ static inline +@@ -4252,7 +4256,7 @@ static inline struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len, const struct ieee80211_ops *ops) { @@ -501,31 +425,31 @@ index bca141e..ae3316f 100644 /** diff --git a/include/uapi/linux/nl80211.h b/include/uapi/linux/nl80211.h -index ef08258..2f41258 100644 +index 0d90183..4f5ba93 100644 --- a/include/uapi/linux/nl80211.h +++ b/include/uapi/linux/nl80211.h -@@ -3559,6 +3559,8 @@ enum nl80211_wmm_rule { - * @NL80211_FREQUENCY_ATTR_WMM: this channel has wmm limitations. - * This is a nested attribute that contains the wmm limitation per AC. - * (see &enum nl80211_wmm_rule) +@@ -3779,6 +3779,8 @@ enum nl80211_wmm_rule { + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_16MHZ: 16 MHz operation is allowed + * on this channel in current regulatory domain. + * @NL80211_FREQUENCY_ATTR_SRD_CHANNEL: short range devices mode + * on this channel in current regulatory domain. * @NL80211_FREQUENCY_ATTR_MAX: highest frequency attribute number * currently defined * @__NL80211_FREQUENCY_ATTR_AFTER_LAST: internal use -@@ -3588,6 +3590,7 @@ enum nl80211_frequency_attr { - NL80211_FREQUENCY_ATTR_NO_20MHZ, - NL80211_FREQUENCY_ATTR_NO_10MHZ, - NL80211_FREQUENCY_ATTR_WMM, -+ NL80211_FREQUENCY_ATTR_SRD_CHANNEL, +@@ -3815,6 +3817,7 @@ enum nl80211_frequency_attr { + NL80211_FREQUENCY_ATTR_4MHZ, + NL80211_FREQUENCY_ATTR_8MHZ, + NL80211_FREQUENCY_ATTR_16MHZ, ++ NL80211_FREQUENCY_ATTR_SRD_CHANNEL, /* keep last */ __NL80211_FREQUENCY_ATTR_AFTER_LAST, diff --git a/net/mac80211/cfg.c b/net/mac80211/cfg.c -index 993ee7b..13bd5b2 100644 +index 272b433..2a30e87 100644 --- a/net/mac80211/cfg.c +++ b/net/mac80211/cfg.c -@@ -2595,6 +2595,18 @@ static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi) +@@ -2720,6 +2720,18 @@ static int ieee80211_set_antenna_gain(struct wiphy *wiphy, int dbi) return 0; } @@ -544,7 +468,7 @@ index 993ee7b..13bd5b2 100644 static int ieee80211_set_wds_peer(struct wiphy *wiphy, struct net_device *dev, const u8 *addr) { -@@ -4031,6 +4043,7 @@ const struct cfg80211_ops mac80211_config_ops = { +@@ -4151,6 +4163,7 @@ const struct cfg80211_ops mac80211_config_ops = { .set_tx_power = ieee80211_set_tx_power, .get_tx_power = ieee80211_get_tx_power, .set_antenna_gain = ieee80211_set_antenna_gain, @@ -553,10 +477,10 @@ index 993ee7b..13bd5b2 100644 .rfkill_poll = ieee80211_rfkill_poll, CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd) diff --git a/net/mac80211/main.c b/net/mac80211/main.c -index 71dada6..7bfa7bb 100644 +index 44076fb..293bfec 100644 --- a/net/mac80211/main.c +++ b/net/mac80211/main.c -@@ -512,7 +512,7 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { +@@ -532,7 +532,7 @@ static const struct ieee80211_vht_cap mac80211_vht_capa_mod_mask = { struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, const struct ieee80211_ops *ops, @@ -565,7 +489,7 @@ index 71dada6..7bfa7bb 100644 { struct ieee80211_local *local; int priv_size, i; -@@ -552,7 +552,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, +@@ -572,7 +572,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_nm(size_t priv_data_len, */ priv_size = ALIGN(sizeof(*local), NETDEV_ALIGN) + priv_data_len; @@ -575,7 +499,7 @@ index 71dada6..7bfa7bb 100644 if (!wiphy) return NULL; diff --git a/net/wireless/core.c b/net/wireless/core.c -index c8a6c0e..847d4f6 100644 +index afdfcc2..cefbcbc 100644 --- a/net/wireless/core.c +++ b/net/wireless/core.c @@ -123,6 +123,19 @@ static int cfg80211_dev_check_name(struct cfg80211_registered_device *rdev, @@ -598,7 +522,7 @@ index c8a6c0e..847d4f6 100644 int cfg80211_dev_rename(struct cfg80211_registered_device *rdev, char *newname) { -@@ -396,7 +409,7 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work) +@@ -398,7 +411,7 @@ static void cfg80211_propagate_cac_done_wk(struct work_struct *work) /* exported functions */ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, @@ -607,7 +531,7 @@ index c8a6c0e..847d4f6 100644 { static atomic_t wiphy_counter = ATOMIC_INIT(0); -@@ -439,17 +452,31 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, +@@ -441,17 +454,31 @@ struct wiphy *wiphy_new_nm(const struct cfg80211_ops *ops, int sizeof_priv, rdev->ops = ops; @@ -646,20 +570,20 @@ index c8a6c0e..847d4f6 100644 /* give it a proper name */ if (requested_name && requested_name[0]) { diff --git a/net/wireless/nl80211.c b/net/wireless/nl80211.c -index c93a4e0..1b3c0d9 100644 +index 132df74..80b8caf 100644 --- a/net/wireless/nl80211.c +++ b/net/wireless/nl80211.c -@@ -970,6 +970,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy, - if ((chan->flags & IEEE80211_CHAN_NO_10MHZ) && - nla_put_flag(msg, NL80211_FREQUENCY_ATTR_NO_10MHZ)) +@@ -1021,6 +1021,9 @@ static int nl80211_msg_put_channel(struct sk_buff *msg, struct wiphy *wiphy, + goto nla_put_failure; + if (nla_put_flag(msg, __NL80211_FREQUENCY_ATTR_NO_IBSS)) goto nla_put_failure; + if ((chan->flags & IEEE80211_CHAN_SRD) && + nla_put_flag(msg, NL80211_FREQUENCY_ATTR_SRD_CHANNEL)) + goto nla_put_failure; } - - if (nla_put_u32(msg, NL80211_FREQUENCY_ATTR_MAX_TX_POWER, -@@ -3253,6 +3256,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag + if (chan->flags & IEEE80211_CHAN_RADAR) { + if (nla_put_flag(msg, NL80211_FREQUENCY_ATTR_RADAR)) +@@ -3503,6 +3506,16 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag goto nla_put_failure; } @@ -677,7 +601,7 @@ index c93a4e0..1b3c0d9 100644 switch (wdev->iftype) { case NL80211_IFTYPE_AP: diff --git a/net/wireless/reg.c b/net/wireless/reg.c -index a2908b8..ed16782 100644 +index b6caa2b..fbe581a 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c @@ -68,6 +68,7 @@ @@ -688,7 +612,7 @@ index a2908b8..ed16782 100644 /** * enum reg_request_treatment - regulatory request treatment -@@ -1778,11 +1779,21 @@ static void handle_channel(struct wiphy *wiphy, +@@ -1788,11 +1789,21 @@ static void handle_channel_single_rule(struct wiphy *wiphy, MBI_TO_DBI(power_rule->max_antenna_gain)); chan->max_reg_power = (int) MBM_TO_DBM(power_rule->max_eirp); @@ -714,7 +638,7 @@ index a2908b8..ed16782 100644 } if (chan->orig_mpwr) { -@@ -2314,6 +2325,10 @@ static void handle_channel_custom(struct wiphy *wiphy, +@@ -2522,6 +2533,10 @@ static void handle_channel_custom(struct wiphy *wiphy, } chan->max_power = chan->max_reg_power; diff --git a/recipes-kernel/mac80211/mac80211_5.4.27-1.bb b/recipes-kernel/mac80211/mac80211_5.10.16-1.bb similarity index 88% rename from recipes-kernel/mac80211/mac80211_5.4.27-1.bb rename to recipes-kernel/mac80211/mac80211_5.10.16-1.bb index c91894a..0cc0581 100644 --- a/recipes-kernel/mac80211/mac80211_5.4.27-1.bb +++ b/recipes-kernel/mac80211/mac80211_5.10.16-1.bb @@ -5,7 +5,7 @@ DESCRIPTION = "Linux Backports" HOMEPAGE = "https://backports.wiki.kernel.org" SECTION = "kernel/modules" LICENSE = "GPLv2" -LIC_FILES_CHKSUM = "file://COPYING;md5=bbea815ee2795b2f4230826c0c6b8814" +LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46" inherit module cml1 @@ -14,17 +14,18 @@ include nrsw-modules.${NM_TARGET}.inc SHRT_VER = "${@d.getVar('PV', True).split('-')[0]}" SRC_URI = "http://www.kernel.org/pub/linux/kernel/projects/backports/stable/v${SHRT_VER}/backports-${PV}.tar.gz \ + file://config.${NM_TARGET} \ file://0001-backport-of-build-patches-from-openwrt.patch \ file://0002-backport-of-subsys-patches-from-openwrt.patch \ file://0003-backport-of-ath-patches-from-openwrt.patch \ file://0004-backport-of-rt2x00-patches-from-openwrt.patch \ file://0005-backport-of-mwl-patches-from-openwrt.patch \ file://0006-backport-of-brcm-patches-from-openwrt.patch \ - file://0007-backport-of-netmodule-patches-from-openwrt.patch \ - file://config.${NM_TARGET} \ + file://0007-backport-of-rtl-patches-from-openwrt.patch \ + file://0008-netmodule-patches.patch \ " -SRC_URI[sha256sum] = "2b060db29386c6f3fb178df33e0b8256703b7e90f7e3799e8b5a26330ca6fc1e" +SRC_URI[sha256sum] = "90005f3598b4b1fac4b0088f0b345ef2e8312df9f9f80c50aeb28497453888f5" S = "${WORKDIR}/backports-${PV}"