From 5ccdbcd797336249c959fb6f2eba0b4d657b8ef2 Mon Sep 17 00:00:00 2001
From: Josef Schlehofer <josef.schlehofer@nic.cz>
Date: Fri, 14 Oct 2022 04:28:09 +0200
Subject: [PATCH] patches/openwrt: mac80211: update to version 5.15.58-1

---
 .../0005-Backport-mac80211.patch              | 11176 ++++++++++++----
 1 file changed, 8939 insertions(+), 2237 deletions(-)

diff --git a/patches/openwrt/5.15-kernel-configuration/0005-Backport-mac80211.patch b/patches/openwrt/5.15-kernel-configuration/0005-Backport-mac80211.patch
index ee86989a2..51d163429 100644
--- a/patches/openwrt/5.15-kernel-configuration/0005-Backport-mac80211.patch
+++ b/patches/openwrt/5.15-kernel-configuration/0005-Backport-mac80211.patch
@@ -1,22 +1,30 @@
-From 7f2c657dedb9000a984a1ecd2b30882e7a9b66bb Mon Sep 17 00:00:00 2001
+From f086537264caf27208312949dbc9ce656ecb4217 Mon Sep 17 00:00:00 2001
 From: Josef Schlehofer <pepe.schlehofer@gmail.com>
-Date: Mon, 23 May 2022 09:15:41 +0200
-Subject: [PATCH 5/8] Backport mac80211
+Date: Fri, 14 Oct 2022 04:25:14 +0200
+Subject: [PATCH] Backport mac80211
 
 ---
- package/kernel/mac80211/Makefile              |   36 +-
- package/kernel/mac80211/ath.mk                |    4 +-
- package/kernel/mac80211/broadcom.mk           |    4 +-
+ package/kernel/mac80211/Makefile              |   43 +-
+ package/kernel/mac80211/ath.mk                |    7 +-
+ package/kernel/mac80211/broadcom.mk           |    5 +-
  .../mac80211/files/lib/netifd/mac80211.sh     |   36 -
- .../files/lib/netifd/wireless/mac80211.sh     |    3 +-
+ .../files/lib/netifd/wireless/mac80211.sh     |   33 +-
  .../mac80211/files/lib/wifi/mac80211.sh       |    5 +-
+ package/kernel/mac80211/intel.mk              |    3 +-
+ package/kernel/mac80211/marvell.mk            |    3 +
  .../patches/ath/120-owl-loader-compat.patch   |   53 -
  .../patches/ath/402-ath_regd_optional.patch   |    8 +-
  .../patches/ath/404-regd_no_assoc_hints.patch |    4 +-
  .../ath/406-ath_relax_default_regd.patch      |    2 +-
  .../ath/550-ath9k-disable-bands-via-dt.patch  |   15 -
+ .../ath/580-ath9k_ar9561_fix_bias_level.patch |   47 -
  ...h10k-increase-rx-buffer-size-to-2048.patch |   37 -
- .../080-ath10k_thermal_config.patch           |    0
+ .../080-ath10k_thermal_config.patch           |    2 +-
+ ...1-ath10k-improve-tx-status-reporting.patch |   69 +
+ ...-ath10k-turn-rawmode-into-frame-mode.patch |   74 +
+ ...-do-not-interpret-Eth-frames-as-WiFi.patch |  163 ++
+ ...add-encapsulation-offloading-support.patch |  194 +++
+ ...us-and-device-specific-API-1-BDF-sel.patch |   65 +
  ...calibration-data-via-nvmem-subsystem.patch |  162 ++
  ...21-ath10k_init_devices_synchronously.patch |    2 +-
  .../930-ath10k_add_tpt_led_trigger.patch      |    4 +-
@@ -59,36 +67,53 @@ Subject: [PATCH 5/8] Backport mac80211
  .../551-ath9k_ubnt_uap_plus_hsr.patch         |    2 +-
  .../552-ath9k-ahb_of.patch}                   |   18 +-
  .../553-ath9k_of_gpio_mask.patch              |    4 +-
- .../580-ath9k_ar9561_fix_bias_level.patch     |    0
  ...calibration-data-via-nvmem-subsystem.patch |  154 ++
  ...-fetch-pci-init-values-through-nvmem.patch |  181 +++
+ ...etting-wlan-MAC-address-using-device.patch |  103 ++
  .../brcm/812-b43-add-antenna-control.patch    |    8 +-
  ...-register-wiphy-s-during-module_init.patch |   18 +-
  ...62-brcmfmac-Disable-power-management.patch |    2 +-
  ...-in-driver-tables-with-country-codes.patch |   12 +-
+ ...d-alternative-firmware-names-from-DT.patch |  196 +++
  .../mac80211/patches/brcm/998-survey.patch    |   12 +-
  .../build/003-remove_bogus_modparams.patch    |    2 +-
  .../build/004-kconfig_backport_fix.patch      |   28 -
  .../patches/build/010-disable_rfkill.patch    |   15 -
  .../patches/build/060-no_local_ssb_bcma.patch |   18 +-
+ .../build/070-remove-broken-wext-select.patch |   10 +
  ...700-mwl8k-missing-pci-id-for-WNR854T.patch |    2 +-
+ ...crease-the-global-limit-up-to-4-SSID.patch |   41 +
  ...940-mwl8k_init_devices_synchronously.patch |    4 +-
- ...define-RF5592-in-init_eeprom-routine.patch |    2 +-
- .../602-rt2x00-introduce-rt2x00eeprom.patch   |   10 +-
+ ...ringified-name-of-command-in-error-l.patch |  189 +++
+ ...define-RF5592-in-init_eeprom-routine.patch |   52 +
+ ...02-rt2x00-add-throughput-LED-trigger.patch |   76 +
+ ...define-RF5592-in-init_eeprom-routine.patch |   51 -
+ ...d-support-for-external-PA-on-MT7620.patch} |   72 +-
+ ...ove-up-and-reuse-busy-wait-functions.patch |  178 +++
+ ...RF-self-TXDC-calibration-for-MT7620.patch} |   61 +-
+ ...rt2x00-add-r-calibration-for-MT7620.patch} |   93 +-
+ ...0-add-RXDCOC-calibration-for-MT7620.patch} |   62 +-
+ ...x00-add-RXIQ-calibration-for-MT7620.patch} |  285 ++--
+ ...-run-Rt5592-IQ-calibration-on-MT7620.patch |   52 +
+ ...-add-TX-LOFT-calibration-for-MT7620.patch} |  277 ++--
+ ...x00-move-helper-functions-up-in-file.patch |   94 ++
+ ...HT20-HT40-bandwidth-switch-on-MT7620.patch |   56 +
+ ...t-TX_SW_CFG1-MAC-register-for-MT7620.patch |   52 +
+ ...t-VGC-gain-for-both-chains-of-MT7620.patch |   50 +
+ ...5-rt2x00-set-SoC-wmac-clock-register.patch |   70 +
+ ...ectly-set-BBP-register-86-for-MT7620.patch |   79 +
+ .../602-rt2x00-introduce-rt2x00eeprom.patch   |   16 +-
+ .../603-rt2x00-of_load_eeprom_filename.patch  |    6 +-
  ...isabling_bands_through_platform_data.patch |    4 +-
  ...07-rt2x00-add_platform_data_mac_addr.patch |   11 +-
  ...00-allow_disabling_bands_through_dts.patch |    2 +-
  ...0-rt2x00-change-led-polarity-from-OF.patch |    2 +-
  .../611-rt2x00-add-AP+STA-support.patch       |    2 +-
- .../612-rt2x00-led-tpt-trigger-support.patch  |    4 +-
- ...dd-support-for-external-PA-on-MT7620.patch |    6 +-
- ...-rt2x00-add-rf-self-txdc-calibration.patch |    4 +-
- .../rt2x00/983-rt2x00-add-r-calibration.patch |    4 +-
- .../984-rt2x00-add-rxdcoc-calibration.patch   |    4 +-
- .../985-rt2x00-add-rxiq-calibration.patch     |    4 +-
- .../986-rt2x00-add-TX-LOFT-calibration.patch  |    4 +-
- ...-differentiate-based-on-SoC-CHIP_VER.patch |   16 +-
+ .../612-rt2x00-led-tpt-trigger-support.patch  |   44 -
  ...ave-survey-for-every-channel-visited.patch |  183 ---
+ ...t-support-for-external-LNA-on-MT7620.patch |  161 ++
+ ...uce-accessors-for-CHIP_VER-register.patch} |    0
+ ...differentiate-based-on-SoC-CHIP_VER.patch} |   28 +-
  ...ent-set_tim-by-update-beacon-content.patch |  118 --
  .../patches/subsys/010-sync-nl80211_h.patch   |  297 ----
  .../100-remove-cryptoapi-dependencies.patch   |  699 ---------
@@ -108,9 +133,9 @@ Subject: [PATCH 5/8] Backport mac80211
  ...211_hwsim-make-6-GHz-channels-usable.patch |   74 +
  ...d-support-for-.ndo_fill_forward_path.patch |  178 +++
  ...minstrel_ht-fix-MINSTREL_FRAC-macro.patch} |    0
- ..._ht-reduce-fluctuations-in-rate-pro.patch} |    0
+ ..._ht-reduce-fluctuations-in-rate-pro.patch} |    2 +-
  ...-free-packets-from-a-flow-on-overmem.patch |   95 --
- ..._ht-rework-rate-downgrade-code-and-.patch} |   10 +-
+ ..._ht-rework-rate-downgrade-code-and-.patch} |   16 +-
  ...-get_default_func-move-default-flow-.patch |  144 --
  ...211-split-beacon-retrieval-functions.patch |  262 ++++
  ...ot-maintain-a-backlog-sorted-list-of.patch |  317 ----
@@ -128,23 +153,42 @@ Subject: [PATCH 5/8] Backport mac80211
  ...11-MBSSID-beacon-handling-in-AP-mode.patch |  326 ++++
  .../325-mac80211-MBSSID-channel-switch.patch  |   52 +
  ...bssid_indicator-in-ieee80211_assign_.patch |   25 +
- ...l_ht-fix-where-rate-stats-are-stored.patch |   61 +
+ ...wake-queues-on-a-vif-that-is-being-s.patch |   38 +
+ ...airtime-fairness-back-to-deficit-rou.patch | 1249 ++++++++++++++++
+ ...a-airtime-deficit-field-s32-instead-.patch |   52 +
+ ...r-aql_tx_pending-when-checking-airti.patch |   48 +
+ ...cently-active-tx-queues-in-schedulin.patch |  118 ++
+ ...er-PHY-AQL-limit-to-improve-fairness.patch |  131 ++
+ ...ugfs-file-to-display-per-phy-AQL-pen.patch |   58 +
+ ...cumulate-airtime-deficit-for-active-.patch |   36 +
+ ...crease-quantum-for-airtime-scheduler.patch |   53 +
  ...c80211-minstrel_ht-clean-up-CCK-code.patch |  166 ---
  ...l_ht-add-support-for-OFDM-rates-on-n.patch |  762 ----------
+ ...-multicast-packets-from-AQL-pending-.patch |   30 +
  ...-remove-legacy-minstrel-rate-control.patch | 1328 -----------------
  ...l_ht-remove-old-ewma-based-rate-aver.patch |   96 --
+ ...-not-abuse-fq.lock-in-ieee80211_do_s.patch |   46 +
+ ...dlock-Don-t-start-TX-while-holding-f.patch |   40 +
  ...l_ht-improve-ampdu-length-estimation.patch |   67 -
+ ...vif-queues-are-operational-after-sta.patch |   47 +
  ...rel_ht-improve-sample-rate-selection.patch |   31 -
  ...l_ht-fix-max-probability-rate-select.patch |  124 --
+ ...x-decap-offload-for-stations-on-AP_V.patch |   37 +
  ...el_ht-increase-stats-update-interval.patch |   20 -
+ ...x-ieee80211_data_to_8023_exthdr-hand.patch |   99 ++
  ...l_ht-fix-rounding-error-in-throughpu.patch |   34 -
+ ...-not-drop-packets-smaller-than-the-L.patch |   25 +
  ...l_ht-use-bitfields-to-encode-rate-in.patch |  412 -----
  ...l_ht-update-total-packets-counter-in.patch |   54 -
  ...l_ht-reduce-the-need-to-sample-slowe.patch |  102 --
  ...l_ht-significantly-redesign-the-rate.patch |  767 ----------
+ .../subsys/350-bss-color-collision.patch      |  118 ++
  ...el_ht-show-sampling-rates-in-debugfs.patch |   58 -
  ...l_ht-remove-sample-rate-switching-co.patch |  279 ----
  ...l_ht-fix-regression-in-the-max_prob_.patch |   23 -
+ ...emory-leak-where-sta_info-is-not-fre.patch |   77 +
+ ...n-t-finalize-CSA-in-IBSS-mode-if-sta.patch |   47 +
+ ...ac80211-Fix-UAF-in-ieee80211_scan_rx.patch |   55 +
  ...pply-flow-control-on-management-fram.patch |   60 -
  ...set-sk_pacing_shift-for-802.3-txpath.patch |   21 -
  ...-Rx-timestamp-calculation-for-all-pr.patch |  134 --
@@ -167,16 +211,26 @@ Subject: [PATCH 5/8] Backport mac80211
  ...pelling-of-A-MSDU-in-HE-capabilities.patch |  113 --
  ...E-capabilities-A-MPDU-Length-Exponen.patch |  148 --
  ...ate-control-for-retransmitted-frames.patch |   35 -
+ ...x-crash-in-beacon-protection-for-P2P.patch |   52 -
+ .../patches/subsys/397-disable-mbssid.patch   |   44 -
  .../patches/subsys/400-allow-ibss-mixed.patch |    2 +-
  .../500-mac80211_configure_antenna_gain.patch |   66 +-
  ...the-dst-buffer-to-of_get_mac_address.patch |   29 +
+ .../patches/subsys/783-sync-nl80211.patch     |   22 +
+ ...-mask-nested-A-MSDU-support-for-mesh.patch |   33 +
  package/kernel/mac80211/realtek.mk            |   18 +
- 167 files changed, 4074 insertions(+), 12997 deletions(-)
+ 215 files changed, 9043 insertions(+), 13587 deletions(-)
  delete mode 100644 package/kernel/mac80211/files/lib/netifd/mac80211.sh
  delete mode 100644 package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch
  delete mode 100644 package/kernel/mac80211/patches/ath/550-ath9k-disable-bands-via-dt.patch
+ delete mode 100644 package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch
  delete mode 100644 package/kernel/mac80211/patches/ath/922-ath10k-increase-rx-buffer-size-to-2048.patch
- rename package/kernel/mac80211/patches/{ath => ath10k}/080-ath10k_thermal_config.patch (100%)
+ rename package/kernel/mac80211/patches/{ath => ath10k}/080-ath10k_thermal_config.patch (97%)
+ create mode 100644 package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch
+ create mode 100644 package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch
+ create mode 100644 package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch
+ create mode 100644 package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch
+ create mode 100644 package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch
  create mode 100644 package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch
  rename package/kernel/mac80211/patches/{ath => ath10k}/921-ath10k_init_devices_synchronously.patch (94%)
  rename package/kernel/mac80211/patches/{ath => ath10k}/930-ath10k_add_tpt_led_trigger.patch (89%)
@@ -219,12 +273,37 @@ Subject: [PATCH 5/8] Backport mac80211
  rename package/kernel/mac80211/patches/{ath => ath9k}/551-ath9k_ubnt_uap_plus_hsr.patch (99%)
  rename package/kernel/mac80211/patches/{ath/552-ahb_of.patch => ath9k/552-ath9k-ahb_of.patch} (93%)
  rename package/kernel/mac80211/patches/{ath => ath9k}/553-ath9k_of_gpio_mask.patch (80%)
- rename package/kernel/mac80211/patches/{ath => ath9k}/580-ath9k_ar9561_fix_bias_level.patch (100%)
  create mode 100644 package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch
  create mode 100644 package/kernel/mac80211/patches/ath9k/601-v5.16-ath9k-owl-loader-fetch-pci-init-values-through-nvmem.patch
+ create mode 100644 package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch
+ create mode 100644 package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch
  delete mode 100644 package/kernel/mac80211/patches/build/004-kconfig_backport_fix.patch
  delete mode 100644 package/kernel/mac80211/patches/build/010-disable_rfkill.patch
+ create mode 100644 package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch
+ create mode 100644 package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch
+ create mode 100644 package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/001-rt2x00-define-RF5592-in-init_eeprom-routine.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/002-rt2x00-add-throughput-LED-trigger.patch
+ delete mode 100644 package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
+ rename package/kernel/mac80211/patches/rt2x00/{650-rt2x00-add-support-for-external-PA-on-MT7620.patch => 003-rt2x00-add-support-for-external-PA-on-MT7620.patch} (58%)
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/004-rt2x00-move-up-and-reuse-busy-wait-functions.patch
+ rename package/kernel/mac80211/patches/rt2x00/{982-rt2x00-add-rf-self-txdc-calibration.patch => 005-rt2x00-add-RF-self-TXDC-calibration-for-MT7620.patch} (51%)
+ rename package/kernel/mac80211/patches/rt2x00/{983-rt2x00-add-r-calibration.patch => 006-rt2x00-add-r-calibration-for-MT7620.patch} (66%)
+ rename package/kernel/mac80211/patches/rt2x00/{984-rt2x00-add-rxdcoc-calibration.patch => 007-rt2x00-add-RXDCOC-calibration-for-MT7620.patch} (50%)
+ rename package/kernel/mac80211/patches/rt2x00/{985-rt2x00-add-rxiq-calibration.patch => 008-rt2x00-add-RXIQ-calibration-for-MT7620.patch} (63%)
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/009-rt2x00-don-t-run-Rt5592-IQ-calibration-on-MT7620.patch
+ rename package/kernel/mac80211/patches/rt2x00/{986-rt2x00-add-TX-LOFT-calibration.patch => 010-rt2x00-add-TX-LOFT-calibration-for-MT7620.patch} (84%)
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/011-rt2x00-move-helper-functions-up-in-file.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/012-rt2x00-fix-HT20-HT40-bandwidth-switch-on-MT7620.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/013-rt2x00-set-correct-TX_SW_CFG1-MAC-register-for-MT7620.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/014-rt2x00-set-VGC-gain-for-both-chains-of-MT7620.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/015-rt2x00-set-SoC-wmac-clock-register.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/016-rt2x00-correctly-set-BBP-register-86-for-MT7620.patch
+ delete mode 100644 package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
  delete mode 100644 package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
+ create mode 100644 package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch
+ rename package/kernel/mac80211/patches/rt2x00/{990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch => 995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch} (100%)
+ rename package/kernel/mac80211/patches/rt2x00/{991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch => 996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch} (95%)
  delete mode 100644 package/kernel/mac80211/patches/rtl/002-v5.13-rtlwifi-implement-set_tim-by-update-beacon-content.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/010-sync-nl80211_h.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/100-remove-cryptoapi-dependencies.patch
@@ -240,9 +319,9 @@ Subject: [PATCH 5/8] Backport mac80211
  create mode 100644 package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch
  create mode 100644 package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch
  rename package/kernel/mac80211/patches/subsys/{353-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch => 309-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch} (100%)
- rename package/kernel/mac80211/patches/subsys/{354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch => 310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch} (100%)
+ rename package/kernel/mac80211/patches/subsys/{354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch => 310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch} (94%)
  delete mode 100644 package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch
- rename package/kernel/mac80211/patches/subsys/{355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch => 311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch} (93%)
+ rename package/kernel/mac80211/patches/subsys/{355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch => 311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch} (90%)
  delete mode 100644 package/kernel/mac80211/patches/subsys/311-net-fq_impl-drop-get_default_func-move-default-flow-.patch
  create mode 100644 package/kernel/mac80211/patches/subsys/312-mac80211-split-beacon-retrieval-functions.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/312-net-fq_impl-do-not-maintain-a-backlog-sorted-list-of.patch
@@ -260,23 +339,42 @@ Subject: [PATCH 5/8] Backport mac80211
  create mode 100644 package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
  create mode 100644 package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch
  create mode 100644 package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch
- create mode 100644 package/kernel/mac80211/patches/subsys/329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/338-mac80211-minstrel_ht-add-support-for-OFDM-rates-on-n.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/340-mac80211-minstrel_ht-remove-old-ewma-based-rate-aver.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/343-mac80211-minstrel_ht-fix-max-probability-rate-select.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/347-mac80211-minstrel_ht-update-total-packets-counter-in.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/348-mac80211-minstrel_ht-reduce-the-need-to-sample-slowe.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/349-mac80211-minstrel_ht-significantly-redesign-the-rate.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/351-mac80211-minstrel_ht-remove-sample-rate-switching-co.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/352-mac80211-minstrel_ht-fix-regression-in-the-max_prob_.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/372-mac80211-set-sk_pacing_shift-for-802.3-txpath.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/373-mac80211-support-Rx-timestamp-calculation-for-all-pr.patch
@@ -299,10 +397,14 @@ Subject: [PATCH 5/8] Backport mac80211
  delete mode 100644 package/kernel/mac80211/patches/subsys/392-wireless-fix-spelling-of-A-MSDU-in-HE-capabilities.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/393-wireless-align-HE-capabilities-A-MPDU-Length-Exponen.patch
  delete mode 100644 package/kernel/mac80211/patches/subsys/394-mac80211-fix-rate-control-for-retransmitted-frames.patch
+ delete mode 100644 package/kernel/mac80211/patches/subsys/396-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
+ delete mode 100644 package/kernel/mac80211/patches/subsys/397-disable-mbssid.patch
  create mode 100644 package/kernel/mac80211/patches/subsys/782-net-next-1-of-net-pass-the-dst-buffer-to-of_get_mac_address.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch
+ create mode 100644 package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch
 
 diff --git a/package/kernel/mac80211/Makefile b/package/kernel/mac80211/Makefile
-index d92d4f5457..e51208aaba 100644
+index d92d4f5457..44428ca89f 100644
 --- a/package/kernel/mac80211/Makefile
 +++ b/package/kernel/mac80211/Makefile
 @@ -10,10 +10,10 @@ include $(INCLUDE_DIR)/kernel.mk
@@ -310,12 +412,13 @@ index d92d4f5457..e51208aaba 100644
  PKG_NAME:=mac80211
  
 -PKG_VERSION:=5.10.110-1
-+PKG_VERSION:=5.15.33-1
- PKG_RELEASE:=1
+-PKG_RELEASE:=1
 -PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.10.110/
 -PKG_HASH:=3d958154080c059adaf26512430fd1a8888d65a2228e5e70e48d028201e148b1
-+PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.33/
-+PKG_HASH:=1b6b3bded4c81814ebebe2d194c2f8966d2399005b85ebb0557285b6e73f5422
++PKG_VERSION:=5.15.58-1
++PKG_RELEASE:=2
++PKG_SOURCE_URL:=@KERNEL/linux/kernel/projects/backports/stable/v5.15.58/
++PKG_HASH:=a3c2a2b7bbaf8943c65fd72f4e7d7ad5e205aeae28b26c835f9d8afa0f9810bf
  
  PKG_SOURCE:=backports-$(PKG_VERSION).tar.xz
  PKG_BUILD_DIR:=$(KERNEL_BUILD_DIR)/backports-$(PKG_VERSION)
@@ -327,7 +430,15 @@ index d92d4f5457..e51208aaba 100644
  	hermes hermes-pci hermes-pcmcia hermes-plx\
  	lib80211 \
  	mac80211-hwsim \
-@@ -98,7 +97,7 @@ PKG_CONFIG_DEPENDS += \
+@@ -57,7 +56,6 @@ config_package=$(if $(CONFIG_PACKAGE_kmod-$(1)),m)
+ 
+ config-y:= \
+ 	WLAN \
+-	CFG80211_WEXT \
+ 	CFG80211_CERTIFICATION_ONUS \
+ 	MAC80211_RC_MINSTREL \
+ 	MAC80211_RC_MINSTREL_HT \
+@@ -98,7 +96,7 @@ PKG_CONFIG_DEPENDS += \
  define KernelPackage/cfg80211
    $(call KernelPackage/mac80211/Default)
    TITLE:=cfg80211 - wireless configuration API
@@ -336,7 +447,7 @@ index d92d4f5457..e51208aaba 100644
    ABI_VERSION:=$(PKG_VERSION)-$(PKG_RELEASE)
    FILES:= \
  	$(PKG_BUILD_DIR)/compat/compat.ko \
-@@ -127,7 +126,7 @@ define KernelPackage/mac80211
+@@ -127,7 +125,7 @@ define KernelPackage/mac80211
    $(call KernelPackage/mac80211/Default)
    TITLE:=Linux 802.11 Wireless Networking Stack
    # +kmod-crypto-cmac is a runtime only dependency of net/mac80211/aes_cmac.c
@@ -345,7 +456,7 @@ index d92d4f5457..e51208aaba 100644
    KCONFIG:=\
  	CONFIG_AVERAGE=y
    FILES:= $(PKG_BUILD_DIR)/net/mac80211/mac80211.ko
-@@ -174,18 +173,6 @@ define KernelPackage/adm8211
+@@ -174,22 +172,11 @@ define KernelPackage/adm8211
    AUTOLOAD:=$(call AutoProbe,adm8211)
  endef
  
@@ -364,7 +475,29 @@ index d92d4f5457..e51208aaba 100644
  define KernelPackage/hermes
    $(call KernelPackage/mac80211/Default)
    TITLE:=Hermes 802.11b chipset support
-@@ -406,8 +393,6 @@ endif
+   DEPENDS:=@PCI_SUPPORT||PCMCIA_SUPPORT +kmod-cfg80211 +@DRIVER_WEXT_SUPPORT +kmod-crypto-michael-mic
++  DEFAULT:=n
+   FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intersil/orinoco/orinoco.ko
+   AUTOLOAD:=$(call AutoProbe,orinoco)
+ endef
+@@ -239,6 +226,7 @@ define KernelPackage/lib80211
+   $(call KernelPackage/mac80211/Default)
+   TITLE:=802.11 Networking stack
+   DEPENDS:=+kmod-cfg80211 +kmod-crypto-hash +kmod-crypto-ccm
++  HIDDEN:=1
+   FILES:= \
+ 	$(PKG_BUILD_DIR)/net/wireless/lib80211.ko \
+ 	$(PKG_BUILD_DIR)/net/wireless/lib80211_crypt_wep.ko \
+@@ -265,7 +253,7 @@ endef
+ define KernelPackage/mac80211-hwsim
+   $(call KernelPackage/mac80211/Default)
+   TITLE:=mac80211 HW simulation device
+-  DEPENDS+= +kmod-mac80211 +@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT
++  DEPENDS+= +kmod-mac80211 +@DRIVER_11AX_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11N_SUPPORT
+   FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/mac80211_hwsim.ko
+   AUTOLOAD:=$(call AutoProbe,mac80211_hwsim)
+ endef
+@@ -406,8 +394,6 @@ endif
  
  config-$(call config_package,lib80211) += LIB80211 LIB80211_CRYPT_WEP LIB80211_CRYPT_CCMP LIB80211_CRYPT_TKIP
  
@@ -373,7 +506,7 @@ index d92d4f5457..e51208aaba 100644
  config-$(call config_package,mac80211-hwsim) += MAC80211_HWSIM
  config-$(call config_package,mt7601u) += MT7601U
  config-y += WL_MEDIATEK
-@@ -507,9 +492,14 @@ define Build/Patch
+@@ -507,9 +493,14 @@ define Build/Patch
  	$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/build,build/)
  	$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/subsys,subsys/)
  	$(call PatchDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/ath,ath/)
@@ -388,7 +521,7 @@ index d92d4f5457..e51208aaba 100644
  	$(if $(QUILT),touch $(PKG_BUILD_DIR)/.quilt_used)
  endef
  
-@@ -517,9 +507,14 @@ define Quilt/Refresh/Package
+@@ -517,9 +508,14 @@ define Quilt/Refresh/Package
  	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/build,build/)
  	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/subsys,subsys/)
  	$(call Quilt/RefreshDir,$(PKG_BUILD_DIR),$(PATCH_DIR)/ath,ath/)
@@ -403,7 +536,7 @@ index d92d4f5457..e51208aaba 100644
  endef
  
  define Build/Compile
-@@ -545,7 +540,6 @@ endef
+@@ -545,7 +541,6 @@ endef
  define KernelPackage/cfg80211/install
  	$(INSTALL_DIR) $(1)/lib/wifi $(1)/lib/netifd/wireless
  	$(INSTALL_DATA) ./files/lib/wifi/mac80211.sh $(1)/lib/wifi
@@ -412,7 +545,7 @@ index d92d4f5457..e51208aaba 100644
  	$(INSTALL_DIR) $(1)/etc/hotplug.d/ieee80211
  	$(INSTALL_DATA) ./files/mac80211.hotplug $(1)/etc/hotplug.d/ieee80211/10-wifi-detect
 diff --git a/package/kernel/mac80211/ath.mk b/package/kernel/mac80211/ath.mk
-index e815f37e1c..50b1eed9c8 100644
+index e815f37e1c..9af8c4665d 100644
 --- a/package/kernel/mac80211/ath.mk
 +++ b/package/kernel/mac80211/ath.mk
 @@ -34,7 +34,7 @@ ifdef CONFIG_PACKAGE_MAC80211_TRACING
@@ -433,8 +566,18 @@ index e815f37e1c..50b1eed9c8 100644
  config-$(CONFIG_ATH9K_HWRNG) += ATH9K_HWRNG
  config-$(CONFIG_ATH9K_SUPPORT_PCOEM) += ATH9K_PCOEM
  config-$(CONFIG_ATH9K_TX99) += ATH9K_TX99
+@@ -260,7 +260,8 @@ define KernelPackage/ath10k
+   FILES:= \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath10k/ath10k_core.ko \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/ath/ath10k/ath10k_pci.ko
+-  AUTOLOAD:=$(call AutoProbe,ath10k_pci)
++  AUTOLOAD:=$(call AutoProbe,ath10k_core ath10k_pci)
++  MODPARAMS.ath10k_core:=frame_mode=2
+   VARIANT:=regular
+ endef
+ 
 diff --git a/package/kernel/mac80211/broadcom.mk b/package/kernel/mac80211/broadcom.mk
-index fb576c5809..473bbf597c 100644
+index fb576c5809..5548f6e661 100644
 --- a/package/kernel/mac80211/broadcom.mk
 +++ b/package/kernel/mac80211/broadcom.mk
 @@ -209,7 +209,7 @@ config PACKAGE_B43_USE_BCMA
@@ -455,6 +598,14 @@ index fb576c5809..473bbf597c 100644
  		    A  => A-PHY
  		    AG => Dual A-PHY G-PHY
  		    G  => G-PHY
+@@ -450,6 +450,7 @@ define KernelPackage/brcmfmac/config
+ 	config BRCMFMAC_SDIO
+ 		bool "Enable SDIO bus interface support"
+ 		default y if TARGET_bcm27xx
++		default y if TARGET_imx_cortexa7
+ 		default y if TARGET_sunxi
+ 		default n
+ 		help
 diff --git a/package/kernel/mac80211/files/lib/netifd/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/mac80211.sh
 deleted file mode 100644
 index 92e5c0e395..0000000000
@@ -498,18 +649,84 @@ index 92e5c0e395..0000000000
 -	done
 -}
 diff --git a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
-index d69667bf8c..27eecf3a7f 100644
+index d69667bf8c..f462fc8ad9 100644
 --- a/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
 +++ b/package/kernel/mac80211/files/lib/netifd/wireless/mac80211.sh
-@@ -1,7 +1,6 @@
+@@ -1,7 +1,7 @@
  #!/bin/sh
  . /lib/netifd/netifd-wireless.sh
  . /lib/netifd/hostapd.sh
 -. /lib/netifd/mac80211.sh
++. /lib/functions/system.sh
  
  init_wireless_driver "$@"
  
-@@ -563,7 +562,7 @@ mac80211_generate_mac() {
+@@ -29,8 +29,8 @@ drv_mac80211_init_device_config() {
+ 	config_add_string tx_burst
+ 	config_add_string distance
+ 	config_add_int beacon_int chanbw frag rts
+-	config_add_int rxantenna txantenna antenna_gain txpower
+-	config_add_boolean noscan ht_coex acs_exclude_dfs
++	config_add_int rxantenna txantenna antenna_gain txpower min_tx_power
++	config_add_boolean noscan ht_coex acs_exclude_dfs background_radar
+ 	config_add_array ht_capab
+ 	config_add_array channels
+ 	config_add_array scan_list
+@@ -138,13 +138,15 @@ mac80211_hostapd_setup_base() {
+ 	[ -n "$acs_exclude_dfs" ] && [ "$acs_exclude_dfs" -gt 0 ] &&
+ 		append base_cfg "acs_exclude_dfs=1" "$N"
+ 
+-	json_get_vars noscan ht_coex
+-	json_get_values ht_capab_list ht_capab tx_burst
++	json_get_vars noscan ht_coex min_tx_power:0 tx_burst
++	json_get_values ht_capab_list ht_capab
+ 	json_get_values channel_list channels
+ 
+ 	[ "$auto_channel" = 0 ] && [ -z "$channel_list" ] && \
+ 		channel_list="$channel"
+ 
++	[ "$min_tx_power" -gt 0 ] && append base_cfg "min_tx_power=$min_tx_power"
++
+ 	set_default noscan 0
+ 
+ 	[ "$noscan" -gt 0 ] && hostapd_noscan=1
+@@ -274,6 +276,11 @@ mac80211_hostapd_setup_base() {
+ 			vht_center_seg0=$idx
+ 		;;
+ 	esac
++	[ "$band" = "5g" ] && {
++		json_get_vars background_radar:0
++
++		[ "$background_radar" -eq 1 ] && append base_cfg "enable_background_radar=1" "$N"
++	}
+ 	[ "$band" = "6g" ] && {
+ 		op_class=
+ 		case "$htmode" in
+@@ -414,18 +421,20 @@ mac80211_hostapd_setup_base() {
+ 			he_spr_non_srg_obss_pd_max_offset:1 \
+ 			he_bss_color
+ 
+-		he_phy_cap=$(iw phy "$phy" info | awk -F "[()]" '/HE PHY Capabilities/ { print $2 }' | head -1)
++		he_phy_cap=$(iw phy "$phy" info | sed -n '/HE Iftypes: AP/,$p' | awk -F "[()]" '/HE PHY Capabilities/ { print $2 }' | head -1)
+ 		he_phy_cap=${he_phy_cap:2}
+-		he_mac_cap=$(iw phy "$phy" info | awk -F "[()]" '/HE MAC Capabilities/ { print $2 }' | head -1)
++		he_mac_cap=$(iw phy "$phy" info | sed -n '/HE Iftypes: AP/,$p' | awk -F "[()]" '/HE MAC Capabilities/ { print $2 }' | head -1)
+ 		he_mac_cap=${he_mac_cap:2}
+ 
+ 		append base_cfg "ieee80211ax=1" "$N"
+-		[ -n "$he_bss_color" ] && append base_cfg "he_bss_color=$he_bss_color" "$N"
+ 		[ "$hwmode" = "a" ] && {
+ 			append base_cfg "he_oper_chwidth=$vht_oper_chwidth" "$N"
+ 			append base_cfg "he_oper_centr_freq_seg0_idx=$vht_center_seg0" "$N"
+ 		}
+ 
++		set_default he_bss_color 128
++		append base_cfg "he_bss_color=$he_bss_color" "$N"
++
+ 		mac80211_add_he_capabilities \
+ 			he_su_beamformer:${he_phy_cap:6:2}:0x80:$he_su_beamformer \
+ 			he_su_beamformee:${he_phy_cap:8:2}:0x1:$he_su_beamformee \
+@@ -563,7 +572,7 @@ mac80211_generate_mac() {
  find_phy() {
  	[ -n "$phy" -a -d /sys/class/ieee80211/$phy ] && return 0
  	[ -n "$path" ] && {
@@ -518,6 +735,21 @@ index d69667bf8c..27eecf3a7f 100644
  		[ -n "$phy" ] && return 0
  	}
  	[ -n "$macaddr" ] && {
+@@ -659,10 +668,12 @@ mac80211_prepare_vif() {
+ 
+ 	json_select ..
+ 
+-	[ -n "$macaddr" ] || {
++	if [ -z "$macaddr" ]; then
+ 		macaddr="$(mac80211_generate_mac $phy)"
+ 		macidx="$(($macidx + 1))"
+-	}
++	elif [ "$macaddr" = 'random' ]; then
++		macaddr="$(macaddr_random)"
++	fi
+ 
+ 	json_add_object data
+ 	json_add_string ifname "$ifname"
 diff --git a/package/kernel/mac80211/files/lib/wifi/mac80211.sh b/package/kernel/mac80211/files/lib/wifi/mac80211.sh
 index 5eb7cc4c61..6aa46b0c74 100644
 --- a/package/kernel/mac80211/files/lib/wifi/mac80211.sh
@@ -546,6 +778,55 @@ index 5eb7cc4c61..6aa46b0c74 100644
  		if [ -n "$path" ]; then
  			dev_id="set wireless.radio${devidx}.path='$path'"
  		else
+diff --git a/package/kernel/mac80211/intel.mk b/package/kernel/mac80211/intel.mk
+index 8bab727a41..eca4a574be 100644
+--- a/package/kernel/mac80211/intel.mk
++++ b/package/kernel/mac80211/intel.mk
+@@ -15,7 +15,7 @@ config-$(call config_package,ipw2200) += IPW2200
+ 
+ define KernelPackage/iwlwifi
+   $(call KernelPackage/mac80211/Default)
+-  DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT
++  DEPENDS:= +kmod-mac80211 @PCI_SUPPORT +@DRIVER_11N_SUPPORT +@DRIVER_11AC_SUPPORT +@DRIVER_11AX_SUPPORT
+   TITLE:=Intel AGN Wireless support
+   FILES:= \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/intel/iwlwifi/iwlwifi.ko \
+@@ -125,6 +125,7 @@ define KernelPackage/libipw
+   $(call KernelPackage/mac80211/Default)
+   TITLE:=libipw for ipw2100 and ipw2200
+   DEPENDS:=@PCI_SUPPORT +kmod-crypto-michael-mic +kmod-crypto-ecb +kmod-lib80211 +kmod-cfg80211 +@DRIVER_WEXT_SUPPORT @!BIG_ENDIAN
++  DEFAULT:=n
+   FILES:=$(PKG_BUILD_DIR)/drivers/net/wireless/intel/ipw2x00/libipw.ko
+   AUTOLOAD:=$(call AutoProbe,libipw)
+ endef
+diff --git a/package/kernel/mac80211/marvell.mk b/package/kernel/mac80211/marvell.mk
+index a0e67091e5..254395932d 100644
+--- a/package/kernel/mac80211/marvell.mk
++++ b/package/kernel/mac80211/marvell.mk
+@@ -13,6 +13,7 @@ define KernelPackage/libertas-usb
+   $(call KernelPackage/mac80211/Default)
+   DEPENDS+= @USB_SUPPORT +kmod-cfg80211 +kmod-usb-core +kmod-lib80211 +@DRIVER_WEXT_SUPPORT +libertas-usb-firmware
+   TITLE:=Marvell 88W8015 Wireless Driver
++  DEFAULT:=n
+   FILES:= \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/usb8xxx.ko
+@@ -23,6 +24,7 @@ define KernelPackage/libertas-sdio
+   $(call KernelPackage/mac80211/Default)
+   DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +kmod-mmc +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-sdio-firmware
+   TITLE:=Marvell 88W8686 Wireless Driver
++  DEFAULT:=n
+   FILES:= \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas.ko \
+ 	$(PKG_BUILD_DIR)/drivers/net/wireless/marvell/libertas/libertas_sdio.ko
+@@ -33,6 +35,7 @@ define KernelPackage/libertas-spi
+   $(call KernelPackage/mac80211/Default)
+   SUBMENU:=Wireless Drivers
+   DEPENDS+= +kmod-cfg80211 +kmod-lib80211 +@DRIVER_WEXT_SUPPORT @!TARGET_uml +libertas-spi-firmware
++  DEFAULT:=n
+   KCONFIG := \
+ 	CONFIG_SPI=y \
+ 	CONFIG_SPI_MASTER=y
 diff --git a/package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch b/package/kernel/mac80211/patches/ath/120-owl-loader-compat.patch
 deleted file mode 100644
 index d1d6c9e2e3..0000000000
@@ -606,7 +887,7 @@ index d1d6c9e2e3..0000000000
 - 
 - 	eeprom_name = devm_kzalloc(dev, EEPROM_FILENAME_LEN, GFP_KERNEL);
 diff --git a/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch
-index bf87d3551a..514cfd9e5e 100644
+index bf87d3551a..4ea33365d1 100644
 --- a/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch
 +++ b/package/kernel/mac80211/patches/ath/402-ath_regd_optional.patch
 @@ -37,7 +37,7 @@
@@ -641,19 +922,19 @@ index bf87d3551a..514cfd9e5e 100644
  --- a/local-symbols
  +++ b/local-symbols
 -@@ -85,6 +85,7 @@ ADM8211=
-+@@ -83,6 +83,7 @@ ADM8211=
++@@ -106,6 +106,7 @@ ADM8211=
   ATH_COMMON=
   WLAN_VENDOR_ATH=
   ATH_DEBUG=
 diff --git a/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch
-index c6dc184e28..c8eef504c6 100644
+index c6dc184e28..02281adf4a 100644
 --- a/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch
 +++ b/package/kernel/mac80211/patches/ath/404-regd_no_assoc_hints.patch
 @@ -1,6 +1,6 @@
  --- a/net/wireless/reg.c
  +++ b/net/wireless/reg.c
 -@@ -3252,6 +3252,8 @@ void regulatory_hint_country_ie(struct w
-+@@ -3304,6 +3304,8 @@ void regulatory_hint_country_ie(struct w
++@@ -3309,6 +3309,8 @@ void regulatory_hint_country_ie(struct w
   	enum environment_cap env = ENVIRON_ANY;
   	struct regulatory_request *request = NULL, *lr;
   
@@ -662,7 +943,7 @@ index c6dc184e28..c8eef504c6 100644
   	if (country_ie_len & 0x01)
   		return;
 -@@ -3503,6 +3505,7 @@ static bool is_wiphy_all_set_reg_flag(en
-+@@ -3555,6 +3557,7 @@ static bool is_wiphy_all_set_reg_flag(en
++@@ -3560,6 +3562,7 @@ static bool is_wiphy_all_set_reg_flag(en
   
   void regulatory_hint_disconnect(void)
   {
@@ -700,6 +981,59 @@ index 7d3a334c42..0000000000
 - 	if (of_property_read_bool(np, "qca,no-eeprom")) {
 - 		/* ath9k-eeprom-<bus>-<id>.bin */
 - 		scnprintf(eeprom_name, sizeof(eeprom_name),
+diff --git a/package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch b/package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch
+deleted file mode 100644
+index e4c2e1cd02..0000000000
+--- a/package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch
++++ /dev/null
+@@ -1,47 +0,0 @@
+-From 4509e523dba46f789377cfec6f20579adf743416 Mon Sep 17 00:00:00 2001
+-From: =?UTF-8?q?Thibaut=20VAR=C3=88NE?= <hacks+kernel@slashdirt.org>
+-Date: Sun, 17 Apr 2022 11:31:35 +0200
+-Subject: [PATCH v2] ath9k: fix QCA9561 PA bias level
+-MIME-Version: 1.0
+-Content-Type: text/plain; charset=UTF-8
+-Content-Transfer-Encoding: 8bit
+-
+-This patch fixes an invalid TX PA DC bias level on QCA9561, which
+-results in a very low output power and very low throughput as devices
+-are further away from the AP (compared to other 2.4GHz APs).
+-
+-This patch was suggested by Felix Fietkau, who noted[1]:
+-"The value written to that register is wrong, because while the mask
+-definition AR_CH0_TOP2_XPABIASLVL uses a different value for 9561, the
+-shift definition AR_CH0_TOP2_XPABIASLVL_S is hardcoded to 12, which is
+-wrong for 9561."
+-
+-In real life testing, without this patch the 2.4GHz throughput on
+-Yuncore XD3200 is around 10Mbps sitting next to the AP, and closer to
+-practical maximum with the patch applied.
+-
+-[1] https://lore.kernel.org/all/91c58969-c60e-2f41-00ac-737786d435ae@nbd.name
+-
+-Signed-off-by: Thibaut VARÈNE <hacks+kernel@slashdirt.org>
+----
+-v2: Adjust #define per Felix's suggestion
+----
+- drivers/net/wireless/ath/ath9k/ar9003_phy.h | 2 +-
+- 1 file changed, 1 insertion(+), 1 deletion(-)
+-
+-diff --git a/drivers/net/wireless/ath/ath9k/ar9003_phy.h b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+-index a171dbb29..ad949eb02 100644
+---- a/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+-+++ b/drivers/net/wireless/ath/ath9k/ar9003_phy.h
+-@@ -720,7 +720,7 @@
+- #define AR_CH0_TOP2		(AR_SREV_9300(ah) ? 0x1628c : \
+- 					(AR_SREV_9462(ah) ? 0x16290 : 0x16284))
+- #define AR_CH0_TOP2_XPABIASLVL		(AR_SREV_9561(ah) ? 0x1e00 : 0xf000)
+--#define AR_CH0_TOP2_XPABIASLVL_S	12
+-+#define AR_CH0_TOP2_XPABIASLVL_S	(AR_SREV_9561(ah) ? 9 : 12)
+- 
+- #define AR_CH0_XTAL		(AR_SREV_9300(ah) ? 0x16294 : \
+- 				 ((AR_SREV_9462(ah) || AR_SREV_9565(ah)) ? 0x16298 : \
+--- 
+-2.30.2
+-
 diff --git a/package/kernel/mac80211/patches/ath/922-ath10k-increase-rx-buffer-size-to-2048.patch b/package/kernel/mac80211/patches/ath/922-ath10k-increase-rx-buffer-size-to-2048.patch
 deleted file mode 100644
 index 8f7a60eec8..0000000000
@@ -744,12 +1078,619 @@ index 8f7a60eec8..0000000000
 - 
 - /* Refill a bunch of RX buffers for each refill round so that FW/HW can handle
 diff --git a/package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch b/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch
-similarity index 100%
+similarity index 97%
 rename from package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch
 rename to package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch
+index de6f9d9bb0..d9a3cd534c 100644
+--- a/package/kernel/mac80211/patches/ath/080-ath10k_thermal_config.patch
++++ b/package/kernel/mac80211/patches/ath10k/080-ath10k_thermal_config.patch
+@@ -37,7 +37,7 @@
+  void ath10k_thermal_event_temperature(struct ath10k *ar, int temperature);
+ --- a/local-symbols
+ +++ b/local-symbols
+-@@ -142,6 +142,7 @@ ATH10K_SNOC=
++@@ -165,6 +165,7 @@ ATH10K_SNOC=
+  ATH10K_DEBUG=
+  ATH10K_DEBUGFS=
+  ATH10K_SPECTRAL=
+diff --git a/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch b/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch
+new file mode 100644
+index 0000000000..c024850918
+--- /dev/null
++++ b/package/kernel/mac80211/patches/ath10k/081-01-ath10k-improve-tx-status-reporting.patch
+@@ -0,0 +1,69 @@
++From 2587d5198aa5adcbd8896aae4a2404dc13d48637 Mon Sep 17 00:00:00 2001
++From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Date: Wed, 18 May 2022 10:27:26 +0300
++Subject: ath10k: improve tx status reporting
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++We use ieee80211_tx_status() to report each completed tx frame.
++Internally, this function calls sta_info_get_by_addrs(), what has a
++couple of drawbacks:
++1. additional station lookup causes a performance degradation;
++2. mac80211 can not properly account Ethernet encapsulated frames due
++   to the inability to properly determine the destination (station) MAC
++   address since ieee80211_tx_status() assumes the frame has a 802.11
++   header.
++
++The latter is especially destructive if we want to use hardware frames
++encapsulation.
++
++To fix both of these issues, replace ieee80211_tx_status() with
++ieee80211_tx_status_ext() call and feed it station pointer from the tx
++queue associated with the transmitted frame.
++
++Tested-on: QCA9888 hw2.0 PCI 10.4-3.9.0.2-00131
++Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00157-QCARMSWPZ-1
++
++Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Tested-by: Oldřich Jedlička <oldium.pro@gmail.com> # TP-Link Archer C7 v4 & v5 (QCA9563 + QCA9880)
++Tested-by: Edward Matijevic <motolav@gmail.com> # TP-Link Archer C2600 (IPQ8064 + QCA9980 10.4.1.00030-1)
++Tested-by: Edward Matijevic <motolav@gmail.com> # QCA9377 PCI in Sta mode
++Tested-by: Zhijun You <hujy652@gmail.com> # NETGEAR R7800 (QCA9984 10.4-3.9.0.2-00159)
++Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
++Link: https://lore.kernel.org/r/20220516032519.29831-2-ryazanov.s.a@gmail.com
++---
++ drivers/net/wireless/ath/ath10k/txrx.c | 15 ++++++++++++++-
++ 1 file changed, 14 insertions(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ath/ath10k/txrx.c
+++++ b/drivers/net/wireless/ath/ath10k/txrx.c
++@@ -43,6 +43,7 @@ out:
++ int ath10k_txrx_tx_unref(struct ath10k_htt *htt,
++ 			 const struct htt_tx_done *tx_done)
++ {
+++	struct ieee80211_tx_status status;
++ 	struct ath10k *ar = htt->ar;
++ 	struct device *dev = ar->dev;
++ 	struct ieee80211_tx_info *info;
++@@ -128,7 +129,19 @@ int ath10k_txrx_tx_unref(struct ath10k_h
++ 		info->status.is_valid_ack_signal = true;
++ 	}
++ 
++-	ieee80211_tx_status(htt->ar->hw, msdu);
+++	memset(&status, 0, sizeof(status));
+++	status.skb = msdu;
+++	status.info = info;
+++
+++	rcu_read_lock();
+++
+++	if (txq)
+++		status.sta = txq->sta;
+++
+++	ieee80211_tx_status_ext(htt->ar->hw, &status);
+++
+++	rcu_read_unlock();
+++
++ 	/* we do not own the msdu anymore */
++ 
++ 	return 0;
+diff --git a/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch b/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch
+new file mode 100644
+index 0000000000..e672815522
+--- /dev/null
++++ b/package/kernel/mac80211/patches/ath10k/081-02-ath10k-turn-rawmode-into-frame-mode.patch
+@@ -0,0 +1,74 @@
++From a09740548275a74b897654b3aca5af589289b57a Mon Sep 17 00:00:00 2001
++From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Date: Mon, 16 May 2022 13:26:00 +0300
++Subject: ath10k: turn rawmode into frame_mode
++
++Turn boolean rawmode module param into integer frame_mode param that
++contains value from ath10k_hw_txrx_mode enum. As earlier the default
++param value is non-RAW (native Wi-Fi) encapsulation. The param name
++is selected to be consistent with the similar ath11k param.
++
++This is a preparation step for upcoming encapsulation offloading
++support.
++
++Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
++Link: https://lore.kernel.org/r/20220516032519.29831-4-ryazanov.s.a@gmail.com
++---
++ drivers/net/wireless/ath/ath10k/core.c | 11 +++++++----
++ drivers/net/wireless/ath/ath10k/core.h |  1 +
++ 2 files changed, 8 insertions(+), 4 deletions(-)
++
++--- a/drivers/net/wireless/ath/ath10k/core.c
+++++ b/drivers/net/wireless/ath/ath10k/core.c
++@@ -32,9 +32,11 @@ EXPORT_SYMBOL(ath10k_debug_mask);
++ static unsigned int ath10k_cryptmode_param;
++ static bool uart_print;
++ static bool skip_otp;
++-static bool rawmode;
++ static bool fw_diag_log;
++ 
+++/* frame mode values are mapped as per enum ath10k_hw_txrx_mode */
+++unsigned int ath10k_frame_mode = ATH10K_HW_TXRX_NATIVE_WIFI;
+++
++ unsigned long ath10k_coredump_mask = BIT(ATH10K_FW_CRASH_DUMP_REGISTERS) |
++ 				     BIT(ATH10K_FW_CRASH_DUMP_CE_DATA);
++ 
++@@ -43,15 +45,16 @@ module_param_named(debug_mask, ath10k_de
++ module_param_named(cryptmode, ath10k_cryptmode_param, uint, 0644);
++ module_param(uart_print, bool, 0644);
++ module_param(skip_otp, bool, 0644);
++-module_param(rawmode, bool, 0644);
++ module_param(fw_diag_log, bool, 0644);
+++module_param_named(frame_mode, ath10k_frame_mode, uint, 0644);
++ module_param_named(coredump_mask, ath10k_coredump_mask, ulong, 0444);
++ 
++ MODULE_PARM_DESC(debug_mask, "Debugging mask");
++ MODULE_PARM_DESC(uart_print, "Uart target debugging");
++ MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
++ MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
++-MODULE_PARM_DESC(rawmode, "Use raw 802.11 frame datapath");
+++MODULE_PARM_DESC(frame_mode,
+++		 "Datapath frame mode (0: raw, 1: native wifi (default))");
++ MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
++ MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");
++ 
++@@ -2487,7 +2490,7 @@ static int ath10k_core_init_firmware_fea
++ 	ar->htt.max_num_amsdu = ATH10K_HTT_MAX_NUM_AMSDU_DEFAULT;
++ 	ar->htt.max_num_ampdu = ATH10K_HTT_MAX_NUM_AMPDU_DEFAULT;
++ 
++-	if (rawmode) {
+++	if (ath10k_frame_mode == ATH10K_HW_TXRX_RAW) {
++ 		if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
++ 			      fw_file->fw_features)) {
++ 			ath10k_err(ar, "rawmode = 1 requires support from firmware");
++--- a/drivers/net/wireless/ath/ath10k/core.h
+++++ b/drivers/net/wireless/ath/ath10k/core.h
++@@ -1311,6 +1311,7 @@ static inline bool ath10k_peer_stats_ena
++ 	return false;
++ }
++ 
+++extern unsigned int ath10k_frame_mode;
++ extern unsigned long ath10k_coredump_mask;
++ 
++ void ath10k_core_napi_sync_disable(struct ath10k *ar);
+diff --git a/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch b/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch
+new file mode 100644
+index 0000000000..a669c77fe2
+--- /dev/null
++++ b/package/kernel/mac80211/patches/ath10k/081-03-ath10k-htt-tx-do-not-interpret-Eth-frames-as-WiFi.patch
+@@ -0,0 +1,163 @@
++From 70f119fb82af7f7417dc659faf02c91e1f853739 Mon Sep 17 00:00:00 2001
++From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Date: Mon, 16 May 2022 13:26:00 +0300
++Subject: ath10k: htt_tx: do not interpret Eth frames as WiFi
++
++The xmit path for the Ethernet encapsulated frames become more or less
++usable since d740d8fd2439 ("ath10k: unify tx mode and dispatch"). This
++change reorganize the xmit path in a manageable way to properly support
++various tx modes, but misses that the Ethernet encapsulated frame is a
++special case. We do not have an IEEE 802.11 header at the begining of
++them. But the HTT Tx handler still interprets first bytes of each frame
++as an IEEE 802.11 Frame Control field.
++
++Than this code was copied by e62ee5c381c5 ("ath10k: Add support for
++htt_data_tx_desc_64 descriptor") and a2097d6444c3 ("ath10k: htt: High
++latency TX support") to another handlers. In fact the issue in the high
++latency (HL) handler was introduced by 83ac260151e7 ("ath10k: add mic
++bytes for pmf management packet").
++
++Ethernet encapsulated frame tx mode stay unused until 75d85fd9993c
++("ath10k: introduce basic tdls functionality") started using it for TDLS
++frames to avoid key selection issue in some firmwares.
++
++Trying to interpret the begining of an Ethernet encapsulated frame as an
++IEEE 802.11 header was not hurt us noticeably since we need to meet two
++conditions: (1) xmit should be performed towards a TDLS peer, and (2)
++the TDLS peer should have a specific OUI part of its MAC address. Looks
++like that the rareness in TDLS communications of OUIs that can be
++interpreted as an 802.11 management frame saves users from facing this
++issue earlier.
++
++Improve Ethernet tx mode support in the HTT Tx handler by avoiding
++interpreting its first bytes as an IEEE 802.11 header. While at it, make
++the ieee80211_hdr variable local to the code block that is guarded by
++!is_eth check. In this way, we clarify in which cases a frame can be
++interpreted as IEEE 802.11, and saves us from similar issues in the
++future.
++
++Credits: this change as part of xmit encapsulation offloading support
++was originally made by QCA and then submitted for inclusion by John
++Crispin [1]. But the whole work was not accepted due to the lack of a
++part for 64-bits descriptors [2]. Zhijun You then pointed this out to me
++in a reply to my initial RFC patch series. And I made this slightly
++reworked version that covered all the HTT Tx handler variants.
++
++1. https://lore.kernel.org/all/20191216092207.31032-1-john@phrozen.org/
++2. https://patchwork.kernel.org/project/linux-wireless/patch/20191216092207.31032-1-john@phrozen.org/
++
++Reported-by: Zhijun You <hujy652@gmail.com>
++Signed-off-by: Vasanthakumar Thiagarajan <vthiagar@qti.qualcomm.com>
++Signed-off-by: John Crispin <john@phrozen.org>
++Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
++Link: https://lore.kernel.org/r/20220516032519.29831-3-ryazanov.s.a@gmail.com
++---
++ drivers/net/wireless/ath/ath10k/htt_tx.c | 61 ++++++++++++++++++--------------
++ 1 file changed, 35 insertions(+), 26 deletions(-)
++
++--- a/drivers/net/wireless/ath/ath10k/htt_tx.c
+++++ b/drivers/net/wireless/ath/ath10k/htt_tx.c
++@@ -1295,7 +1295,6 @@ static int ath10k_htt_tx_hl(struct ath10
++ 	struct ath10k *ar = htt->ar;
++ 	int res, data_len;
++ 	struct htt_cmd_hdr *cmd_hdr;
++-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
++ 	struct htt_data_tx_desc *tx_desc;
++ 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
++ 	struct sk_buff *tmp_skb;
++@@ -1306,11 +1305,15 @@ static int ath10k_htt_tx_hl(struct ath10
++ 	u16 flags1 = 0;
++ 	u16 msdu_id = 0;
++ 
++-	if ((ieee80211_is_action(hdr->frame_control) ||
++-	     ieee80211_is_deauth(hdr->frame_control) ||
++-	     ieee80211_is_disassoc(hdr->frame_control)) &&
++-	     ieee80211_has_protected(hdr->frame_control)) {
++-		skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++	if (!is_eth) {
+++		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+++
+++		if ((ieee80211_is_action(hdr->frame_control) ||
+++		     ieee80211_is_deauth(hdr->frame_control) ||
+++		     ieee80211_is_disassoc(hdr->frame_control)) &&
+++		     ieee80211_has_protected(hdr->frame_control)) {
+++			skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++		}
++ 	}
++ 
++ 	data_len = msdu->len;
++@@ -1407,7 +1410,6 @@ static int ath10k_htt_tx_32(struct ath10
++ {
++ 	struct ath10k *ar = htt->ar;
++ 	struct device *dev = ar->dev;
++-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
++ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
++ 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
++ 	struct ath10k_hif_sg_item sg_items[2];
++@@ -1439,15 +1441,19 @@ static int ath10k_htt_tx_32(struct ath10
++ 	txbuf_paddr = htt->txbuf.paddr +
++ 		      (sizeof(struct ath10k_htt_txbuf_32) * msdu_id);
++ 
++-	if ((ieee80211_is_action(hdr->frame_control) ||
++-	     ieee80211_is_deauth(hdr->frame_control) ||
++-	     ieee80211_is_disassoc(hdr->frame_control)) &&
++-	     ieee80211_has_protected(hdr->frame_control)) {
++-		skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
++-	} else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
++-		   txmode == ATH10K_HW_TXRX_RAW &&
++-		   ieee80211_has_protected(hdr->frame_control)) {
++-		skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++	if (!is_eth) {
+++		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+++
+++		if ((ieee80211_is_action(hdr->frame_control) ||
+++		     ieee80211_is_deauth(hdr->frame_control) ||
+++		     ieee80211_is_disassoc(hdr->frame_control)) &&
+++		     ieee80211_has_protected(hdr->frame_control)) {
+++			skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++		} else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
+++			   txmode == ATH10K_HW_TXRX_RAW &&
+++			   ieee80211_has_protected(hdr->frame_control)) {
+++			skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++		}
++ 	}
++ 
++ 	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
++@@ -1609,7 +1615,6 @@ static int ath10k_htt_tx_64(struct ath10
++ {
++ 	struct ath10k *ar = htt->ar;
++ 	struct device *dev = ar->dev;
++-	struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
++ 	struct ieee80211_tx_info *info = IEEE80211_SKB_CB(msdu);
++ 	struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(msdu);
++ 	struct ath10k_hif_sg_item sg_items[2];
++@@ -1641,15 +1646,19 @@ static int ath10k_htt_tx_64(struct ath10
++ 	txbuf_paddr = htt->txbuf.paddr +
++ 		      (sizeof(struct ath10k_htt_txbuf_64) * msdu_id);
++ 
++-	if ((ieee80211_is_action(hdr->frame_control) ||
++-	     ieee80211_is_deauth(hdr->frame_control) ||
++-	     ieee80211_is_disassoc(hdr->frame_control)) &&
++-	     ieee80211_has_protected(hdr->frame_control)) {
++-		skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
++-	} else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
++-		   txmode == ATH10K_HW_TXRX_RAW &&
++-		   ieee80211_has_protected(hdr->frame_control)) {
++-		skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++	if (!is_eth) {
+++		struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)msdu->data;
+++
+++		if ((ieee80211_is_action(hdr->frame_control) ||
+++		     ieee80211_is_deauth(hdr->frame_control) ||
+++		     ieee80211_is_disassoc(hdr->frame_control)) &&
+++		     ieee80211_has_protected(hdr->frame_control)) {
+++			skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++		} else if (!(skb_cb->flags & ATH10K_SKB_F_NO_HWCRYPT) &&
+++			   txmode == ATH10K_HW_TXRX_RAW &&
+++			   ieee80211_has_protected(hdr->frame_control)) {
+++			skb_put(msdu, IEEE80211_CCMP_MIC_LEN);
+++		}
++ 	}
++ 
++ 	skb_cb->paddr = dma_map_single(dev, msdu->data, msdu->len,
+diff --git a/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch b/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch
+new file mode 100644
+index 0000000000..abca7aac9e
+--- /dev/null
++++ b/package/kernel/mac80211/patches/ath10k/081-04-ath10k-add-encapsulation-offloading-support.patch
+@@ -0,0 +1,194 @@
++From af6d8265c47e46881b80c6b073f53c8c4af52d28 Mon Sep 17 00:00:00 2001
++From: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Date: Mon, 16 May 2022 13:26:00 +0300
++Subject: ath10k: add encapsulation offloading support
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Frame encapsulation from Ethernet into the IEEE 802.11 frame format
++takes a considerable host CPU time on the xmit path. The firmware is
++able to do this operation for us, so enable encapsulation offloading for
++AP and Sta interface types to improve overall system performance.
++
++The driver is almost ready for encapsulation offloading support. There
++are only a few places where the driver assumes the frame format is IEEE
++802.11 that need to be fixed.
++
++Encapsulation offloading is currently disabled by default and the driver
++utilizes mac80211 encapsulation support. To activate offloading, the
++frame_mode=2 parameter should be passed during module loading.
++
++On a QCA9563+QCA9888-based access point in bridged mode, encapsulation
++offloading increases TCP 16-streams DL throughput from 365 to 396 mbps
++(+8%) and UDP DL throughput from 436 to 483 mbps (+11%).
++
++Tested-on: QCA9888 hw2.0 PCI 10.4-3.9.0.2-00131
++Tested-on: QCA6174 hw3.2 PCI WLAN.RM.4.4.1-00157-QCARMSWPZ-1
++Signed-off-by: Sergey Ryazanov <ryazanov.s.a@gmail.com>
++Tested-by: Oldřich Jedlička <oldium.pro@gmail.com> # TP-Link Archer C7 v4 & v5 (QCA9563 + QCA9880)
++Tested-by: Edward Matijevic <motolav@gmail.com> # TP-Link Archer C2600 (IPQ8064 + QCA9980 10.4.1.00030-1)
++Tested-by: Edward Matijevic <motolav@gmail.com> # QCA9377 PCI in Sta mode
++Tested-by: Zhijun You <hujy652@gmail.com> # NETGEAR R7800 (QCA9984 10.4-3.9.0.2-00159)
++Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
++Link: https://lore.kernel.org/r/20220516032519.29831-5-ryazanov.s.a@gmail.com
++---
++ drivers/net/wireless/ath/ath10k/core.c |  2 +-
++ drivers/net/wireless/ath/ath10k/mac.c  | 67 +++++++++++++++++++++++++++-------
++ 2 files changed, 55 insertions(+), 14 deletions(-)
++
++--- a/drivers/net/wireless/ath/ath10k/core.c
+++++ b/drivers/net/wireless/ath/ath10k/core.c
++@@ -54,7 +54,7 @@ MODULE_PARM_DESC(uart_print, "Uart targe
++ MODULE_PARM_DESC(skip_otp, "Skip otp failure for calibration in testmode");
++ MODULE_PARM_DESC(cryptmode, "Crypto mode: 0-hardware, 1-software");
++ MODULE_PARM_DESC(frame_mode,
++-		 "Datapath frame mode (0: raw, 1: native wifi (default))");
+++		 "Datapath frame mode (0: raw, 1: native wifi (default), 2: ethernet)");
++ MODULE_PARM_DESC(coredump_mask, "Bitfield of what to include in firmware crash file");
++ MODULE_PARM_DESC(fw_diag_log, "Diag based fw log debugging");
++ 
++--- a/drivers/net/wireless/ath/ath10k/mac.c
+++++ b/drivers/net/wireless/ath/ath10k/mac.c
++@@ -3710,6 +3710,9 @@ ath10k_mac_tx_h_get_txmode(struct ath10k
++ 	const struct ath10k_skb_cb *skb_cb = ATH10K_SKB_CB(skb);
++ 	__le16 fc = hdr->frame_control;
++ 
+++	if (IEEE80211_SKB_CB(skb)->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)
+++		return ATH10K_HW_TXRX_ETHERNET;
+++
++ 	if (!vif || vif->type == NL80211_IFTYPE_MONITOR)
++ 		return ATH10K_HW_TXRX_RAW;
++ 
++@@ -3870,6 +3873,12 @@ static void ath10k_mac_tx_h_fill_cb(stru
++ 	bool noack = false;
++ 
++ 	cb->flags = 0;
+++
+++	if (info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP) {
+++		cb->flags |= ATH10K_SKB_F_QOS;	/* Assume data frames are QoS */
+++		goto finish_cb_fill;
+++	}
+++
++ 	if (!ath10k_tx_h_use_hwcrypto(vif, skb))
++ 		cb->flags |= ATH10K_SKB_F_NO_HWCRYPT;
++ 
++@@ -3908,6 +3917,7 @@ static void ath10k_mac_tx_h_fill_cb(stru
++ 		cb->flags |= ATH10K_SKB_F_RAW_TX;
++ 	}
++ 
+++finish_cb_fill:
++ 	cb->vif = vif;
++ 	cb->txq = txq;
++ 	cb->airtime_est = airtime;
++@@ -4031,7 +4041,11 @@ static int ath10k_mac_tx(struct ath10k *
++ 		ath10k_tx_h_seq_no(vif, skb);
++ 		break;
++ 	case ATH10K_HW_TXRX_ETHERNET:
++-		ath10k_tx_h_8023(skb);
+++		/* Convert 802.11->802.3 header only if the frame was erlier
+++		 * encapsulated to 802.11 by mac80211. Otherwise pass it as is.
+++		 */
+++		if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP))
+++			ath10k_tx_h_8023(skb);
++ 		break;
++ 	case ATH10K_HW_TXRX_RAW:
++ 		if (!test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags) &&
++@@ -4643,12 +4657,10 @@ static void ath10k_mac_op_tx(struct ieee
++ 	struct ieee80211_vif *vif = info->control.vif;
++ 	struct ieee80211_sta *sta = control->sta;
++ 	struct ieee80211_txq *txq = NULL;
++-	struct ieee80211_hdr *hdr = (void *)skb->data;
++ 	enum ath10k_hw_txrx_mode txmode;
++ 	enum ath10k_mac_tx_path txpath;
++ 	bool is_htt;
++ 	bool is_mgmt;
++-	bool is_presp;
++ 	int ret;
++ 	u16 airtime;
++ 
++@@ -4662,8 +4674,14 @@ static void ath10k_mac_op_tx(struct ieee
++ 	is_mgmt = (txpath == ATH10K_MAC_TX_HTT_MGMT);
++ 
++ 	if (is_htt) {
+++		bool is_presp = false;
+++
++ 		spin_lock_bh(&ar->htt.tx_lock);
++-		is_presp = ieee80211_is_probe_resp(hdr->frame_control);
+++		if (!(info->flags & IEEE80211_TX_CTL_HW_80211_ENCAP)) {
+++			struct ieee80211_hdr *hdr = (void *)skb->data;
+++
+++			is_presp = ieee80211_is_probe_resp(hdr->frame_control);
+++		}
++ 
++ 		ret = ath10k_htt_tx_inc_pending(htt);
++ 		if (ret) {
++@@ -5463,6 +5481,30 @@ static int ath10k_mac_set_txbf_conf(stru
++ 					 ar->wmi.vdev_param->txbf, value);
++ }
++ 
+++static void ath10k_update_vif_offload(struct ieee80211_hw *hw,
+++				      struct ieee80211_vif *vif)
+++{
+++	struct ath10k_vif *arvif = (void *)vif->drv_priv;
+++	struct ath10k *ar = hw->priv;
+++	u32 vdev_param;
+++	int ret;
+++
+++	if (ath10k_frame_mode != ATH10K_HW_TXRX_ETHERNET ||
+++	    ar->wmi.vdev_param->tx_encap_type == WMI_VDEV_PARAM_UNSUPPORTED ||
+++	     (vif->type != NL80211_IFTYPE_STATION &&
+++	      vif->type != NL80211_IFTYPE_AP))
+++		vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
+++
+++	vdev_param = ar->wmi.vdev_param->tx_encap_type;
+++	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
+++					ATH10K_HW_TXRX_NATIVE_WIFI);
+++	/* 10.X firmware does not support this VDEV parameter. Do not warn */
+++	if (ret && ret != -EOPNOTSUPP) {
+++		ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
+++			    arvif->vdev_id, ret);
+++	}
+++}
+++
++ /*
++  * TODO:
++  * Figure out how to handle WMI_VDEV_SUBTYPE_P2P_DEVICE,
++@@ -5672,15 +5714,7 @@ static int ath10k_add_interface(struct i
++ 
++ 	arvif->def_wep_key_idx = -1;
++ 
++-	vdev_param = ar->wmi.vdev_param->tx_encap_type;
++-	ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id, vdev_param,
++-					ATH10K_HW_TXRX_NATIVE_WIFI);
++-	/* 10.X firmware does not support this VDEV parameter. Do not warn */
++-	if (ret && ret != -EOPNOTSUPP) {
++-		ath10k_warn(ar, "failed to set vdev %i TX encapsulation: %d\n",
++-			    arvif->vdev_id, ret);
++-		goto err_vdev_delete;
++-	}
+++	ath10k_update_vif_offload(hw, vif);
++ 
++ 	/* Configuring number of spatial stream for monitor interface is causing
++ 	 * target assert in qca9888 and qca6174.
++@@ -9368,6 +9402,7 @@ static const struct ieee80211_ops ath10k
++ 	.stop				= ath10k_stop,
++ 	.config				= ath10k_config,
++ 	.add_interface			= ath10k_add_interface,
+++	.update_vif_offload		= ath10k_update_vif_offload,
++ 	.remove_interface		= ath10k_remove_interface,
++ 	.configure_filter		= ath10k_configure_filter,
++ 	.bss_info_changed		= ath10k_bss_info_changed,
++@@ -10037,6 +10072,12 @@ int ath10k_mac_register(struct ath10k *a
++ 	if (test_bit(WMI_SERVICE_TDLS_UAPSD_BUFFER_STA, ar->wmi.svc_map))
++ 		ieee80211_hw_set(ar->hw, SUPPORTS_TDLS_BUFFER_STA);
++ 
+++	if (ath10k_frame_mode == ATH10K_HW_TXRX_ETHERNET) {
+++		if (ar->wmi.vdev_param->tx_encap_type !=
+++		    WMI_VDEV_PARAM_UNSUPPORTED)
+++			ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
+++	}
+++
++ 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
++ 	ar->hw->wiphy->flags |= WIPHY_FLAG_HAS_CHANNEL_SWITCH;
++ 	ar->hw->wiphy->max_remain_on_channel_duration = 5000;
+diff --git a/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch b/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch
+new file mode 100644
+index 0000000000..7ef418e506
+--- /dev/null
++++ b/package/kernel/mac80211/patches/ath10k/100-ath10k-support-bus-and-device-specific-API-1-BDF-sel.patch
+@@ -0,0 +1,65 @@
++From f2a7064a78b22f2b68b9fcbc8a6f4c5e61c5ba64 Mon Sep 17 00:00:00 2001
++From: Robert Marko <robimarko@gmail.com>
++Date: Sun, 10 Oct 2021 00:17:11 +0200
++Subject: [PATCH] ath10k: support bus and device specific API 1 BDF selection
++
++Some ath10k IPQ40xx devices like the MikroTik hAP ac2 and ac3 require the
++BDF-s to be extracted from the device storage instead of shipping packaged
++API 2 BDF-s.
++
++This is required as MikroTik has started shipping boards that require BDF-s
++to be updated, as otherwise their WLAN performance really suffers.
++This is however impossible as the devices that require this are release
++under the same revision and its not possible to differentiate them from
++devices using the older BDF-s.
++
++In OpenWrt we are extracting the calibration data during runtime and we are
++able to extract the BDF-s in the same manner, however we cannot package the
++BDF-s to API 2 format on the fly and can only use API 1 to provide BDF-s on
++the fly.
++This is an issue as the ath10k driver explicitly looks only for the
++board.bin file and not for something like board-bus-device.bin like it does
++for pre-cal data.
++Due to this we have no way of providing correct BDF-s on the fly, so lets
++extend the ath10k driver to first look for BDF-s in the
++board-bus-device.bin format, for example: board-ahb-a800000.wifi.bin
++If that fails, look for the default board file name as defined previously.
++
++Signed-off-by: Robert Marko <robimarko@gmail.com>
++Signed-off-by: Kalle Valo <quic_kvalo@quicinc.com>
++Link: https://lore.kernel.org/r/20211009221711.2315352-1-robimarko@gmail.com
++---
++ drivers/net/wireless/ath/ath10k/core.c | 13 ++++++++++++-
++ 1 file changed, 12 insertions(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ath/ath10k/core.c
+++++ b/drivers/net/wireless/ath/ath10k/core.c
++@@ -1202,6 +1202,7 @@ success:
++ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar, int bd_ie_type)
++ {
++ 	const struct firmware *fw;
+++	char boardname[100];
++ 
++ 	if (bd_ie_type == ATH10K_BD_IE_BOARD) {
++ 		if (!ar->hw_params.fw.board) {
++@@ -1209,9 +1210,19 @@ static int ath10k_core_fetch_board_data_
++ 			return -EINVAL;
++ 		}
++ 
+++		scnprintf(boardname, sizeof(boardname), "board-%s-%s.bin",
+++			  ath10k_bus_str(ar->hif.bus), dev_name(ar->dev));
+++
++ 		ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
++ 								ar->hw_params.fw.dir,
++-								ar->hw_params.fw.board);
+++								boardname);
+++		if (IS_ERR(ar->normal_mode_fw.board)) {
+++			fw = ath10k_fetch_fw_file(ar,
+++						  ar->hw_params.fw.dir,
+++						  ar->hw_params.fw.board);
+++			ar->normal_mode_fw.board = fw;
+++		}
+++
++ 		if (IS_ERR(ar->normal_mode_fw.board))
++ 			return PTR_ERR(ar->normal_mode_fw.board);
++ 
 diff --git a/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch b/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch
 new file mode 100644
-index 0000000000..bebd5fe6c2
+index 0000000000..c7a00b7e4b
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/ath10k/120-ath10k-fetch-calibration-data-via-nvmem-subsystem.patch
 @@ -0,0 +1,162 @@
@@ -789,7 +1730,7 @@ index 0000000000..bebd5fe6c2
 + #include <asm/byteorder.h>
 + 
 + #include "core.h"
-+@@ -952,7 +953,8 @@ static int ath10k_core_get_board_id_from
++@@ -955,7 +956,8 @@ static int ath10k_core_get_board_id_from
 + 	}
 + 
 + 	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
@@ -799,7 +1740,7 @@ index 0000000000..bebd5fe6c2
 + 		bmi_board_id_param = BMI_PARAM_GET_FLASH_BOARD_ID;
 + 	else
 + 		bmi_board_id_param = BMI_PARAM_GET_EEPROM_BOARD_ID;
-+@@ -1743,7 +1745,8 @@ static int ath10k_download_and_run_otp(s
++@@ -1757,7 +1759,8 @@ static int ath10k_download_and_run_otp(s
 + 
 + 	/* As of now pre-cal is valid for 10_4 variants */
 + 	if (ar->cal_mode == ATH10K_PRE_CAL_MODE_DT ||
@@ -809,7 +1750,7 @@ index 0000000000..bebd5fe6c2
 + 		bmi_otp_exe_param = BMI_PARAM_FLASH_SECTION_ALL;
 + 
 + 	ret = ath10k_bmi_execute(ar, address, bmi_otp_exe_param, &result);
-+@@ -1870,6 +1873,39 @@ out_free:
++@@ -1884,6 +1887,39 @@ out_free:
 + 	return ret;
 + }
 + 
@@ -849,7 +1790,7 @@ index 0000000000..bebd5fe6c2
 + int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
 + 				     struct ath10k_fw_file *fw_file)
 + {
-+@@ -2104,6 +2140,18 @@ static int ath10k_core_pre_cal_download(
++@@ -2118,6 +2154,18 @@ static int ath10k_core_pre_cal_download(
 + {
 + 	int ret;
 + 
@@ -868,7 +1809,7 @@ index 0000000000..bebd5fe6c2
 + 	ret = ath10k_download_cal_file(ar, ar->pre_cal_file);
 + 	if (ret == 0) {
 + 		ar->cal_mode = ATH10K_PRE_CAL_MODE_FILE;
-+@@ -2170,6 +2218,18 @@ static int ath10k_download_cal_data(stru
++@@ -2184,6 +2232,18 @@ static int ath10k_download_cal_data(stru
 + 		   "pre cal download procedure failed, try cal file: %d\n",
 + 		   ret);
 + 
@@ -919,7 +1860,7 @@ diff --git a/package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchro
 similarity index 94%
 rename from package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchronously.patch
 rename to package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch
-index 2b8fe7816f..b6ae2c7c83 100644
+index 2b8fe7816f..e47fb012fa 100644
 --- a/package/kernel/mac80211/patches/ath/921-ath10k_init_devices_synchronously.patch
 +++ b/package/kernel/mac80211/patches/ath10k/921-ath10k_init_devices_synchronously.patch
 @@ -14,7 +14,7 @@ Signed-off-by: Sven Eckelmann <sven@open-mesh.com>
@@ -927,7 +1868,7 @@ index 2b8fe7816f..b6ae2c7c83 100644
  --- a/drivers/net/wireless/ath/ath10k/core.c
  +++ b/drivers/net/wireless/ath/ath10k/core.c
 -@@ -3206,6 +3206,16 @@ int ath10k_core_register(struct ath10k *
-+@@ -3429,6 +3429,16 @@ int ath10k_core_register(struct ath10k *
++@@ -3443,6 +3443,16 @@ int ath10k_core_register(struct ath10k *
   
   	queue_work(ar->workqueue, &ar->register_work);
   
@@ -935,14 +1876,14 @@ diff --git a/package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.
 similarity index 89%
 rename from package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.patch
 rename to package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch
-index 41022b873a..b60db19464 100644
+index 41022b873a..9dfde4385e 100644
 --- a/package/kernel/mac80211/patches/ath/930-ath10k_add_tpt_led_trigger.patch
 +++ b/package/kernel/mac80211/patches/ath10k/930-ath10k_add_tpt_led_trigger.patch
 @@ -1,6 +1,6 @@
  --- a/drivers/net/wireless/ath/ath10k/mac.c
  +++ b/drivers/net/wireless/ath/ath10k/mac.c
 -@@ -9732,6 +9732,21 @@ static int ath10k_mac_init_rd(struct ath
-+@@ -9843,6 +9843,21 @@ static int ath10k_mac_init_rd(struct ath
++@@ -9894,6 +9894,21 @@ static int ath10k_mac_init_rd(struct ath
   	return 0;
   }
   
@@ -951,7 +1892,7 @@ index 41022b873a..b60db19464 100644
   {
   	static const u32 cipher_suites[] = {
 -@@ -10081,6 +10096,12 @@ int ath10k_mac_register(struct ath10k *a
-+@@ -10195,6 +10210,12 @@ int ath10k_mac_register(struct ath10k *a
++@@ -10252,6 +10267,12 @@ int ath10k_mac_register(struct ath10k *a
   
   	ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
   
@@ -959,7 +1900,7 @@ diff --git a/package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-con
 similarity index 96%
 rename from package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch
 rename to package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch
-index d8c8a8abc0..6db2430749 100644
+index d8c8a8abc0..47b52416ab 100644
 --- a/package/kernel/mac80211/patches/ath/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch
 +++ b/package/kernel/mac80211/patches/ath10k/974-ath10k_add-LED-and-GPIO-controlling-support-for-various-chipsets.patch
 @@ -85,7 +85,7 @@ v13:
@@ -976,7 +1917,7 @@ index d8c8a8abc0..6db2430749 100644
  --- a/local-symbols
  +++ b/local-symbols
 -@@ -145,6 +145,7 @@ ATH10K_DEBUG=
-+@@ -143,6 +143,7 @@ ATH10K_DEBUG=
++@@ -166,6 +166,7 @@ ATH10K_DEBUG=
   ATH10K_DEBUGFS=
   ATH10K_SPECTRAL=
   ATH10K_THERMAL=
@@ -994,7 +1935,7 @@ index d8c8a8abc0..6db2430749 100644
   unsigned int ath10k_debug_mask;
   EXPORT_SYMBOL(ath10k_debug_mask);
 -@@ -61,6 +62,7 @@ static const struct ath10k_hw_params ath
-+@@ -62,6 +63,7 @@ static const struct ath10k_hw_params ath
++@@ -65,6 +66,7 @@ static const struct ath10k_hw_params ath
   		.dev_id = QCA988X_2_0_DEVICE_ID,
   		.bus = ATH10K_BUS_PCI,
   		.name = "qca988x hw2.0",
@@ -1003,7 +1944,7 @@ index d8c8a8abc0..6db2430749 100644
   		.uart_pin = 7,
   		.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
 -@@ -132,6 +134,7 @@ static const struct ath10k_hw_params ath
-+@@ -135,6 +137,7 @@ static const struct ath10k_hw_params ath
++@@ -138,6 +140,7 @@ static const struct ath10k_hw_params ath
   		.dev_id = QCA9887_1_0_DEVICE_ID,
   		.bus = ATH10K_BUS_PCI,
   		.name = "qca9887 hw1.0",
@@ -1012,7 +1953,7 @@ index d8c8a8abc0..6db2430749 100644
   		.uart_pin = 7,
   		.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_ALL,
 -@@ -343,6 +346,7 @@ static const struct ath10k_hw_params ath
-+@@ -352,6 +355,7 @@ static const struct ath10k_hw_params ath
++@@ -355,6 +358,7 @@ static const struct ath10k_hw_params ath
   		.dev_id = QCA99X0_2_0_DEVICE_ID,
   		.bus = ATH10K_BUS_PCI,
   		.name = "qca99x0 hw2.0",
@@ -1021,7 +1962,7 @@ index d8c8a8abc0..6db2430749 100644
   		.uart_pin = 7,
   		.otp_exe_param = 0x00000700,
 -@@ -384,6 +388,7 @@ static const struct ath10k_hw_params ath
-+@@ -394,6 +398,7 @@ static const struct ath10k_hw_params ath
++@@ -397,6 +401,7 @@ static const struct ath10k_hw_params ath
   		.dev_id = QCA9984_1_0_DEVICE_ID,
   		.bus = ATH10K_BUS_PCI,
   		.name = "qca9984/qca9994 hw1.0",
@@ -1030,7 +1971,7 @@ index d8c8a8abc0..6db2430749 100644
   		.uart_pin = 7,
   		.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
 -@@ -432,6 +437,7 @@ static const struct ath10k_hw_params ath
-+@@ -443,6 +448,7 @@ static const struct ath10k_hw_params ath
++@@ -446,6 +451,7 @@ static const struct ath10k_hw_params ath
   		.dev_id = QCA9888_2_0_DEVICE_ID,
   		.bus = ATH10K_BUS_PCI,
   		.name = "qca9888 hw2.0",
@@ -1039,7 +1980,7 @@ index d8c8a8abc0..6db2430749 100644
   		.uart_pin = 7,
   		.cc_wraparound_type = ATH10K_HW_CC_WRAP_SHIFTED_EACH,
 -@@ -2921,6 +2927,10 @@ int ath10k_core_start(struct ath10k *ar,
-+@@ -3144,6 +3150,10 @@ int ath10k_core_start(struct ath10k *ar,
++@@ -3158,6 +3164,10 @@ int ath10k_core_start(struct ath10k *ar,
   		goto err_hif_stop;
   	}
   
@@ -1048,7 +1989,7 @@ index d8c8a8abc0..6db2430749 100644
   
   err_hif_stop:
 -@@ -3179,9 +3189,18 @@ static void ath10k_core_register_work(st
-+@@ -3402,9 +3412,18 @@ static void ath10k_core_register_work(st
++@@ -3416,9 +3426,18 @@ static void ath10k_core_register_work(st
   		goto err_spectral_destroy;
   	}
   
@@ -1057,7 +1998,7 @@ index d8c8a8abc0..6db2430749 100644
   	ath10k_spectral_destroy(ar);
   err_debug_destroy:
 -@@ -3227,6 +3246,8 @@ void ath10k_core_unregister(struct ath10
-+@@ -3450,6 +3469,8 @@ void ath10k_core_unregister(struct ath10
++@@ -3464,6 +3483,8 @@ void ath10k_core_unregister(struct ath10
   	if (!test_bit(ATH10K_FLAG_CORE_REGISTERED, &ar->dev_flags))
   		return;
   
@@ -1074,7 +2015,7 @@ diff --git a/package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-d
 similarity index 92%
 rename from package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-default.patch
 rename to package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch
-index 5781f9c7ad..da31ad578a 100644
+index 5781f9c7ad..842853ddf4 100644
 --- a/package/kernel/mac80211/patches/ath/975-ath10k-use-tpt-trigger-by-default.patch
 +++ b/package/kernel/mac80211/patches/ath10k/975-ath10k-use-tpt-trigger-by-default.patch
 @@ -16,9 +16,9 @@ Signed-off-by: Mathias Kresin <dev@kresin.me>
@@ -1095,7 +2036,7 @@ index 5781f9c7ad..da31ad578a 100644
  --- a/drivers/net/wireless/ath/ath10k/mac.c
  +++ b/drivers/net/wireless/ath/ath10k/mac.c
 -@@ -10098,7 +10098,7 @@ int ath10k_mac_register(struct ath10k *a
-+@@ -10212,7 +10212,7 @@ int ath10k_mac_register(struct ath10k *a
++@@ -10269,7 +10269,7 @@ int ath10k_mac_register(struct ath10k *a
   	ar->hw->weight_multiplier = ATH10K_AIRTIME_WEIGHT_MULTIPLIER;
   
   #ifdef CPTCFG_MAC80211_LEDS
@@ -1144,7 +2085,7 @@ index 1f19765891..a45addf119 100644
   			ch->max_reg_power = channel->max_reg_power * 2;
 diff --git a/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch b/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch
 new file mode 100644
-index 0000000000..4077b2f393
+index 0000000000..80da07de8a
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/ath10k/984-ath10k-Try-to-get-mac-address-from-dts.patch
 @@ -0,0 +1,37 @@
@@ -1176,7 +2117,7 @@ index 0000000000..4077b2f393
 + #include <linux/property.h>
 + #include <linux/dmi.h>
 + #include <linux/ctype.h>
-+@@ -3320,6 +3321,8 @@ static int ath10k_core_probe_fw(struct a
++@@ -3334,6 +3335,8 @@ static int ath10k_core_probe_fw(struct a
 + 
 + 	device_get_mac_address(ar->dev, ar->mac_addr, sizeof(ar->mac_addr));
 + 
@@ -1749,7 +2690,7 @@ diff --git a/package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.pat
 similarity index 99%
 rename from package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.patch
 rename to package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch
-index e9cf00769d..291bc6d1e1 100644
+index e9cf00769d..6b5c0dc514 100644
 --- a/package/kernel/mac80211/patches/ath/551-ath9k_ubnt_uap_plus_hsr.patch
 +++ b/package/kernel/mac80211/patches/ath9k/551-ath9k_ubnt_uap_plus_hsr.patch
 @@ -371,7 +371,7 @@
@@ -1757,7 +2698,7 @@ index e9cf00769d..291bc6d1e1 100644
  --- a/local-symbols
  +++ b/local-symbols
 -@@ -112,6 +112,7 @@ ATH9K_WOW=
-+@@ -110,6 +110,7 @@ ATH9K_WOW=
++@@ -133,6 +133,7 @@ ATH9K_WOW=
   ATH9K_RFKILL=
   ATH9K_CHANNEL_CONTEXT=
   ATH9K_PCOEM=
@@ -1859,10 +2800,6 @@ index 8e0041e3ef..80e0dc4c5e 100644
   	if (ret)
   		goto err_hw;
   
-diff --git a/package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch b/package/kernel/mac80211/patches/ath9k/580-ath9k_ar9561_fix_bias_level.patch
-similarity index 100%
-rename from package/kernel/mac80211/patches/ath/580-ath9k_ar9561_fix_bias_level.patch
-rename to package/kernel/mac80211/patches/ath9k/580-ath9k_ar9561_fix_bias_level.patch
 diff --git a/package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch b/package/kernel/mac80211/patches/ath9k/600-v5.16-ath9k-fetch-calibration-data-via-nvmem-subsystem.patch
 new file mode 100644
 index 0000000000..a250d2318e
@@ -2210,6 +3147,115 @@ index 0000000000..62c561d619
 + 	if (err)
 + 		dev_err(&pdev->dev, "failed to request caldata (%d).\n", err);
 + 
+diff --git a/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch b/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch
+new file mode 100644
+index 0000000000..03d9f8ecd8
+--- /dev/null
++++ b/package/kernel/mac80211/patches/brcm/001-brcmfmac-allow-setting-wlan-MAC-address-using-device.patch
+@@ -0,0 +1,103 @@
++From 716c220b4d990a4fe7800d0685ca69dee99e4e8f Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Pavel=20L=C3=B6bl?= <pavel@loebl.cz>
++Date: Fri, 6 May 2022 06:42:46 +0200
++Subject: [PATCH] brcmfmac: allow setting wlan MAC address using device tree
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++This allows firmware to provide MAC address using device tree. Like in
++case there is no MAC burned in wlan NVRAM.
++
++Signed-off-by: Pavel Löbl <pavel@loebl.cz>
++Signed-off-by: Kalle Valo <kvalo@kernel.org>
++Link: https://lore.kernel.org/r/20220506044246.67146-1-pavel@loebl.cz
++---
++ .../broadcom/brcm80211/brcmfmac/common.c      | 23 ++++++++++++++-----
++ .../broadcom/brcm80211/brcmfmac/common.h      |  1 +
++ .../broadcom/brcm80211/brcmfmac/core.c        |  4 +++-
++ .../wireless/broadcom/brcm80211/brcmfmac/of.c |  3 +++
++ 4 files changed, 24 insertions(+), 7 deletions(-)
++
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
++@@ -202,13 +202,24 @@ int brcmf_c_preinit_dcmds(struct brcmf_i
++ 	char *ptr;
++ 	s32 err;
++ 
++-	/* retreive mac address */
++-	err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
++-				       sizeof(ifp->mac_addr));
++-	if (err < 0) {
++-		bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
++-		goto done;
+++	if (is_valid_ether_addr(ifp->mac_addr)) {
+++		/* set mac address */
+++		err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
+++					       ETH_ALEN);
+++		if (err < 0) {
+++			bphy_err(ifp->drvr, "Setting cur_etheraddr failed, %d\n", err);
+++			goto done;
+++		}
+++	} else {
+++		/* retrieve mac address */
+++		err = brcmf_fil_iovar_data_get(ifp, "cur_etheraddr", ifp->mac_addr,
+++					       sizeof(ifp->mac_addr));
+++		if (err < 0) {
+++			bphy_err(drvr, "Retrieving cur_etheraddr failed, %d\n", err);
+++			goto done;
+++		}
++ 	}
+++
++ 	memcpy(ifp->drvr->mac, ifp->mac_addr, sizeof(ifp->drvr->mac));
++ 	memcpy(ifp->drvr->wiphy->perm_addr, ifp->drvr->mac, ETH_ALEN);
++ 
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.h
++@@ -50,6 +50,7 @@ struct brcmf_mp_device {
++ 	bool		ignore_probe_fail;
++ 	struct brcmfmac_pd_cc *country_codes;
++ 	const char	*board_type;
+++	unsigned char	mac[ETH_ALEN];
++ 	union {
++ 		struct brcmfmac_sdio_pd sdio;
++ 	} bus;
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
++@@ -7,6 +7,7 @@
++ #include <linux/etherdevice.h>
++ #include <linux/module.h>
++ #include <linux/inetdevice.h>
+++#include <linux/property.h>
++ #include <net/cfg80211.h>
++ #include <net/rtnetlink.h>
++ #include <net/addrconf.h>
++@@ -1226,7 +1227,8 @@ static int brcmf_bus_started(struct brcm
++ 	brcmf_dbg(TRACE, "\n");
++ 
++ 	/* add primary networking interface */
++-	ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d", NULL);
+++	ifp = brcmf_add_if(drvr, 0, 0, false, "wlan%d",
+++			   is_valid_ether_addr(drvr->settings->mac) ? drvr->settings->mac : NULL);
++ 	if (IS_ERR(ifp))
++ 		return PTR_ERR(ifp);
++ 
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
++@@ -5,6 +5,7 @@
++ #include <linux/init.h>
++ #include <linux/of.h>
++ #include <linux/of_irq.h>
+++#include <linux/of_net.h>
++ 
++ #include <defs.h>
++ #include "debug.h"
++@@ -97,6 +98,8 @@ void brcmf_of_probe(struct device *dev,
++ 	if (err)
++ 		brcmf_err("failed to get OF country code map (err=%d)\n", err);
++ 
+++	of_get_mac_address(np, settings->mac);
+++
++ 	if (bus_type != BRCMF_BUSTYPE_SDIO)
++ 		return;
++ 
 diff --git a/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch b/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch
 index 52ae7a8eba..5dc04ecc88 100644
 --- a/package/kernel/mac80211/patches/brcm/812-b43-add-antenna-control.patch
@@ -2320,7 +3366,7 @@ index 774656f1fd..88465f256b 100644
   	 * FW later while initializing the dongle
   	 */
 diff --git a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
-index 9658bda1c1..835c870a65 100644
+index 9658bda1c1..1ddc78f7ca 100644
 --- a/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
 +++ b/package/kernel/mac80211/patches/brcm/863-brcmfmac-add-in-driver-tables-with-country-codes.patch
 @@ -12,9 +12,9 @@ Signed-off-by: Rafał Miłecki <rafal@milecki.pl>
@@ -2330,7 +3376,7 @@ index 9658bda1c1..835c870a65 100644
 -@@ -12,6 +12,36 @@
 - #include "common.h"
 - #include "of.h"
-+@@ -58,6 +58,36 @@ static int brcmf_of_get_country_codes(st
++@@ -59,6 +59,36 @@ static int brcmf_of_get_country_codes(st
 + 	return 0;
 + }
   
@@ -2341,7 +3387,7 @@ index 9658bda1c1..835c870a65 100644
   		    struct brcmf_mp_device *settings)
   {
 -@@ -43,6 +73,8 @@ void brcmf_of_probe(struct device *dev,
-+@@ -90,6 +120,8 @@ void brcmf_of_probe(struct device *dev,
++@@ -91,6 +121,8 @@ void brcmf_of_probe(struct device *dev,
   		of_node_put(root);
   	}
   
@@ -2352,8 +3398,210 @@ index 9658bda1c1..835c870a65 100644
 + 	if (!np || !of_device_is_compatible(np, "brcm,bcm4329-fmac"))
   		return;
 + 
+diff --git a/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch b/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch
+new file mode 100644
+index 0000000000..8adb8c42a1
+--- /dev/null
++++ b/package/kernel/mac80211/patches/brcm/865-brcmfmac-Read-alternative-firmware-names-from-DT.patch
+@@ -0,0 +1,196 @@
++From 4e32024cbb14230af3048e249e84f8c2b25ce45a Mon Sep 17 00:00:00 2001
++From: Phil Elwell <phil@raspberrypi.com>
++Date: Thu, 28 Oct 2021 15:03:16 +0100
++Subject: [PATCH] brcmfmac: Read alternative firmware names from DT
++
++Add the ability to load the names of alternative firmwares from the
++Device Tree node. This permits separate firmwares for 43436s and 43438
++and allows downstream firmwares to coexist with upstream.
++
++Signed-off-by: Phil Elwell <phil@raspberrypi.com>
++---
++ .../wireless/broadcom/brcm80211/brcmfmac/of.c | 36 ++++++++++++++
++ .../wireless/broadcom/brcm80211/brcmfmac/of.h |  7 +++
++ .../broadcom/brcm80211/brcmfmac/sdio.c        | 47 +++++++++++++++++--
++ 3 files changed, 87 insertions(+), 3 deletions(-)
++
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.c
++@@ -11,6 +11,7 @@
++ #include "debug.h"
++ #include "core.h"
++ #include "common.h"
+++#include "firmware.h"
++ #include "of.h"
++ 
++ static int brcmf_of_get_country_codes(struct device *dev,
++@@ -153,3 +154,38 @@ void brcmf_of_probe(struct device *dev,
++ 	sdio->oob_irq_nr = irq;
++ 	sdio->oob_irq_flags = irqf;
++ }
+++
+++struct brcmf_firmware_mapping *
+++brcmf_of_fwnames(struct device *dev, u32 *fwname_count)
+++{
+++	struct device_node *np = dev->of_node;
+++	struct brcmf_firmware_mapping *fwnames;
+++	struct device_node *map_np, *fw_np;
+++	int of_count;
+++	int count = 0;
+++
+++	map_np = of_get_child_by_name(np, "firmwares");
+++	of_count = of_get_child_count(map_np);
+++	if (!of_count)
+++		return NULL;
+++
+++	fwnames = devm_kcalloc(dev, of_count,
+++			       sizeof(struct brcmf_firmware_mapping),
+++			       GFP_KERNEL);
+++
+++	for_each_child_of_node(map_np, fw_np)
+++	{
+++		struct brcmf_firmware_mapping *cur = &fwnames[count];
+++
+++		if (of_property_read_u32(fw_np, "chipid", &cur->chipid) ||
+++		    of_property_read_u32(fw_np, "revmask", &cur->revmask))
+++			continue;
+++		cur->fw_base = of_get_property(fw_np, "fw_base", NULL);
+++		if (cur->fw_base)
+++			count++;
+++	}
+++
+++	*fwname_count = count;
+++
+++	return count ? fwnames : NULL;
+++}
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/of.h
++@@ -5,9 +5,16 @@
++ #ifdef CONFIG_OF
++ void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
++ 		    struct brcmf_mp_device *settings);
+++struct brcmf_firmware_mapping *
+++brcmf_of_fwnames(struct device *dev, u32 *map_count);
++ #else
++ static void brcmf_of_probe(struct device *dev, enum brcmf_bus_type bus_type,
++ 			   struct brcmf_mp_device *settings)
++ {
++ }
+++static struct brcmf_firmware_mapping *
+++brcmf_of_fwnames(struct device *dev, u32 *map_count)
+++{
+++	return NULL;
+++}
++ #endif /* CONFIG_OF */
++--- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
+++++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
++@@ -35,6 +35,7 @@
++ #include "core.h"
++ #include "common.h"
++ #include "bcdc.h"
+++#include "of.h"
++ 
++ #define DCMD_RESP_TIMEOUT	msecs_to_jiffies(2500)
++ #define CTL_DONE_TIMEOUT	msecs_to_jiffies(2500)
++@@ -633,7 +634,7 @@ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "b
++ /* per-board firmware binaries */
++ MODULE_FIRMWARE(BRCMF_FW_DEFAULT_PATH "brcmfmac*-sdio.*.bin");
++ 
++-static const struct brcmf_firmware_mapping brcmf_sdio_fwnames[] = {
+++static const struct brcmf_firmware_mapping sdio_fwnames[] = {
++ 	BRCMF_FW_ENTRY(BRCM_CC_43143_CHIP_ID, 0xFFFFFFFF, 43143),
++ 	BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x0000001F, 43241B0),
++ 	BRCMF_FW_ENTRY(BRCM_CC_43241_CHIP_ID, 0x00000020, 43241B4),
++@@ -659,6 +660,9 @@ static const struct brcmf_firmware_mappi
++ 	BRCMF_FW_ENTRY(CY_CC_43752_CHIP_ID, 0xFFFFFFFF, 43752)
++ };
++ 
+++static const struct brcmf_firmware_mapping *brcmf_sdio_fwnames = sdio_fwnames;
+++static u32 brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
+++
++ #define TXCTL_CREDITS	2
++ 
++ static void pkt_align(struct sk_buff *p, int len, int align)
++@@ -4140,7 +4144,7 @@ int brcmf_sdio_get_fwname(struct device
++ 
++ 	fwreq = brcmf_fw_alloc_request(bus_if->chip, bus_if->chiprev,
++ 				       brcmf_sdio_fwnames,
++-				       ARRAY_SIZE(brcmf_sdio_fwnames),
+++				       brcmf_sdio_fwnames_count,
++ 				       fwnames, ARRAY_SIZE(fwnames));
++ 	if (!fwreq)
++ 		return -ENOMEM;
++@@ -4196,6 +4200,9 @@ static const struct brcmf_bus_ops brcmf_
++ #define BRCMF_SDIO_FW_CODE	0
++ #define BRCMF_SDIO_FW_NVRAM	1
++ 
+++static struct brcmf_fw_request *
+++brcmf_sdio_prepare_fw_request(struct brcmf_sdio *bus);
+++
++ static void brcmf_sdio_firmware_callback(struct device *dev, int err,
++ 					 struct brcmf_fw_request *fwreq)
++ {
++@@ -4211,6 +4218,22 @@ static void brcmf_sdio_firmware_callback
++ 
++ 	brcmf_dbg(TRACE, "Enter: dev=%s, err=%d\n", dev_name(dev), err);
++ 
+++	if (err && brcmf_sdio_fwnames != sdio_fwnames) {
+++		/* Try again with the standard firmware names */
+++		brcmf_sdio_fwnames = sdio_fwnames;
+++		brcmf_sdio_fwnames_count = ARRAY_SIZE(sdio_fwnames);
+++		kfree(fwreq);
+++		fwreq = brcmf_sdio_prepare_fw_request(bus);
+++		if (!fwreq) {
+++			err = -ENOMEM;
+++			goto fail;
+++		}
+++		err = brcmf_fw_get_firmwares(dev, fwreq,
+++					     brcmf_sdio_firmware_callback);
+++		if (!err)
+++			return;
+++	}
+++
++ 	if (err)
++ 		goto fail;
++ 
++@@ -4419,7 +4442,7 @@ brcmf_sdio_prepare_fw_request(struct brc
++ 
++ 	fwreq = brcmf_fw_alloc_request(bus->ci->chip, bus->ci->chiprev,
++ 				       brcmf_sdio_fwnames,
++-				       ARRAY_SIZE(brcmf_sdio_fwnames),
+++				       brcmf_sdio_fwnames_count,
++ 				       fwnames, ARRAY_SIZE(fwnames));
++ 	if (!fwreq)
++ 		return NULL;
++@@ -4437,6 +4460,9 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
++ 	struct brcmf_sdio *bus;
++ 	struct workqueue_struct *wq;
++ 	struct brcmf_fw_request *fwreq;
+++	struct brcmf_firmware_mapping *of_fwnames, *fwnames = NULL;
+++	const int fwname_size = sizeof(struct brcmf_firmware_mapping);
+++	u32 of_fw_count;
++ 
++ 	brcmf_dbg(TRACE, "Enter\n");
++ 
++@@ -4519,6 +4545,21 @@ struct brcmf_sdio *brcmf_sdio_probe(stru
++ 
++ 	brcmf_dbg(INFO, "completed!!\n");
++ 
+++	of_fwnames = brcmf_of_fwnames(sdiodev->dev, &of_fw_count);
+++	if (of_fwnames)
+++		fwnames = devm_kcalloc(sdiodev->dev,
+++				       of_fw_count + brcmf_sdio_fwnames_count,
+++				       fwname_size, GFP_KERNEL);
+++
+++	if (fwnames) {
+++		/* The array is scanned in order, so overrides come first */
+++		memcpy(fwnames, of_fwnames, of_fw_count * fwname_size);
+++		memcpy(fwnames + of_fw_count, sdio_fwnames,
+++		       brcmf_sdio_fwnames_count * fwname_size);
+++		brcmf_sdio_fwnames = fwnames;
+++		brcmf_sdio_fwnames_count += of_fw_count;
+++	}
+++
++ 	fwreq = brcmf_sdio_prepare_fw_request(bus);
++ 	if (!fwreq) {
++ 		ret = -ENOMEM;
 diff --git a/package/kernel/mac80211/patches/brcm/998-survey.patch b/package/kernel/mac80211/patches/brcm/998-survey.patch
-index 25a12c783e..a5efc08015 100644
+index 25a12c783e..d194e25177 100644
 --- a/package/kernel/mac80211/patches/brcm/998-survey.patch
 +++ b/package/kernel/mac80211/patches/brcm/998-survey.patch
 @@ -1,6 +1,6 @@
@@ -2396,7 +3644,7 @@ index 25a12c783e..a5efc08015 100644
  --- a/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
  +++ b/drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
 -@@ -1356,6 +1356,8 @@ int brcmf_attach(struct device *dev)
-+@@ -1361,6 +1361,8 @@ int brcmf_attach(struct device *dev)
++@@ -1363,6 +1363,8 @@ int brcmf_attach(struct device *dev)
   
   	/* Link to bus module */
   	drvr->hdrlen = 0;
@@ -2405,7 +3653,7 @@ index 25a12c783e..a5efc08015 100644
   	/* Attach and link in the protocol */
   	ret = brcmf_proto_attach(drvr);
 -@@ -1438,6 +1440,12 @@ void brcmf_detach(struct device *dev)
-+@@ -1443,6 +1445,12 @@ void brcmf_detach(struct device *dev)
++@@ -1445,6 +1447,12 @@ void brcmf_detach(struct device *dev)
   	if (drvr == NULL)
   		return;
   
@@ -2477,7 +3725,7 @@ index d5253063ce..0000000000
 - #include_next <linux/rfkill.h>
 - #else
 diff --git a/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch b/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch
-index ff2ce2071f..19a60d7956 100644
+index ff2ce2071f..089ff2117b 100644
 --- a/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch
 +++ b/package/kernel/mac80211/patches/build/060-no_local_ssb_bcma.patch
 @@ -1,9 +1,9 @@
@@ -2485,7 +3733,7 @@ index ff2ce2071f..19a60d7956 100644
  +++ b/local-symbols
 -@@ -437,43 +437,6 @@ USB_SIERRA_NET=
 - USB_VL600=
-+@@ -428,43 +428,6 @@ USB_VL600=
++@@ -451,43 +451,6 @@ USB_VL600=
   USB_NET_CH9200=
   USB_NET_AQC111=
 + USB_RTL8153_ECM=
@@ -2498,7 +3746,7 @@ index ff2ce2071f..19a60d7956 100644
  +++ b/Kconfig.local
 -@@ -1315,117 +1315,6 @@ config BACKPORTED_USB_NET_CH9200
 - config BACKPORTED_USB_NET_AQC111
-+@@ -1288,117 +1288,6 @@ config BACKPORTED_USB_NET_AQC111
++@@ -1357,117 +1357,6 @@ config BACKPORTED_USB_NET_AQC111
 + config BACKPORTED_USB_RTL8153_ECM
   	tristate
 - 	default USB_NET_AQC111
@@ -2511,7 +3759,7 @@ index ff2ce2071f..19a60d7956 100644
  --- a/Kconfig.sources
  +++ b/Kconfig.sources
 -@@ -7,9 +7,6 @@ source "$BACKPORT_DIR/net/mac80211/Kconf
-+@@ -9,9 +9,6 @@ source "$BACKPORT_DIR/drivers/bus/mhi/Kc
++@@ -10,9 +10,6 @@ source "$BACKPORT_DIR/drivers/soc/qcom/K
   source "$BACKPORT_DIR/drivers/net/wireless/Kconfig"
   source "$BACKPORT_DIR/drivers/net/usb/Kconfig"
   
@@ -2522,12 +3770,28 @@ index ff2ce2071f..19a60d7956 100644
 -@@ -40,8 +40,6 @@ obj-y += compat/
 - obj-$(CPTCFG_CFG80211) += net/wireless/
 - obj-$(CPTCFG_MAC80211) += net/mac80211/
-+@@ -42,8 +42,6 @@ obj-$(CPTCFG_MAC80211) += net/mac80211/
-+ obj-$(CPTCFG_QRTR) += net/qrtr/
++@@ -43,8 +43,6 @@ obj-$(CPTCFG_QRTR) += net/qrtr/
++ obj-$(CPTCFG_QCOM_QMI_HELPERS) += drivers/soc/qcom/
 + obj-$(CPTCFG_MHI_BUS) += drivers/bus/mhi/
   obj-$(CPTCFG_WLAN) += drivers/net/wireless/
  -obj-$(CPTCFG_SSB) += drivers/ssb/
  -obj-$(CPTCFG_BCMA) += drivers/bcma/
+diff --git a/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch b/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch
+new file mode 100644
+index 0000000000..77b6e1de1c
+--- /dev/null
++++ b/package/kernel/mac80211/patches/build/070-remove-broken-wext-select.patch
+@@ -0,0 +1,10 @@
++--- a/drivers/staging/rtl8723bs/Kconfig
+++++ b/drivers/staging/rtl8723bs/Kconfig
++@@ -5,7 +5,6 @@ config RTL8723BS
++ 	depends on m
++ 	depends on WLAN && MMC && CFG80211
++ 	depends on m
++-	select CFG80211_WEXT
++ 	select BPAUTO_CRYPTO_LIB_ARC4
++ 	help
++ 	This option enables support for RTL8723BS SDIO drivers, such as
 diff --git a/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch b/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch
 index d358cfe367..140949f9a8 100644
 --- a/package/kernel/mac80211/patches/mwl/700-mwl8k-missing-pci-id-for-WNR854T.patch
@@ -2540,8 +3804,55 @@ index d358cfe367..140949f9a8 100644
   MODULE_FIRMWARE(MWL8K_8366_AP_FW(MWL8K_8366_AP_FW_API));
   
   static const struct pci_device_id mwl8k_pci_id_table[] = {
-diff --git a/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch
-index a35cf1875a..96b1ce77e9 100644
+diff --git a/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch b/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch
+new file mode 100644
+index 0000000000..4115eeccbb
+--- /dev/null
++++ b/package/kernel/mac80211/patches/mwl/900-mwifiex-increase-the-global-limit-up-to-4-SSID.patch
+@@ -0,0 +1,41 @@
++From ef8098cd6cb8b5989afef2e8461fe6ba9570a854 Mon Sep 17 00:00:00 2001
++From: Josef Schlehofer <pepe.schlehofer@gmail.com>
++Date: Wed, 24 Nov 2021 12:47:40 +0100
++Subject: [PATCH] mwifiex: increase the global limit up to 4 SSID
++
++Firmware for SDIO (88W8997), which is used in Turris MOX SDIO addon [1],
++allows up to 4 SSID. Unfortunately, driver (even in mainline kernel)
++has a global limit for all Marvell cards up to 3 SSID.
++
++Pali Rohár tested this patch and verified that the SDIO Wi-Fi addon works
++with the 4 SSID. So, let's increase the global limit from 3 to 4.
++
++Ideally, this patch should be done differently before sending
++it to Linux kernel. It means that limit definition should be moved to
++the card-specific structure.
++
++[1] https://docs.turris.cz/hw/mox/addons/#wi-fi-sdio
++---
++ drivers/net/wireless/marvell/mwifiex/decl.h | 4 ++--
++ 1 file changed, 2 insertions(+), 2 deletions(-)
++
++--- a/drivers/net/wireless/marvell/mwifiex/decl.h
+++++ b/drivers/net/wireless/marvell/mwifiex/decl.h
++@@ -30,7 +30,7 @@
++ #include <net/cfg80211.h>
++ 
++ #define MWIFIEX_BSS_COEX_COUNT	     2
++-#define MWIFIEX_MAX_BSS_NUM         (3)
+++#define MWIFIEX_MAX_BSS_NUM         (4)
++ 
++ #define MWIFIEX_DMA_ALIGN_SZ	    64
++ #define MWIFIEX_RX_HEADROOM	    64
++@@ -112,7 +112,7 @@
++ #define MWIFIEX_RATE_INDEX_OFDM0   4
++ 
++ #define MWIFIEX_MAX_STA_NUM		3
++-#define MWIFIEX_MAX_UAP_NUM		3
+++#define MWIFIEX_MAX_UAP_NUM		4
++ #define MWIFIEX_MAX_P2P_NUM		3
++ 
++ #define MWIFIEX_A_BAND_START_FREQ	5000
+diff --git a/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch b/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch
+index a35cf1875a..96b1ce77e9 100644
 --- a/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch
 +++ b/package/kernel/mac80211/patches/mwl/940-mwl8k_init_devices_synchronously.patch
 @@ -1,6 +1,6 @@
@@ -2561,578 +3872,3298 @@ index a35cf1875a..96b1ce77e9 100644
   		return;
   	priv = hw->priv;
   
+diff --git a/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch b/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch
+new file mode 100644
+index 0000000000..8fa3924e60
+--- /dev/null
++++ b/package/kernel/mac80211/patches/mwl/950-mwifiex-Print-stringified-name-of-command-in-error-l.patch
+@@ -0,0 +1,189 @@
++From f7252b1b5755150535af226e806594bbefd45e0f Mon Sep 17 00:00:00 2001
++From: =?UTF-8?q?Pali=20Roh=C3=A1r?= <pali@kernel.org>
++Date: Sun, 26 Sep 2021 14:39:44 +0200
++Subject: [PATCH] mwifiex: Print stringified name of command in error log
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++Failed hex command number in error log is hard to understand.
++So add also more human readable stringified command name into error log.
++
++Signed-off-by: Pali Rohár <pali@kernel.org>
++---
++ drivers/net/wireless/marvell/mwifiex/cmdevt.c | 96 +++++++++++++++++--
++ drivers/net/wireless/marvell/mwifiex/main.h   |  2 +
++ .../wireless/marvell/mwifiex/sta_cmdresp.c    |  5 +-
++ .../net/wireless/marvell/mwifiex/uap_cmd.c    |  3 +-
++ 4 files changed, 95 insertions(+), 11 deletions(-)
++
++--- a/drivers/net/wireless/marvell/mwifiex/cmdevt.c
+++++ b/drivers/net/wireless/marvell/mwifiex/cmdevt.c
++@@ -28,6 +28,85 @@
++ 
++ static void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
++ 
+++const char *
+++mwifiex_cmd_to_str(u16 command)
+++{
+++	switch (command) {
+++	case HostCmd_CMD_GET_HW_SPEC:			return "GET_HW_SPEC";
+++	case HostCmd_CMD_802_11_SCAN:			return "SCAN";
+++	case HostCmd_CMD_802_11_GET_LOG:		return "GET_LOG";
+++	case HostCmd_CMD_MAC_MULTICAST_ADR:		return "MAC_MULTICAST_ADR";
+++	case HostCmd_CMD_802_11_EEPROM_ACCESS:		return "EEPROM_ACCESS";
+++	case HostCmd_CMD_802_11_ASSOCIATE:		return "ASSOCIATE";
+++	case HostCmd_CMD_802_11_SNMP_MIB:		return "SNMP_MIB";
+++	case HostCmd_CMD_MAC_REG_ACCESS:		return "MAC_REG_ACCESS";
+++	case HostCmd_CMD_BBP_REG_ACCESS:		return "BBP_REG_ACCESS";
+++	case HostCmd_CMD_RF_REG_ACCESS:			return "RF_REG_ACCESS";
+++	case HostCmd_CMD_PMIC_REG_ACCESS:		return "PMIC_REG_ACCESS";
+++	case HostCmd_CMD_RF_TX_PWR:			return "RF_TX_PWR";
+++	case HostCmd_CMD_RF_ANTENNA:			return "RF_ANTENNA";
+++	case HostCmd_CMD_802_11_DEAUTHENTICATE:		return "DEAUTHENTICATE";
+++	case HostCmd_CMD_MAC_CONTROL:			return "MAC_CONTROL";
+++	case HostCmd_CMD_802_11_AD_HOC_START:		return "AD_HOC_START";
+++	case HostCmd_CMD_802_11_AD_HOC_JOIN:		return "AD_HOC_JOIN";
+++	case HostCmd_CMD_802_11_AD_HOC_STOP:		return "AD_HOC_STOP";
+++	case HostCmd_CMD_802_11_MAC_ADDRESS:		return "MAC_ADDRESS";
+++	case HostCmd_CMD_802_11D_DOMAIN_INFO:		return "DOMAIN_INFO";
+++	case HostCmd_CMD_802_11_KEY_MATERIAL:		return "KEY_MATERIAL";
+++	case HostCmd_CMD_802_11_BG_SCAN_CONFIG:		return "BG_SCAN_CONFIG";
+++	case HostCmd_CMD_802_11_BG_SCAN_QUERY:		return "BG_SCAN_QUERY";
+++	case HostCmd_CMD_WMM_GET_STATUS:		return "WMM_GET_STATUS";
+++	case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:	return "SUBSCRIBE_EVENT";
+++	case HostCmd_CMD_802_11_TX_RATE_QUERY:		return "TX_RATE_QUERY";
+++	case HostCmd_CMD_802_11_IBSS_COALESCING_STATUS:	return "IBSS_COALESCING_STATUS";
+++	case HostCmd_CMD_MEM_ACCESS:			return "MEM_ACCESS";
+++	case HostCmd_CMD_CFG_DATA:			return "CFG_DATA";
+++	case HostCmd_CMD_VERSION_EXT:			return "VERSION_EXT";
+++	case HostCmd_CMD_MEF_CFG:			return "MEF_CFG";
+++	case HostCmd_CMD_RSSI_INFO:			return "RSSI_INFO";
+++	case HostCmd_CMD_FUNC_INIT:			return "FUNC_INIT";
+++	case HostCmd_CMD_FUNC_SHUTDOWN:			return "FUNC_SHUTDOWN";
+++	case HOST_CMD_APCMD_SYS_RESET:			return "SYS_RESET";
+++	case HostCmd_CMD_UAP_SYS_CONFIG:		return "UAP_SYS_CONFIG";
+++	case HostCmd_CMD_UAP_BSS_START:			return "UAP_BSS_START";
+++	case HostCmd_CMD_UAP_BSS_STOP:			return "UAP_BSS_STOP";
+++	case HOST_CMD_APCMD_STA_LIST:			return "STA_LIST";
+++	case HostCmd_CMD_UAP_STA_DEAUTH:		return "UAP_STA_DEAUTH";
+++	case HostCmd_CMD_11N_CFG:			return "11N_CFG";
+++	case HostCmd_CMD_11N_ADDBA_REQ:			return "ADDBA_REQ";
+++	case HostCmd_CMD_11N_ADDBA_RSP:			return "ADDBA_RSP";
+++	case HostCmd_CMD_11N_DELBA:			return "DELBA";
+++	case HostCmd_CMD_RECONFIGURE_TX_BUFF:		return "RECONFIGURE_TX_BUFF";
+++	case HostCmd_CMD_CHAN_REPORT_REQUEST:		return "CHAN_REPORT_REQUEST";
+++	case HostCmd_CMD_AMSDU_AGGR_CTRL:		return "AMSDU_AGGR_CTRL";
+++	case HostCmd_CMD_TXPWR_CFG:			return "TXPWR_CFG";
+++	case HostCmd_CMD_TX_RATE_CFG:			return "TX_RATE_CFG";
+++	case HostCmd_CMD_ROBUST_COEX:			return "ROBUST_COEX";
+++	case HostCmd_CMD_802_11_PS_MODE_ENH:		return "PS_MODE_ENH";
+++	case HostCmd_CMD_802_11_HS_CFG_ENH:		return "HS_CFG_ENH";
+++	case HostCmd_CMD_P2P_MODE_CFG:			return "P2P_MODE_CFG";
+++	case HostCmd_CMD_CAU_REG_ACCESS:		return "CAU_REG_ACCESS";
+++	case HostCmd_CMD_SET_BSS_MODE:			return "SET_BSS_MODE";
+++	case HostCmd_CMD_PCIE_DESC_DETAILS:		return "PCIE_DESC_DETAILS";
+++	case HostCmd_CMD_802_11_SCAN_EXT:		return "SCAN_EXT";
+++	case HostCmd_CMD_COALESCE_CFG:			return "COALESCE_CFG";
+++	case HostCmd_CMD_MGMT_FRAME_REG:		return "MGMT_FRAME_REG";
+++	case HostCmd_CMD_REMAIN_ON_CHAN:		return "REMAIN_ON_CHAN";
+++	case HostCmd_CMD_GTK_REKEY_OFFLOAD_CFG:		return "GTK_REKEY_OFFLOAD_CFG";
+++	case HostCmd_CMD_11AC_CFG:			return "11AC_CFG";
+++	case HostCmd_CMD_HS_WAKEUP_REASON:		return "HS_WAKEUP_REASON";
+++	case HostCmd_CMD_TDLS_CONFIG:			return "TDLS_CONFIG";
+++	case HostCmd_CMD_MC_POLICY:			return "MC_POLICY";
+++	case HostCmd_CMD_TDLS_OPER:			return "TDLS_OPER";
+++	case HostCmd_CMD_FW_DUMP_EVENT:			return "FW_DUMP_EVENT";
+++	case HostCmd_CMD_SDIO_SP_RX_AGGR_CFG:		return "SDIO_SP_RX_AGGR_CFG";
+++	case HostCmd_CMD_STA_CONFIGURE:			return "STA_CONFIGURE";
+++	case HostCmd_CMD_CHAN_REGION_CFG:		return "CHAN_REGION_CFG";
+++	case HostCmd_CMD_PACKET_AGGR_CTRL:		return "PACKET_AGGR_CTRL";
+++	default:					return "UNKNOWN";
+++	}
+++}
+++
++ /*
++  * This function initializes a command node.
++  *
++@@ -205,8 +284,8 @@ static int mwifiex_dnld_cmd_to_fw(struct
++ 	    cmd_code != HostCmd_CMD_FUNC_SHUTDOWN &&
++ 	    cmd_code != HostCmd_CMD_FUNC_INIT) {
++ 		mwifiex_dbg(adapter, ERROR,
++-			    "DNLD_CMD: FW in reset state, ignore cmd %#x\n",
++-			cmd_code);
+++			    "DNLD_CMD: FW in reset state, ignore cmd %s (%#x)\n",
+++			    mwifiex_cmd_to_str(cmd_code), cmd_code);
++ 		mwifiex_recycle_cmd_node(adapter, cmd_node);
++ 		queue_work(adapter->workqueue, &adapter->main_work);
++ 		return -1;
++@@ -660,8 +739,8 @@ int mwifiex_send_cmd(struct mwifiex_priv
++ 	/* Return error, since the command preparation failed */
++ 	if (ret) {
++ 		mwifiex_dbg(adapter, ERROR,
++-			    "PREP_CMD: cmd %#x preparation failed\n",
++-			cmd_no);
+++			    "PREP_CMD: cmd %s (%#x) preparation failed\n",
+++			    mwifiex_cmd_to_str(cmd_no), cmd_no);
++ 		mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
++ 		return -1;
++ 	}
++@@ -900,8 +979,9 @@ int mwifiex_process_cmdresp(struct mwifi
++ 	if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING) {
++ 		if (ret) {
++ 			mwifiex_dbg(adapter, ERROR,
++-				    "%s: cmd %#x failed during\t"
++-				    "initialization\n", __func__, cmdresp_no);
+++				    "%s: cmd %s (%#x) failed during\t"
+++				    "initialization\n", __func__,
+++				    mwifiex_cmd_to_str(cmdresp_no), cmdresp_no);
++ 			mwifiex_init_fw_complete(adapter);
++ 			return -1;
++ 		} else if (adapter->last_init_cmd == cmdresp_no)
++@@ -1264,8 +1344,8 @@ mwifiex_process_sleep_confirm_resp(struc
++ 
++ 	if (command != HostCmd_CMD_802_11_PS_MODE_ENH) {
++ 		mwifiex_dbg(adapter, ERROR,
++-			    "%s: rcvd unexpected resp for cmd %#x, result = %x\n",
++-			    __func__, command, result);
+++			    "%s: rcvd unexpected resp for cmd %s (%#x), result = %x\n",
+++			    __func__, mwifiex_cmd_to_str(command), command, result);
++ 		return;
++ 	}
++ 
++--- a/drivers/net/wireless/marvell/mwifiex/main.h
+++++ b/drivers/net/wireless/marvell/mwifiex/main.h
++@@ -1106,6 +1106,8 @@ void mwifiex_cancel_all_pending_cmd(stru
++ void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter);
++ void mwifiex_cancel_scan(struct mwifiex_adapter *adapter);
++ 
+++const char *mwifiex_cmd_to_str(u16 command);
+++
++ void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
++ 			      struct cmd_ctrl_node *cmd_node);
++ 
++--- a/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
+++++ b/drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
++@@ -48,8 +48,9 @@ mwifiex_process_cmdresp_error(struct mwi
++ 	struct host_cmd_ds_802_11_ps_mode_enh *pm;
++ 
++ 	mwifiex_dbg(adapter, ERROR,
++-		    "CMD_RESP: cmd %#x error, result=%#x\n",
++-		    resp->command, resp->result);
+++		    "CMD_RESP: cmd %s (%#x) error, result=%#x\n",
+++		    mwifiex_cmd_to_str(le16_to_cpu(resp->command)),
+++		    le16_to_cpu(resp->command), le16_to_cpu(resp->result));
++ 
++ 	if (adapter->curr_cmd->wait_q_enabled)
++ 		adapter->cmd_wait_q.status = -1;
++--- a/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
+++++ b/drivers/net/wireless/marvell/mwifiex/uap_cmd.c
++@@ -806,7 +806,8 @@ int mwifiex_uap_prepare_cmd(struct mwifi
++ 		break;
++ 	default:
++ 		mwifiex_dbg(priv->adapter, ERROR,
++-			    "PREP_CMD: unknown cmd %#x\n", cmd_no);
+++			    "PREP_CMD: unknown cmd (%s) %#x\n",
+++			    mwifiex_cmd_to_str(cmd_no), cmd_no);
++ 		return -1;
++ 	}
++ 
+diff --git a/package/kernel/mac80211/patches/rt2x00/001-rt2x00-define-RF5592-in-init_eeprom-routine.patch b/package/kernel/mac80211/patches/rt2x00/001-rt2x00-define-RF5592-in-init_eeprom-routine.patch
+new file mode 100644
+index 0000000000..351e24a4d5
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/001-rt2x00-define-RF5592-in-init_eeprom-routine.patch
+@@ -0,0 +1,52 @@
++From patchwork Sat Sep 17 20:26:27 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979242
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:26:27 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 01/16] rt2x00: define RF5592 in init_eeprom routine
++Message-ID: 
++ <d7eccb2c7b8ec4cd360fa2007796abffc35abb0d.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Fix incorrect RF value encoded in EEPROM on devices with Ralink Rt5592
++PCIe radio (a single chip 2T2R 802.11abgn solution).
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 ++
++ 1 file changed, 2 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -9435,6 +9435,8 @@ static int rt2800_init_eeprom(struct rt2
++ 		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);
++ 
+diff --git a/package/kernel/mac80211/patches/rt2x00/002-rt2x00-add-throughput-LED-trigger.patch b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-add-throughput-LED-trigger.patch
+new file mode 100644
+index 0000000000..02d1f7a2e5
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-add-throughput-LED-trigger.patch
+@@ -0,0 +1,76 @@
++From patchwork Sat Sep 17 20:26:40 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979243
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:26:40 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 02/16] rt2x00: add throughput LED trigger
++Message-ID: 
++ <73f5ba4134e621462a26186449400cf0c1ac1730.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: David Bauer <mail@david-bauer.net>
++
++This adds a (currently missing) throughput LED trigger for the rt2x00
++driver. Previously, LED triggers had to be assigned to the netdev, which
++was limited to a single VAP.
++
++Tested-by: Christoph Krapp <achterin@googlemail.com>
++Signed-off-by: David Bauer <mail@david-bauer.net>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2x00dev.c | 18 ++++++++++++++++++
++ 1 file changed, 18 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
++@@ -1093,6 +1093,19 @@ static void rt2x00lib_remove_hw(struct r
++ 	kfree(rt2x00dev->spec.channels_info);
++ }
++ 
+++static const struct ieee80211_tpt_blink rt2x00_tpt_blink[] = {
+++	{ .throughput = 0 * 1024, .blink_time = 334 },
+++	{ .throughput = 1 * 1024, .blink_time = 260 },
+++	{ .throughput = 2 * 1024, .blink_time = 220 },
+++	{ .throughput = 5 * 1024, .blink_time = 190 },
+++	{ .throughput = 10 * 1024, .blink_time = 170 },
+++	{ .throughput = 25 * 1024, .blink_time = 150 },
+++	{ .throughput = 54 * 1024, .blink_time = 130 },
+++	{ .throughput = 120 * 1024, .blink_time = 110 },
+++	{ .throughput = 265 * 1024, .blink_time = 80 },
+++	{ .throughput = 586 * 1024, .blink_time = 50 },
+++};
+++
++ static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
++ {
++ 	struct hw_mode_spec *spec = &rt2x00dev->spec;
++@@ -1174,6 +1187,11 @@ static int rt2x00lib_probe_hw(struct rt2
++ 
++ #undef RT2X00_TASKLET_INIT
++ 
+++	ieee80211_create_tpt_led_trigger(rt2x00dev->hw,
+++					 IEEE80211_TPT_LEDTRIG_FL_RADIO,
+++					 rt2x00_tpt_blink,
+++					 ARRAY_SIZE(rt2x00_tpt_blink));
+++
++ 	/*
++ 	 * Register HW.
++ 	 */
 diff --git a/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
-index a50a195285..96eeb37dc6 100644
+deleted file mode 100644
+index a50a195285..0000000000
 --- a/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/002-rt2x00-define-RF5592-in-init_eeprom-routine.patch
-@@ -40,7 +40,7 @@ Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
- 
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++++ /dev/null
+@@ -1,51 +0,0 @@
+-From patchwork Thu Dec 27 14:05:26 2018
+-Content-Type: text/plain; charset="utf-8"
+-MIME-Version: 1.0
+-Content-Transfer-Encoding: 8bit
+-X-Patchwork-Submitter: Tom Psyborg <pozega.tomislav@gmail.com>
+-X-Patchwork-Id: 10743707
+-X-Patchwork-Delegate: kvalo@adurom.com
+-From: =?utf-8?q?Tomislav_Po=C5=BEega?= <pozega.tomislav@gmail.com>
+-To: linux-wireless@vger.kernel.org
+-Cc: kvalo@codeaurora.org, hauke@hauke-m.de, nbd@nbd.name,
+-        john@phrozen.org, sgruszka@redhat.com, daniel@makrotopia.org
+-Subject: [PATCH 2/2] rt2x00: define RF5592 in init_eeprom routine
+-Date: Thu, 27 Dec 2018 15:05:26 +0100
+-Message-Id: <1545919526-4074-2-git-send-email-pozega.tomislav@gmail.com>
+-X-Mailer: git-send-email 1.7.0.4
+-In-Reply-To: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
+-References: <1545919526-4074-1-git-send-email-pozega.tomislav@gmail.com>
+-MIME-Version: 1.0
+-Sender: linux-wireless-owner@vger.kernel.org
+-Precedence: bulk
+-List-ID: <linux-wireless.vger.kernel.org>
+-X-Mailing-List: linux-wireless@vger.kernel.org
+-X-Virus-Scanned: ClamAV using ClamSMTP
+-
+-This patch fixes following crash on Linksys EA2750 during 5GHz wifi
+-init:
+-
+-[    7.955153] rt2800pci 0000:01:00.0: card - bus=0x1, slot = 0x0 irq=4
+-[    7.962259] rt2800pci 0000:01:00.0: loaded eeprom from mtd device "Factory"
+-[    7.969435] ieee80211 phy0: rt2x00_set_rt: Info - RT chipset 5592, rev 0222 detected
+-[    7.977348] ieee80211 phy0: rt2800_init_eeprom: Error - Invalid RF chipset 0x0000 detected
+-[    7.985793] ieee80211 phy0: rt2x00lib_probe_dev: Error - Failed to allocate device
+-[    7.993569] CPU 0 Unable to handle kernel paging request at virtual address 00000024, epc == 800c8f54, ra == 80249ff8
+-[    8.004408] Oops[#1]:
+-
+-Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
+----
+- drivers/net/wireless/ralink/rt2x00/rt2800lib.c |    2 ++
+- 1 files changed, 2 insertions(+), 0 deletions(-)
+-
+---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 -@@ -9416,6 +9416,8 @@ static int rt2800_init_eeprom(struct rt2
-+@@ -9435,6 +9435,8 @@ static int rt2800_init_eeprom(struct rt2
-  		rf = RF3853;
-  	else if (rt2x00_rt(rt2x00dev, RT5350))
-  		rf = RF5350;
-diff --git a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
-index e74d9a9aa0..afe8cea205 100644
---- a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
-@@ -1,6 +1,6 @@
- --- a/local-symbols
- +++ b/local-symbols
--@@ -332,6 +332,7 @@ RT2X00_LIB_FIRMWARE=
-+@@ -322,6 +322,7 @@ RT2X00_LIB_FIRMWARE=
-  RT2X00_LIB_CRYPTO=
-  RT2X00_LIB_LEDS=
-  RT2X00_LIB_DEBUGFS=
-@@ -105,7 +105,7 @@
-  	.drv_init_registers	= rt2800mmio_init_registers,
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
--@@ -694,6 +694,7 @@ enum rt2x00_capability_flags {
-+@@ -703,6 +703,7 @@ enum rt2x00_capability_flags {
-  	REQUIRE_HT_TX_DESC,
-  	REQUIRE_PS_AUTOWAKE,
-  	REQUIRE_DELAYED_RFKILL,
-@@ -113,7 +113,7 @@
-  
-  	/*
-  	 * Capabilities
--@@ -970,6 +971,11 @@ struct rt2x00_dev {
-+@@ -980,6 +981,11 @@ struct rt2x00_dev {
-  	const struct firmware *fw;
-  
-  	/*
-@@ -127,7 +127,7 @@
-  	DECLARE_KFIFO_PTR(txstatus_fifo, u32);
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1406,6 +1406,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
-+@@ -1401,6 +1401,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
-  	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
-  	INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
-  
-@@ -138,7 +138,7 @@
-  	/*
-  	 * Let the driver probe the device to detect the capabilities.
-  	 */
--@@ -1549,6 +1553,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
-+@@ -1541,6 +1545,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
-  	 * Free the driver data.
-  	 */
-  	kfree(rt2x00dev->drv_data);
-diff --git a/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
-index 6a8e594d5e..ffee2189d2 100644
---- a/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
-@@ -12,7 +12,7 @@
-  #endif /* _RT2X00_PLATFORM_H */
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1012,6 +1012,22 @@ static int rt2x00lib_probe_hw_modes(stru
-+@@ -1007,6 +1007,22 @@ static int rt2x00lib_probe_hw_modes(stru
-  	unsigned int num_rates;
-  	unsigned int i;
-  
-@@ -37,7 +37,7 @@
-  		num_rates += 4;
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
--@@ -399,6 +399,7 @@ struct hw_mode_spec {
-+@@ -408,6 +408,7 @@ struct hw_mode_spec {
-  	unsigned int supported_bands;
-  #define SUPPORT_BAND_2GHZ	0x00000001
-  #define SUPPORT_BAND_5GHZ	0x00000002
-diff --git a/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
-index b5b2c61037..37553bb80a 100644
---- a/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
-@@ -1,19 +1,18 @@
- --- 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 ieee80
-+@@ -989,6 +989,12 @@ static void rt2x00lib_rate(struct ieee80
-  
-  void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
-  {
- +	struct rt2x00_platform_data *pdata;
-- 	const char *mac_addr;
+- 		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);
 - 
-++
- +	pdata = rt2x00dev->dev->platform_data;
- +	if (pdata && pdata->mac_address)
- +		ether_addr_copy(eeprom_mac_addr, pdata->mac_address);
- +
-- 	mac_addr = of_get_mac_address(rt2x00dev->dev->of_node);
-- 	if (!IS_ERR(mac_addr))
-- 		ether_addr_copy(eeprom_mac_addr, mac_addr);
-+ 	of_get_mac_address(rt2x00dev->dev->of_node, eeprom_mac_addr);
-+ 
-+ 	if (!is_valid_ether_addr(eeprom_mac_addr)) {
- --- a/include/linux/rt2x00_platform.h
- +++ b/include/linux/rt2x00_platform.h
- @@ -14,6 +14,7 @@
-diff --git a/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
-index ff8b2c947b..6211809c0a 100644
---- a/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
-@@ -1,6 +1,6 @@
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1016,6 +1016,16 @@ static int rt2x00lib_probe_hw_modes(stru
-+@@ -1012,6 +1012,16 @@ static int rt2x00lib_probe_hw_modes(stru
-  	struct ieee80211_rate *rates;
-  	unsigned int num_rates;
-  	unsigned int i;
-diff --git a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
-index 039c6f6afc..d78b76d7f5 100644
---- a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
-@@ -8,7 +8,7 @@
-  
-  #include "rt2x00.h"
-  #include "rt2800lib.h"
--@@ -9530,6 +9531,17 @@ static int rt2800_init_eeprom(struct rt2
-+@@ -9549,6 +9550,17 @@ static int rt2800_init_eeprom(struct rt2
-  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
-  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
-  
-diff --git a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
-index 88d6dd559b..0da9356e0c 100644
---- a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
-@@ -1,6 +1,6 @@
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1344,7 +1344,7 @@ static inline void rt2x00lib_set_if_comb
-+@@ -1340,7 +1340,7 @@ static inline void rt2x00lib_set_if_comb
-  	 */
-  	if_limit = &rt2x00dev->if_limits_ap;
-  	if_limit->max = rt2x00dev->ops->max_ap_intf;
-diff --git a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
-index fca1fb2cd4..6e6564f870 100644
---- a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
-@@ -11,7 +11,7 @@ Tested-by: Christoph Krapp <achterin@googlemail.com>
+diff --git a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/003-rt2x00-add-support-for-external-PA-on-MT7620.patch
+similarity index 58%
+rename from package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
+rename to package/kernel/mac80211/patches/rt2x00/003-rt2x00-add-support-for-external-PA-on-MT7620.patch
+index 20452cd8a7..216f583063 100644
+--- a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
++++ b/package/kernel/mac80211/patches/rt2x00/003-rt2x00-add-support-for-external-PA-on-MT7620.patch
+@@ -1,22 +1,42 @@
+-From 9782a7f7488443568fa4d6088b73c9aff7eb8510 Mon Sep 17 00:00:00 2001
++From patchwork Sat Sep 17 20:26:55 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979244
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:26:55 +0100
+ From: Daniel Golle <daniel@makrotopia.org>
+-Date: Wed, 19 Apr 2017 16:14:53 +0200
+-Subject: [PATCH] rt2x00: add support for external PA on MT7620
+-To: Stanislaw Gruszka <sgruszka@redhat.com>
+-Cc: Helmut Schaa <helmut.schaa@googlemail.com>,
+-    linux-wireless@vger.kernel.org,
+-    Kalle Valo <kvalo@codeaurora.org>
+-Content-Type: text/plain; charset="UTF-8"
+-Content-Transfer-Encoding: quoted-printable
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 03/16] rt2x00: add support for external PA on MT7620
++Message-ID: 
++ <af2c68ff831816a86fc39b0c10911c129a1f03dc.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
  
- --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1129,6 +1129,19 @@ static void rt2x00lib_remove_hw(struct r
-+@@ -1125,6 +1125,19 @@ static void rt2x00lib_remove_hw(struct r
-  	kfree(rt2x00dev->spec.channels_info);
-  }
-  
-@@ -31,7 +31,7 @@ Tested-by: Christoph Krapp <achterin@googlemail.com>
-  static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
-  {
-  	struct hw_mode_spec *spec = &rt2x00dev->spec;
--@@ -1210,6 +1223,10 @@ static int rt2x00lib_probe_hw(struct rt2
-+@@ -1206,6 +1219,10 @@ static int rt2x00lib_probe_hw(struct rt2
-  
-  #undef RT2X00_TASKLET_INIT
+-Signed-off-by: Daniel Golle <daniel@makrotopia.org>
+-Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+-[pozega.tomislav@gmail.com: use chanreg and dccal helpers.]
++Implement support for external PA connected to MT7620A.
+ 
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++[pozega.tomislav@gmail.com: use chanreg and dccal helpers.]
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
+ ---
+- drivers/net/wireless/ralink/rt2x00/rt2800.h    |  1 +
+- drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 70 +++++++++++++++++++++++++-
+- 2 files changed, 70 insertions(+), 1 deletion(-)
++ drivers/net/wireless/ralink/rt2x00/rt2800.h   |  1 +
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 52 ++++++++++++++++++-
++ 2 files changed, 52 insertions(+), 1 deletion(-)
+ 
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
+@@ -24,21 +44,19 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+  #define EEPROM_NIC_CONF2_RX_STREAM	FIELD16(0x000f)
+  #define EEPROM_NIC_CONF2_TX_STREAM	FIELD16(0x00f0)
+  #define EEPROM_NIC_CONF2_CRYSTAL	FIELD16(0x0600)
+-+#define EEPROM_NIC_CONF2_EXTERNAL_PA	FIELD16(0xc000)
+++#define EEPROM_NIC_CONF2_EXTERNAL_PA	FIELD16(0x8000)
   
-diff --git a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
-index 20452cd8a7..8814c02532 100644
---- a/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/650-rt2x00-add-support-for-external-PA-on-MT7620.patch
-@@ -30,7 +30,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+  /*
    * EEPROM LNA
  --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
  +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 -@@ -4356,6 +4356,45 @@ static void rt2800_config_channel(struct
-+@@ -4369,6 +4369,45 @@ static void rt2800_config_channel(struct
++@@ -4368,6 +4368,43 @@ static void rt2800_config_channel(struct
   		rt2800_iq_calibrate(rt2x00dev, rf->channel);
   	}
   
-@@ -76,7 +76,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+ +	if (rt2x00_rt(rt2x00dev, RT6352)) {
+ +		if (test_bit(CAPABILITY_EXTERNAL_PA_TX0,
+ +			     &rt2x00dev->cap_flags)) {
+-+			rt2x00_warn(rt2x00dev, "Using incomplete support for " \
+-+					       "external PA\n");
+ +			reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
+ +			reg |= 0x00000101;
+ +			rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
+@@ -76,7 +94,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
   	bbp = rt2800_bbp_read(rt2x00dev, 4);
   	rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
   	rt2800_bbp_write(rt2x00dev, 4, bbp);
 -@@ -9559,7 +9598,8 @@ static int rt2800_init_eeprom(struct rt2
-+@@ -9578,7 +9617,8 @@ static int rt2800_init_eeprom(struct rt2
++@@ -9566,7 +9603,8 @@ static int rt2800_init_eeprom(struct rt2
   	 */
   	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF1);
   
-@@ -86,7 +86,7 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
+@@ -86,19 +104,19 @@ Signed-off-by: Tomislav Po=C5=BEega <pozega.tomislav@gmail.com>
   		if (rt2x00_get_field16(eeprom,
   		    EEPROM_NIC_CONF1_EXTERNAL_TX0_PA_3352))
   		    __set_bit(CAPABILITY_EXTERNAL_PA_TX0,
 -@@ -9570,6 +9610,18 @@ static int rt2800_init_eeprom(struct rt2
-+@@ -9589,6 +9629,18 @@ static int rt2800_init_eeprom(struct rt2
++@@ -9577,6 +9615,18 @@ static int rt2800_init_eeprom(struct rt2
   			      &rt2x00dev->cap_flags);
   	}
   
-diff --git a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
-index 6be847478e..b798dcc6d8 100644
---- a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
-@@ -1,6 +1,6 @@
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
--@@ -8419,6 +8419,56 @@ static void rt2800_init_rfcsr_5592(struc
-+@@ -8438,6 +8438,56 @@ static void rt2800_init_rfcsr_5592(struc
-  	rt2800_led_open_drain_enable(rt2x00dev);
-  }
-  
-@@ -57,7 +57,7 @@
-  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
-  				       bool set_bw, bool is_ht40)
-  {
--@@ -9026,6 +9076,7 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -9045,6 +9095,7 @@ static void rt2800_init_rfcsr_6352(struc
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
-  
-diff --git a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
-index 3ed0ff7ef5..cf21c39a6c 100644
---- a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
-@@ -1,6 +1,6 @@
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
--@@ -8469,6 +8469,155 @@ static void rt2800_rf_self_txdc_cal(stru
-+@@ -8488,6 +8488,155 @@ static void rt2800_rf_self_txdc_cal(stru
-  	rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
-  }
-  
-@@ -156,7 +156,7 @@
-  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
-  				       bool set_bw, bool is_ht40)
-  {
--@@ -9076,6 +9225,7 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -9095,6 +9244,7 @@ static void rt2800_init_rfcsr_6352(struc
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
-  
-diff --git a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
-index 77be986d18..1f8684b0bf 100644
---- a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
-@@ -1,6 +1,6 @@
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+ +	eeprom = rt2800_eeprom_read(rt2x00dev, EEPROM_NIC_CONF2);
+ +
+ +	if (rt2x00_rt(rt2x00dev, RT6352) && eeprom != 0 && eeprom != 0xffff) {
+-+		if (rt2x00_get_field16(eeprom,
+-+		    EEPROM_NIC_CONF2_EXTERNAL_PA)) {
+-+		    __set_bit(CAPABILITY_EXTERNAL_PA_TX0,
+-+			      &rt2x00dev->cap_flags);
+-+		    __set_bit(CAPABILITY_EXTERNAL_PA_TX1,
+-+			      &rt2x00dev->cap_flags);
+++		if (!rt2x00_get_field16(eeprom,
+++					EEPROM_NIC_CONF2_EXTERNAL_PA)) {
+++			__clear_bit(CAPABILITY_EXTERNAL_PA_TX0,
+++				    &rt2x00dev->cap_flags);
+++			__clear_bit(CAPABILITY_EXTERNAL_PA_TX1,
+++				    &rt2x00dev->cap_flags);
+ +		}
+ +	}
+ +
+diff --git a/package/kernel/mac80211/patches/rt2x00/004-rt2x00-move-up-and-reuse-busy-wait-functions.patch b/package/kernel/mac80211/patches/rt2x00/004-rt2x00-move-up-and-reuse-busy-wait-functions.patch
+new file mode 100644
+index 0000000000..da453074a1
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/004-rt2x00-move-up-and-reuse-busy-wait-functions.patch
+@@ -0,0 +1,178 @@
++From patchwork Sat Sep 17 20:27:10 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979245
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:27:10 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 04/16] rt2x00: move up and reuse busy wait functions
++Message-ID: 
++ <3fdb9dc15e76a9f9c1948b4a3a1308a7a5677bb8.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Move bbp_ready and rf_ready busy wait functions up in the code so they
++can more easily be used. Allow specifying register mask in rf_ready
++function which is useful for calibration routines which will be added
++in follow-up commits.
++
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 99 +++++++++----------
++ 1 file changed, 46 insertions(+), 53 deletions(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -2143,6 +2143,48 @@ void rt2800_config_erp(struct rt2x00_dev
++ }
++ EXPORT_SYMBOL_GPL(rt2800_config_erp);
++ 
+++static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev,
+++				    const struct rt2x00_field32 mask)
+++{
+++	unsigned int i;
+++	u32 reg;
+++
+++	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+++		reg = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+++		if (!rt2x00_get_field32(reg, mask))
+++			return 0;
+++
+++		udelay(REGISTER_BUSY_DELAY);
+++	}
+++
+++	rt2x00_err(rt2x00dev, "BBP/RF register access failed, aborting\n");
+++	return -EACCES;
+++}
+++
+++static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
+++{
+++	unsigned int i;
+++	u8 value;
+++
+++	/*
+++	 * BBP was enabled after firmware was loaded,
+++	 * but we need to reactivate it now.
+++	 */
+++	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
+++	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
+++	msleep(1);
+++
+++	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
+++		value = rt2800_bbp_read(rt2x00dev, 0);
+++		if ((value != 0xff) && (value != 0x00))
+++			return 0;
+++		udelay(REGISTER_BUSY_DELAY);
+++	}
+++
+++	rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
+++	return -EACCES;
+++}
+++
++ static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev)
++ {
++ 	u32 reg;
++@@ -3799,10 +3841,9 @@ static void rt2800_config_alc(struct rt2
++ 			      struct ieee80211_channel *chan,
++ 			      int power_level) {
++ 	u16 eeprom, target_power, max_power;
++-	u32 mac_sys_ctrl, mac_status;
+++	u32 mac_sys_ctrl;
++ 	u32 reg;
++ 	u8 bbp;
++-	int i;
++ 
++ 	/* hardware unit is 0.5dBm, limited to 23.5dBm */
++ 	power_level *= 2;
++@@ -3838,16 +3879,8 @@ static void rt2800_config_alc(struct rt2
++ 	/* Disable Tx/Rx */
++ 	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0);
++ 	/* Check MAC Tx/Rx idle */
++-	for (i = 0; i < 10000; i++) {
++-		mac_status = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++-		if (mac_status & 0x3)
++-			usleep_range(50, 200);
++-		else
++-			break;
++-	}
++-
++-	if (i == 10000)
++-		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY)))
+++		rt2x00_warn(rt2x00dev, "RF busy while configuring ALC\n");
++ 
++ 	if (chan->center_freq > 2457) {
++ 		bbp = rt2800_bbp_read(rt2x00dev, 30);
++@@ -6249,46 +6282,6 @@ static int rt2800_init_registers(struct
++ 	return 0;
++ }
++ 
++-static int rt2800_wait_bbp_rf_ready(struct rt2x00_dev *rt2x00dev)
++-{
++-	unsigned int i;
++-	u32 reg;
++-
++-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
++-		reg = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
++-		if (!rt2x00_get_field32(reg, MAC_STATUS_CFG_BBP_RF_BUSY))
++-			return 0;
++-
++-		udelay(REGISTER_BUSY_DELAY);
++-	}
++-
++-	rt2x00_err(rt2x00dev, "BBP/RF register access failed, aborting\n");
++-	return -EACCES;
++-}
++-
++-static int rt2800_wait_bbp_ready(struct rt2x00_dev *rt2x00dev)
++-{
++-	unsigned int i;
++-	u8 value;
++-
++-	/*
++-	 * BBP was enabled after firmware was loaded,
++-	 * but we need to reactivate it now.
++-	 */
++-	rt2800_register_write(rt2x00dev, H2M_BBP_AGENT, 0);
++-	rt2800_register_write(rt2x00dev, H2M_MAILBOX_CSR, 0);
++-	msleep(1);
++-
++-	for (i = 0; i < REGISTER_BUSY_COUNT; i++) {
++-		value = rt2800_bbp_read(rt2x00dev, 0);
++-		if ((value != 0xff) && (value != 0x00))
++-			return 0;
++-		udelay(REGISTER_BUSY_DELAY);
++-	}
++-
++-	rt2x00_err(rt2x00dev, "BBP register access failed, aborting\n");
++-	return -EACCES;
++-}
++ 
++ static void rt2800_bbp4_mac_if_ctrl(struct rt2x00_dev *rt2x00dev)
++ {
++@@ -9110,7 +9103,7 @@ int rt2800_enable_radio(struct rt2x00_de
++ 	/*
++ 	 * Wait BBP/RF to wake up.
++ 	 */
++-	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev)))
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY)))
++ 		return -EIO;
++ 
++ 	/*
+diff --git a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/005-rt2x00-add-RF-self-TXDC-calibration-for-MT7620.patch
+similarity index 51%
+rename from package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
+rename to package/kernel/mac80211/patches/rt2x00/005-rt2x00-add-RF-self-TXDC-calibration-for-MT7620.patch
+index 6be847478e..4e98d6a375 100644
+--- a/package/kernel/mac80211/patches/rt2x00/982-rt2x00-add-rf-self-txdc-calibration.patch
++++ b/package/kernel/mac80211/patches/rt2x00/005-rt2x00-add-RF-self-TXDC-calibration-for-MT7620.patch
+@@ -1,6 +1,48 @@
++From patchwork Sat Sep 17 20:27:26 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979246
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:27:26 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 05/16] rt2x00: add RF self TXDC calibration for MT7620
++Message-ID: 
++ <dbb6e5a0c12d6101477bd09e83253091d21512c9.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Add TX self calibration based on mtk driver.
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++v2: use ++i instead of i = i + 1 in loops
++
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 48 +++++++++++++++++++
++ 1 file changed, 48 insertions(+)
++
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-@@ -8419,6 +8419,56 @@ static void rt2800_init_rfcsr_5592(struc
++@@ -8428,6 +8428,53 @@ static void rt2800_init_rfcsr_5592(struc
+  	rt2800_led_open_drain_enable(rt2x00dev);
+  }
+  
+@@ -10,7 +52,6 @@
+ +	u32 mac0518, mac051c, mac0528, mac052c;
+ +	u8 i;
+ +
+-+	rt2x00_info(rt2x00dev, "RF Tx self calibration start\n");
+ +	mac0518 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+ +	mac051c = rt2800_register_read(rt2x00dev, RF_BYPASS0);
+ +	mac0528 = rt2800_register_read(rt2x00dev, RF_CONTROL2);
+@@ -27,19 +68,19 @@
+ +	rfb7r1_org = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
+ +
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, 0x4);
+-+	for (i = 0; i < 100; i = i + 1) {
+-+		udelay(50);
+++	for (i = 0; i < 100; ++i) {
+++		usleep_range(50, 100);
+ +		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 5, 1);
+-+		if((rfvalue & 0x04) != 0x4)
+++		if ((rfvalue & 0x04) != 0x4)
+ +			break;
+ +	}
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 5, 1, rfb5r1_org);
+ +
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, 0x4);
+-+	for (i = 0; i < 100; i = i + 1) {
+-+		udelay(50);
+++	for (i = 0; i < 100; ++i) {
+++		usleep_range(50, 100);
+ +		rfvalue = rt2800_rfcsr_read_bank(rt2x00dev, 7, 1);
+-+		if((rfvalue & 0x04) != 0x4)
+++		if ((rfvalue & 0x04) != 0x4)
+ +			break;
+ +	}
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 7, 1, rfb7r1_org);
+@@ -50,14 +91,12 @@
+ +	rt2800_register_write(rt2x00dev, RF_BYPASS0, mac051c);
+ +	rt2800_register_write(rt2x00dev, RF_CONTROL2, mac0528);
+ +	rt2800_register_write(rt2x00dev, RF_BYPASS2, mac052c);
+-+
+-+	rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
+ +}
+ +
+  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+  				       bool set_bw, bool is_ht40)
+  {
+-@@ -9026,6 +9076,7 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -9035,6 +9082,7 @@ static void rt2800_init_rfcsr_6352(struc
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+  
+diff --git a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch b/package/kernel/mac80211/patches/rt2x00/006-rt2x00-add-r-calibration-for-MT7620.patch
+similarity index 66%
+rename from package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
+rename to package/kernel/mac80211/patches/rt2x00/006-rt2x00-add-r-calibration-for-MT7620.patch
+index 3ed0ff7ef5..7c69970166 100644
+--- a/package/kernel/mac80211/patches/rt2x00/983-rt2x00-add-r-calibration.patch
++++ b/package/kernel/mac80211/patches/rt2x00/006-rt2x00-add-r-calibration-for-MT7620.patch
+@@ -1,14 +1,68 @@
++From patchwork Sat Sep 17 20:27:41 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979247
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:27:41 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 06/16] rt2x00: add r calibration for MT7620
++Message-ID: 
++ <e0c34f233089bec4eb73826bc4f512166ee25934.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Add r calibration code as found in mtk driver.
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++v2: use rt2800_wait_bbp_rf_ready()
++
++ drivers/net/wireless/ralink/rt2x00/rt2800.h   |   2 +
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 133 ++++++++++++++++++
++ 2 files changed, 135 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
++@@ -1016,6 +1016,8 @@
++  */
++ #define MAC_STATUS_CFG			0x1200
++ #define MAC_STATUS_CFG_BBP_RF_BUSY	FIELD32(0x00000003)
+++#define MAC_STATUS_CFG_BBP_RF_BUSY_TX	FIELD32(0x00000001)
+++#define MAC_STATUS_CFG_BBP_RF_BUSY_RX	FIELD32(0x00000002)
++ 
++ /*
++  * PWR_PIN_CFG:
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-@@ -8469,6 +8469,155 @@ static void rt2800_rf_self_txdc_cal(stru
+- 	rt2x00_info(rt2x00dev, "RF Tx self calibration end\n");
++@@ -8475,6 +8475,138 @@ static void rt2800_rf_self_txdc_cal(stru
++ 	rt2800_register_write(rt2x00dev, RF_BYPASS2, mac052c);
+  }
+  
+ +static int rt2800_calcrcalibrationcode(struct rt2x00_dev *rt2x00dev, int d1, int d2)
+ +{
+-+	int calcode;
+-+	calcode = ((d2 - d1) * 1000) / 43;
+-+	if ((calcode%10) >= 5)
+++	int calcode = ((d2 - d1) * 1000) / 43;
+++
+++	if ((calcode % 10) >= 5)
+ +		calcode += 10;
+ +	calcode = (calcode / 10);
+ +
+@@ -28,8 +82,7 @@
+ +	char d1 = 0, d2 = 0;
+ +	u8 rfvalue;
+ +	u32 MAC_RF_BYPASS0, MAC_RF_CONTROL0, MAC_PWR_PIN_CFG;
+-+	u32 maccfg, macstatus;
+-+	int i;
+++	u32 maccfg;
+ +
+ +	saverfb0r1 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 1);
+ +	saverfb0r34 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 34);
+@@ -53,30 +106,14 @@
+ +	maccfg &= (~0x04);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
+ +
+-+	for (i = 0; i < 10000; i++) {
+-+		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macstatus & 0x1)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+-+
+-+	if (i == 10000)
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_TX)))
+ +		rt2x00_warn(rt2x00dev, "Wait MAC Tx Status to MAX !!!\n");
+ +
+ +	maccfg = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	maccfg &= (~0x04);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, maccfg);
+ +
+-+	for (i = 0; i < 10000; i++) {
+-+		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macstatus & 0x2)
+-+			udelay(50);
+-+		else
+-+			break;
+-+		}
+-+
+-+	if (i == 10000)
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_RX)))
+ +		rt2x00_warn(rt2x00dev, "Wait MAC Rx Status to MAX !!!\n");
+ +
+ +	rfvalue = (MAC_RF_BYPASS0 | 0x3004);
+@@ -98,7 +135,7 @@
+ +
+ +	rt2800_bbp_write(rt2x00dev, 47, 0x04);
+ +	rt2800_bbp_write(rt2x00dev, 22, 0x80);
+-+	udelay(100);
+++	usleep_range(100, 200);
+ +	bytevalue = rt2800_bbp_read(rt2x00dev, 49);
+ +	if (bytevalue > 128)
+ +		d1 = bytevalue - 256;
+@@ -108,7 +145,7 @@
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 0, 35, 0x01);
+ +
+ +	rt2800_bbp_write(rt2x00dev, 22, 0x80);
+-+	udelay(100);
+++	usleep_range(100, 200);
+ +	bytevalue = rt2800_bbp_read(rt2x00dev, 49);
+ +	if (bytevalue > 128)
+ +		d2 = bytevalue - 256;
+@@ -156,7 +193,7 @@
+  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+  				       bool set_bw, bool is_ht40)
+  {
+-@@ -9076,6 +9225,7 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -9082,6 +9214,7 @@ static void rt2800_init_rfcsr_6352(struc
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+  
+diff --git a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch b/package/kernel/mac80211/patches/rt2x00/007-rt2x00-add-RXDCOC-calibration-for-MT7620.patch
+similarity index 50%
+rename from package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
+rename to package/kernel/mac80211/patches/rt2x00/007-rt2x00-add-RXDCOC-calibration-for-MT7620.patch
+index 77be986d18..8da41e875a 100644
+--- a/package/kernel/mac80211/patches/rt2x00/984-rt2x00-add-rxdcoc-calibration.patch
++++ b/package/kernel/mac80211/patches/rt2x00/007-rt2x00-add-RXDCOC-calibration-for-MT7620.patch
+@@ -1,13 +1,54 @@
++From patchwork Sat Sep 17 20:27:56 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979248
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:27:56 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 07/16] rt2x00: add RXDCOC calibration for MT7620
++Message-ID: 
++ <850b30f652e88de30d79e968af4eb47aa5bc2511.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Add RXDCOC calibration code from mtk driver.
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++[fixed typo reported by Serge Vasilugin <vasilugin@yandex.ru>]
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 60 +++++++++++++++++++
++ 1 file changed, 60 insertions(+)
++
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
  +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 -@@ -8618,6 +8618,70 @@ static void rt2800_r_calibration(struct
-+@@ -8637,6 +8637,70 @@ static void rt2800_r_calibration(struct
++@@ -8607,6 +8607,65 @@ static void rt2800_r_calibration(struct
   	rt2800_register_write(rt2x00dev, PWR_PIN_CFG, MAC_PWR_PIN_CFG);
   }
   
-@@ -71,7 +71,7 @@
+ +static void rt2800_rxdcoc_calibration(struct rt2x00_dev *rt2x00dev)
+ +{
+ +	u8 bbpreg = 0;
+-+	u32 macvalue = 0, macvalue1 = 0;
+++	u32 macvalue = 0;
+ +	u8 saverfb0r2, saverfb5r4, saverfb7r4, rfvalue;
+ +	int i;
+ +
+@@ -24,15 +65,10 @@
+ +	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x8);
+ +
+-+	for (i = 0; i < 10000; i++) {
+-+		macvalue1 = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macvalue1 & 0x1)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_TX)))
+++		rt2x00_warn(rt2x00dev, "RF TX busy in RX RXDCOC calibration\n");
+ +
+-+	saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 0);
+++	saverfb5r4 = rt2800_rfcsr_read_bank(rt2x00dev, 5, 4);
+ +	saverfb7r4 = rt2800_rfcsr_read_bank(rt2x00dev, 7, 4);
+ +	saverfb5r4 = saverfb5r4 & (~0x40);
+ +	saverfb7r4 = saverfb7r4 & (~0x40);
+@@ -49,9 +85,9 @@
+ +
+ +	for (i = 0; i < 10000; i++) {
+ +		bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+-+		if ((bbpreg & 0x40)==0)
+++		if ((bbpreg & 0x40) == 0)
+ +			break;
+-+		udelay(50);
+++		usleep_range(50, 100);
+ +	}
+ +
+ +	bbpreg = rt2800_bbp_read(rt2x00dev, 159);
+@@ -71,7 +107,7 @@
   static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
   				       bool set_bw, bool is_ht40)
   {
 -@@ -9227,6 +9291,7 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -9246,6 +9310,7 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -9216,6 +9275,7 @@ static void rt2800_init_rfcsr_6352(struc
   
   	rt2800_r_calibration(rt2x00dev);
   	rt2800_rf_self_txdc_cal(rt2x00dev);
-diff --git a/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
-index 7352ad036c..98f2e245ce 100644
+diff --git a/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch b/package/kernel/mac80211/patches/rt2x00/008-rt2x00-add-RXIQ-calibration-for-MT7620.patch
+similarity index 63%
+rename from package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
+rename to package/kernel/mac80211/patches/rt2x00/008-rt2x00-add-RXIQ-calibration-for-MT7620.patch
+index 7352ad036c..dc516da43a 100644
 --- a/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/985-rt2x00-add-rxiq-calibration.patch
-@@ -1,6 +1,6 @@
++++ b/package/kernel/mac80211/patches/rt2x00/008-rt2x00-add-RXIQ-calibration-for-MT7620.patch
+@@ -1,17 +1,62 @@
++From patchwork Sat Sep 17 20:28:10 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979249
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:28:10 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 08/16] rt2x00: add RXIQ calibration for MT7620
++Message-ID: 
++ <033a39a697d51f6df258acea4c33608e0944fe4c.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Add RXIQ calibration found in mtk driver. With old openwrt builds this
++gets us ~8Mbps more of RX bandwidth (test with iPA/eLNA layout).
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++v2: use rt2800_wait_bbp_rf_ready(), fix indentation
++
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 375 ++++++++++++++++++
++ 1 file changed, 375 insertions(+)
++
  --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
  +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 -@@ -8682,6 +8682,384 @@ static void rt2800_rxdcoc_calibration(st
-+@@ -8701,6 +8701,384 @@ static void rt2800_rxdcoc_calibration(st
++@@ -8666,6 +8666,380 @@ static void rt2800_rxdcoc_calibration(st
   	rt2800_rfcsr_write_bank(rt2x00dev, 0, 2, saverfb0r2);
   }
   
-@@ -385,7 +385,7 @@
+-+static u32 rt2800_do_sqrt_accumulation(u32 si) {
+++static u32 rt2800_do_sqrt_accumulation(u32 si)
+++{
+ +	u32 root, root_pre, bit;
+ +	char i;
+++
+ +	bit = 1 << 15;
+ +	root = 0;
+ +	for (i = 15; i >= 0; i = i - 1) {
+ +		root_pre = root + bit;
+-+		if ((root_pre*root_pre) <= si)
+++		if ((root_pre * root_pre) <= si)
+ +			root = root_pre;
+ +		bit = bit >> 1;
+ +	}
+@@ -19,7 +64,8 @@
+ +	return root;
+ +}
+ +
+-+static void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev) {
+++static void rt2800_rxiq_calibration(struct rt2x00_dev *rt2x00dev)
+++{
+ +	u8 rfb0r1, rfb0r2, rfb0r42;
+ +	u8 rfb4r0, rfb4r19;
+ +	u8 rfb5r3, rfb5r4, rfb5r17, rfb5r18, rfb5r19, rfb5r20;
+@@ -43,8 +89,8 @@
+ +	u32 orig_RF_BYPASS1 = 0;
+ +	u32 orig_RF_CONTROL3 = 0;
+ +	u32 orig_RF_BYPASS3 = 0;
+-+	u32 macstatus, bbpval1 = 0;
+-+	u8 rf_vga_table[] = {0x20, 0x21, 0x22, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f};
+++	u32 bbpval1 = 0;
+++	static const u8 rf_vga_table[] = {0x20, 0x21, 0x22, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f};
+ +
+ +	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	orig_RF_CONTROL0 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+@@ -59,16 +105,8 @@
+ +
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x0);
+ +
+-+	for (i = 0; i < 10000; i++) {
+-+		macstatus = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macstatus & 0x3)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+-+
+-+	if (i == 10000)
+-+		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY)))
+++		rt2x00_warn(rt2x00dev, "Timeout waiting for MAC status in RXIQ calibration\n");
+ +
+ +	bbpval = bbp4 & (~0x18);
+ +	bbpval = bbp4 | 0x00;
+@@ -165,7 +203,7 @@
+ +			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001006);
+ +			udelay(1);
+ +
+-+			bbpval = bbp1 & (~ 0x18);
+++			bbpval = bbp1 & (~0x18);
+ +			bbpval = bbpval | 0x00;
+ +			rt2800_bbp_write(rt2x00dev, 1, bbpval);
+ +
+@@ -184,132 +222,133 @@
+ +			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002006);
+ +			udelay(1);
+ +
+-+			bbpval = bbp1 & (~ 0x18);
+++			bbpval = bbp1 & (~0x18);
+ +			bbpval = bbpval | 0x08;
+ +			rt2800_bbp_write(rt2x00dev, 1, bbpval);
+ +
+ +			rt2800_bbp_dcoc_write(rt2x00dev, 1, 0x01);
+ +		}
+-+		udelay(500);
+++		usleep_range(500, 1500);
+ +
+ +		vga_idx = 0;
+-+			while (vga_idx < 11) {
+-+				rt2800_rfcsr_write_dccal(rt2x00dev, 3, rf_vga_table[vga_idx]);
+-+				rt2800_rfcsr_write_dccal(rt2x00dev, 4, rf_vga_table[vga_idx]);
+-+
+-+				rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x93);
+-+
+-+				for (i = 0; i < 10000; i++) {
+-+					bbpval = rt2800_bbp_read(rt2x00dev, 159);
+-+					if ((bbpval & 0xff) == 0x93)
+-+						udelay(50);
+-+					else
+-+						break;
+-+					}
+-+
+-+				if ((bbpval & 0xff) == 0x93) {
+-+					rt2x00_warn(rt2x00dev, "Fatal Error: Calibration doesn't finish");
+-+					goto restore_value;
+-+				}
+++		while (vga_idx < 11) {
+++			rt2800_rfcsr_write_dccal(rt2x00dev, 3, rf_vga_table[vga_idx]);
+++			rt2800_rfcsr_write_dccal(rt2x00dev, 4, rf_vga_table[vga_idx]);
+ +
+-+				for (i = 0; i < 5; i++) {
+-+					u32 bbptemp = 0;
+-+					u8 value = 0;
+-+					int result = 0;
+-+
+-+					rt2800_bbp_write(rt2x00dev, 158, 0x1e);
+-+					rt2800_bbp_write(rt2x00dev, 159, i);
+-+					rt2800_bbp_write(rt2x00dev, 158, 0x22);
+-+					value = rt2800_bbp_read(rt2x00dev, 159);
+-+					bbptemp = bbptemp + (value << 24);
+-+					rt2800_bbp_write(rt2x00dev, 158, 0x21);
+-+					value = rt2800_bbp_read(rt2x00dev, 159);
+-+					bbptemp = bbptemp + (value << 16);
+-+					rt2800_bbp_write(rt2x00dev, 158, 0x20);
+-+					value = rt2800_bbp_read(rt2x00dev, 159);
+-+					bbptemp = bbptemp + (value << 8);
+-+					rt2800_bbp_write(rt2x00dev, 158, 0x1f);
+-+					value = rt2800_bbp_read(rt2x00dev, 159);
+-+					bbptemp = bbptemp + value;
+-+
+-+					if ((i < 2) && (bbptemp & 0x800000))
+-+						result = (bbptemp & 0xffffff) - 0x1000000;
+-+					else if (i == 4)
+-+						result = bbptemp;
+-+					else
+-+						result = bbptemp;
+-+
+-+					if (i == 0)
+-+						mi = result/4096;
+-+					else if (i == 1)
+-+						mq = result/4096;
+-+					else if (i == 2)
+-+						si = bbptemp/4096;
+-+					else if (i == 3)
+-+						sq = bbptemp/4096;
+-+					else
+-+						riq = result/4096;
+-+				}
+-+
+-+				bbpval1 = si - mi*mi;
+-+				rt2x00_dbg(rt2x00dev, "RXIQ si=%d, sq=%d, riq=%d, bbpval %d, vga_idx %d", si, sq, riq, bbpval1, vga_idx);
+++			rt2800_bbp_dcoc_write(rt2x00dev, 0, 0x93);
+ +
+-+				if (bbpval1 >= (100*100))
+++			for (i = 0; i < 10000; i++) {
+++				bbpval = rt2800_bbp_read(rt2x00dev, 159);
+++				if ((bbpval & 0xff) == 0x93)
+++					usleep_range(50, 100);
+++				else
+ +					break;
+++				}
+ +
+-+				if (bbpval1 <= 100)
+-+					vga_idx = vga_idx + 9;
+-+				else if (bbpval1 <= 158)
+-+					vga_idx = vga_idx + 8;
+-+				else if (bbpval1 <= 251)
+-+					vga_idx = vga_idx + 7;
+-+				else if (bbpval1 <= 398)
+-+					vga_idx = vga_idx + 6;
+-+				else if (bbpval1 <= 630)
+-+					vga_idx = vga_idx + 5;
+-+				else if (bbpval1 <= 1000)
+-+					vga_idx = vga_idx + 4;
+-+				else if (bbpval1 <= 1584)
+-+					vga_idx = vga_idx + 3;
+-+				else if (bbpval1 <= 2511)
+-+					vga_idx = vga_idx + 2;
+++			if ((bbpval & 0xff) == 0x93) {
+++				rt2x00_warn(rt2x00dev, "Fatal Error: Calibration doesn't finish");
+++				goto restore_value;
+++			}
+++			for (i = 0; i < 5; i++) {
+++				u32 bbptemp = 0;
+++				u8 value = 0;
+++				int result = 0;
+++
+++				rt2800_bbp_write(rt2x00dev, 158, 0x1e);
+++				rt2800_bbp_write(rt2x00dev, 159, i);
+++				rt2800_bbp_write(rt2x00dev, 158, 0x22);
+++				value = rt2800_bbp_read(rt2x00dev, 159);
+++				bbptemp = bbptemp + (value << 24);
+++				rt2800_bbp_write(rt2x00dev, 158, 0x21);
+++				value = rt2800_bbp_read(rt2x00dev, 159);
+++				bbptemp = bbptemp + (value << 16);
+++				rt2800_bbp_write(rt2x00dev, 158, 0x20);
+++				value = rt2800_bbp_read(rt2x00dev, 159);
+++				bbptemp = bbptemp + (value << 8);
+++				rt2800_bbp_write(rt2x00dev, 158, 0x1f);
+++				value = rt2800_bbp_read(rt2x00dev, 159);
+++				bbptemp = bbptemp + value;
+++
+++				if (i < 2 && (bbptemp & 0x800000))
+++					result = (bbptemp & 0xffffff) - 0x1000000;
+++				else if (i == 4)
+++					result = bbptemp;
+++				else
+++					result = bbptemp;
+++
+++				if (i == 0)
+++					mi = result / 4096;
+++				else if (i == 1)
+++					mq = result / 4096;
+++				else if (i == 2)
+++					si = bbptemp / 4096;
+++				else if (i == 3)
+++					sq = bbptemp / 4096;
+ +				else
+-+					vga_idx = vga_idx + 1;
+++					riq = result / 4096;
+ +			}
+ +
+-+		sigma_i = rt2800_do_sqrt_accumulation(100*(si - mi*mi));
+-+		sigma_q = rt2800_do_sqrt_accumulation(100*(sq - mq*mq));
+-+		r_iq = 10*(riq-(mi*mq));
+++			bbpval1 = si - mi * mi;
+++			rt2x00_dbg(rt2x00dev,
+++				   "RXIQ si=%d, sq=%d, riq=%d, bbpval %d, vga_idx %d",
+++				   si, sq, riq, bbpval1, vga_idx);
+++
+++			if (bbpval1 >= (100 * 100))
+++				break;
+++
+++			if (bbpval1 <= 100)
+++				vga_idx = vga_idx + 9;
+++			else if (bbpval1 <= 158)
+++				vga_idx = vga_idx + 8;
+++			else if (bbpval1 <= 251)
+++				vga_idx = vga_idx + 7;
+++			else if (bbpval1 <= 398)
+++				vga_idx = vga_idx + 6;
+++			else if (bbpval1 <= 630)
+++				vga_idx = vga_idx + 5;
+++			else if (bbpval1 <= 1000)
+++				vga_idx = vga_idx + 4;
+++			else if (bbpval1 <= 1584)
+++				vga_idx = vga_idx + 3;
+++			else if (bbpval1 <= 2511)
+++				vga_idx = vga_idx + 2;
+++			else
+++				vga_idx = vga_idx + 1;
+++		}
+++
+++		sigma_i = rt2800_do_sqrt_accumulation(100 * (si - mi * mi));
+++		sigma_q = rt2800_do_sqrt_accumulation(100 * (sq - mq * mq));
+++		r_iq = 10 * (riq - (mi * mq));
+ +
+ +		rt2x00_dbg(rt2x00dev, "Sigma_i=%d, Sigma_q=%d, R_iq=%d", sigma_i, sigma_q, r_iq);
+ +
+-+		if (((sigma_i <= 1400 ) && (sigma_i >= 1000))
+-+			&& ((sigma_i - sigma_q) <= 112)
+-+			&& ((sigma_i - sigma_q) >= -112)
+-+			&& ((mi <= 32) && (mi >= -32))
+-+			&& ((mq <= 32) && (mq >= -32))) {
+-+				r_iq = 10*(riq-(mi*mq));
+-+				rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
+-+
+-+				g_rx = (1000 * sigma_q) / sigma_i;
+-+				g_imb = ((-2) * 128 * (1000 - g_rx)) / (1000 + g_rx);
+-+				ph_rx = (r_iq * 2292) / (sigma_i * sigma_q);
+-+				rt2x00_info(rt2x00dev, "RXIQ G_imb=%d, Ph_rx=%d\n", g_imb, ph_rx);
+-+
+-+				if ((ph_rx > 20) || (ph_rx < -20)) {
+-+					ph_rx = 0;
+-+					rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+-+				}
+++		if (sigma_i <= 1400 && sigma_i >= 1000 &&
+++		    (sigma_i - sigma_q) <= 112 &&
+++		    (sigma_i - sigma_q) >= -112 &&
+++		    mi <= 32 && mi >= -32 &&
+++		    mq <= 32 && mq >= -32) {
+++			r_iq = 10 * (riq - (mi * mq));
+++			rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n",
+++				   sigma_i, sigma_q, r_iq);
+++
+++			g_rx = (1000 * sigma_q) / sigma_i;
+++			g_imb = ((-2) * 128 * (1000 - g_rx)) / (1000 + g_rx);
+++			ph_rx = (r_iq * 2292) / (sigma_i * sigma_q);
+++
+++			if (ph_rx > 20 || ph_rx < -20) {
+++				ph_rx = 0;
+++				rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+++			}
+ +
+-+				if ((g_imb > 12) || (g_imb < -12)) {
+-+					g_imb = 0;
+-+					rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+-+				}
+++			if (g_imb > 12 || g_imb < -12) {
+++				g_imb = 0;
+++				rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+ +			}
+-+		else {
+++		} else {
+ +			g_imb = 0;
+ +			ph_rx = 0;
+-+			rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n", sigma_i, sigma_q, r_iq);
+++			rt2x00_dbg(rt2x00dev, "RXIQ Sigma_i=%d, Sigma_q=%d, R_iq=%d\n",
+++				   sigma_i, sigma_q, r_iq);
+ +			rt2x00_warn(rt2x00dev, "RXIQ calibration FAIL");
+ +		}
+ +
+@@ -385,7 +424,7 @@
   static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
   				       bool set_bw, bool is_ht40)
   {
 -@@ -9294,6 +9672,7 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -9313,6 +9691,7 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -9278,6 +9652,7 @@ static void rt2800_init_rfcsr_6352(struc
   	rt2800_rxdcoc_calibration(rt2x00dev);
   	rt2800_bw_filter_calibration(rt2x00dev, true);
   	rt2800_bw_filter_calibration(rt2x00dev, false);
-diff --git a/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
-index fe0961baa7..6a685f80ab 100644
+diff --git a/package/kernel/mac80211/patches/rt2x00/009-rt2x00-don-t-run-Rt5592-IQ-calibration-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/009-rt2x00-don-t-run-Rt5592-IQ-calibration-on-MT7620.patch
+new file mode 100644
+index 0000000000..6b27f6a705
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/009-rt2x00-don-t-run-Rt5592-IQ-calibration-on-MT7620.patch
+@@ -0,0 +1,52 @@
++From patchwork Sat Sep 17 20:28:29 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979250
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:28:29 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 09/16] rt2x00: don't run Rt5592 IQ calibration on MT7620
++Message-ID: 
++ <31a1c34ddbd296b82f38c18c9ae7339059215fdc.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++The function rt2800_iq_calibrate is intended for Rt5592 only.
++Don't call it for MT7620 which has it's own calibration functions.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++---
++v2: test for RT5592 instead of !RT6352
++
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 3 ++-
++ 1 file changed, 2 insertions(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -4398,7 +4398,8 @@ static void rt2800_config_channel(struct
++ 		reg = (rf->channel <= 14 ? 0x1c : 0x24) + 2*rt2x00dev->lna_gain;
++ 		rt2800_bbp_write_with_rx_chain(rt2x00dev, 66, reg);
++ 
++-		rt2800_iq_calibrate(rt2x00dev, rf->channel);
+++		if (rt2x00_rt(rt2x00dev, RT5592))
+++			rt2800_iq_calibrate(rt2x00dev, rf->channel);
++ 	}
++ 
++ 	if (rt2x00_rt(rt2x00dev, RT6352)) {
+diff --git a/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch b/package/kernel/mac80211/patches/rt2x00/010-rt2x00-add-TX-LOFT-calibration-for-MT7620.patch
+similarity index 84%
+rename from package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
+rename to package/kernel/mac80211/patches/rt2x00/010-rt2x00-add-TX-LOFT-calibration-for-MT7620.patch
+index fe0961baa7..bb01ff1dca 100644
 --- a/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/986-rt2x00-add-TX-LOFT-calibration.patch
-@@ -1,6 +1,6 @@
++++ b/package/kernel/mac80211/patches/rt2x00/010-rt2x00-add-TX-LOFT-calibration-for-MT7620.patch
+@@ -1,10 +1,56 @@
++From patchwork Sat Sep 17 20:28:43 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 8bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979251
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:28:43 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 10/16] rt2x00: add TX LOFT calibration for MT7620
++Message-ID: 
++ <d9295a9138a1f552b648aacb84e1419d38f5c896.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++From: Tomislav Požega <pozega.tomislav@gmail.com>
++
++Add TX LOFT calibration from mtk driver.
++
++Signed-off-by: Tomislav Požega <pozega.tomislav@gmail.com>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++---
++v2: use helper functions, make tables static const, remove useless
++    debug prints
++v3: don't export function not used anywhere else
++Reported-by: kernel test robot <lkp@intel.com>
++
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 902 ++++++++++++++++++
++ .../net/wireless/ralink/rt2x00/rt2800lib.h    |  10 +
++ 2 files changed, 912 insertions(+)
++
  --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
  +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
 -@@ -9060,6 +9060,943 @@ restore_value:
-+@@ -9079,6 +9079,943 @@ restore_value:
++@@ -9041,6 +9041,907 @@ restore_value:
   	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
   }
   
-@@ -944,7 +944,7 @@
-  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
-  				       bool set_bw, bool is_ht40)
-  {
--@@ -9672,6 +10609,7 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -9691,6 +10628,7 @@ static void rt2800_init_rfcsr_6352(struc
-  	rt2800_rxdcoc_calibration(rt2x00dev);
-  	rt2800_bw_filter_calibration(rt2x00dev, true);
-  	rt2800_bw_filter_calibration(rt2x00dev, false);
-diff --git a/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
-index 3de00b2267..40b20ec594 100644
---- a/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
-+++ b/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
-@@ -14,7 +14,7 @@
-   */
- --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
- +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
--@@ -3685,14 +3685,16 @@ static void rt2800_config_channel_rf7620
-+@@ -3698,14 +3698,16 @@ static void rt2800_config_channel_rf7620
-  	rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4);
-  	rt2800_rfcsr_write(rt2x00dev, 19, rfcsr);
-  
-@@ -39,7 +39,7 @@
-  
-  	rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
-  	rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620,
--@@ -3726,18 +3728,23 @@ static void rt2800_config_channel_rf7620
-+@@ -3739,18 +3741,23 @@ static void rt2800_config_channel_rf7620
-  		rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20);
-  	}
-  
-@@ -73,7 +73,7 @@
-  
-  	if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) {
-  		if (conf_is_ht40(conf)) {
--@@ -3837,25 +3844,29 @@ static void rt2800_config_alc(struct rt2
-+@@ -3850,25 +3857,29 @@ static void rt2800_config_alc(struct rt2
-  	if (i == 10000)
-  		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
-  
-@@ -121,7 +121,7 @@
-  	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl);
-  
-  	rt2800_vco_calibration(rt2x00dev);
--@@ -5887,18 +5898,33 @@ static int rt2800_init_registers(struct
-+@@ -5906,18 +5917,33 @@ static int rt2800_init_registers(struct
-  	} else if (rt2x00_rt(rt2x00dev, RT5350)) {
-  		rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
-  	} else if (rt2x00_rt(rt2x00dev, RT6352)) {
-@@ -167,7 +167,7 @@
-  		reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1);
-  		rt2x00_set_field32(&reg, TX_ALC_CFG_1_ROS_BUSY_EN, 0);
-  		rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg);
--@@ -7042,14 +7068,16 @@ static void rt2800_init_bbp_6352(struct
-+@@ -7061,14 +7087,16 @@ static void rt2800_init_bbp_6352(struct
-  	rt2800_bbp_write(rt2x00dev, 188, 0x00);
-  	rt2800_bbp_write(rt2x00dev, 189, 0x00);
-  
-@@ -192,7 +192,7 @@
-  
-  	/* BBP for G band GLRT function (BBP_128 ~ BBP_221) */
-  	rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00);
--@@ -10388,31 +10416,36 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -10407,31 +10435,36 @@ static void rt2800_init_rfcsr_6352(struc
-  	rt2800_rfcsr_write(rt2x00dev, 42, 0x5B);
-  	rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
-  
-@@ -254,7 +254,7 @@
-  
-  	/* Initialize RF channel register to default value */
-  	rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03);
--@@ -10478,63 +10511,71 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -10497,63 +10530,71 @@ static void rt2800_init_rfcsr_6352(struc
-  
-  	rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
-  
-@@ -383,7 +383,7 @@
-  
-  	/* Initialize RF DC calibration register to default value */
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
--@@ -10597,12 +10638,17 @@ static void rt2800_init_rfcsr_6352(struc
-+@@ -10616,12 +10657,17 @@ static void rt2800_init_rfcsr_6352(struc
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00);
-  	rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00);
-  
-diff --git a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
-deleted file mode 100644
-index 31a7baeee7..0000000000
---- a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
-+++ /dev/null
-@@ -1,183 +0,0 @@
----- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
--@@ -1238,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *
-- 	if (test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags))
-- 		return;
-- 
--+	rt2800_update_survey(rt2x00dev);
+-+static void rt2800_rf_configstore(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_reg_record[][13], u8 chain)
+++static void rt2800_rf_configstore(struct rt2x00_dev *rt2x00dev,
+++				  struct rf_reg_pair rf_reg_record[][13], u8 chain)
+ +{
+ +	u8 rfvalue = 0;
+ +
+@@ -116,13 +162,11 @@
+ +		rf_reg_record[CHAIN_1][12].value = rfvalue;
+ +	} else {
+ +		rt2x00_warn(rt2x00dev, "Unknown chain = %u\n", chain);
+-+		return;
+ +	}
 -+
-- 	queue_for_each(rt2x00dev, queue) {
-- 		switch (queue->qid) {
-- 		case QID_AC_VO:
--@@ -1274,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *
-- }
-- 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];
+-+	return;
+ +}
+ +
+-+static void rt2800_rf_configrecover(struct rt2x00_dev *rt2x00dev, rf_reg_pair rf_record[][13])
+++static void rt2800_rf_configrecover(struct rt2x00_dev *rt2x00dev,
+++				    struct rf_reg_pair rf_record[][13])
+ +{
+ +	u8 chain_index = 0, record_index = 0;
+ +	u8 bank = 0, rf_register = 0, value = 0;
+@@ -133,11 +177,10 @@
+ +			rf_register = rf_record[chain_index][record_index].reg;
+ +			value = rf_record[chain_index][record_index].value;
+ +			rt2800_rfcsr_write_bank(rt2x00dev, bank, rf_register, value);
+-+			rt2x00_dbg(rt2x00dev, "bank: %d, rf_register: %d, value: %x\n", bank, rf_register, value);
+++			rt2x00_dbg(rt2x00dev, "bank: %d, rf_register: %d, value: %x\n",
+++				   bank, rf_register, 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);
+-+	return;
+ +}
+ +
+ +static void rt2800_setbbptonegenerator(struct rt2x00_dev *rt2x00dev)
+@@ -155,15 +198,13 @@
+ +	rt2800_bbp_write(rt2x00dev, 159, 0x3F);
+ +
+ +	rt2800_bbp_write(rt2x00dev, 244, 0x40);
 -+
-- static unsigned int rt2800_hw_beacon_base(struct rt2x00_dev *rt2x00dev,
-- 					  unsigned int index)
-- {
--@@ -12199,26 +12213,30 @@ int rt2800_get_survey(struct ieee80211_h
-- {
-- 	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;
--+	}
+-+	return;
+ +}
+ +
+ +static u32 rt2800_do_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx, u8 read_neg)
+ +{
+ +	u32 macvalue = 0;
+ +	int fftout_i = 0, fftout_q = 0;
+-+	u32 ptmp=0, pint = 0;
+++	u32 ptmp = 0, pint = 0;
+ +	u8 bbp = 0;
+ +	u8 tidxi;
+ +
+@@ -173,7 +214,7 @@
+ +	bbp = 0x9b;
+ +
+ +	while (bbp == 0x9b) {
+-+		udelay(10);
+++		usleep_range(10, 50);
+ +		bbp = rt2800_bbp_read(rt2x00dev, 159);
+ +		bbp = bbp & 0xff;
+ +	}
+@@ -218,10 +259,11 @@
+ +	return pint;
+ +}
+ +
+-+static u32 rt2800_read_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx) {
+++static u32 rt2800_read_fft_accumulation(struct rt2x00_dev *rt2x00dev, u8 tidx)
+++{
+ +	u32 macvalue = 0;
+ +	int fftout_i = 0, fftout_q = 0;
+-+	u32 ptmp=0, pint = 0;
+++	u32 ptmp = 0, pint = 0;
+ +
+ +	rt2800_bbp_write(rt2x00dev, 158, 0xBA);
+ +	rt2800_bbp_write(rt2x00dev, 159, tidx);
+@@ -237,7 +279,6 @@
+ +	ptmp = (fftout_i * fftout_i);
+ +	ptmp = ptmp + (fftout_q * fftout_q);
+ +	pint = ptmp;
+-+	rt2x00_info(rt2x00dev, "I = %d,  Q = %d, power = %x\n", fftout_i, fftout_q, pint);
+ +
+ +	return pint;
+ +}
+@@ -251,18 +292,17 @@
+ +	rt2800_bbp_write(rt2x00dev, 159, bbp);
+ +
+ +	if (ch_idx == 0)
+-+		bbp = (iorq == 0) ? 0xb1: 0xb2;
+++		bbp = (iorq == 0) ? 0xb1 : 0xb2;
+ +	else
+-+		bbp = (iorq == 0) ? 0xb8: 0xb9;
+++		bbp = (iorq == 0) ? 0xb8 : 0xb9;
+ +
+ +	rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +	bbp = dc;
+ +	rt2800_bbp_write(rt2x00dev, 159, bbp);
 -+
--+	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);
---
---	if (idle || 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->channel = &rt2x00dev->bands[band].channels[idx];
+-+	return;
+ +}
+ +
+-+static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 alc_idx, u8 dc_result[][RF_ALC_NUM][2])
+++static void rt2800_loft_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx,
+++			       u8 alc_idx, u8 dc_result[][RF_ALC_NUM][2])
+ +{
+ +	u32 p0 = 0, p1 = 0, pf = 0;
+ +	char idx0 = 0, idx1 = 0;
+@@ -276,8 +316,6 @@
+ +
+ +	for (bidx = 5; bidx >= 0; bidx--) {
+ +		for (iorq = 0; iorq <= 1; iorq++) {
+-+			rt2x00_dbg(rt2x00dev, "\n========================================================\n");
+-+
+ +			if (idxf[iorq] == 0x20) {
+ +				idx0 = 0x20;
+ +				p0 = pf;
+@@ -288,16 +326,17 @@
+ +				p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
+ +			}
+ +
+-+			idx1 = idxf[iorq] + ((bidx == 5) ? 0 : ibit);
+++			idx1 = idxf[iorq] + (bidx == 5 ? 0 : ibit);
+ +			idx1 = idx1 & 0x3F;
+ +			rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idx1);
+ +			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
+ +
+-+			rt2x00_dbg(rt2x00dev, "alc=%u, IorQ=%u, idx_final=%2x\n", alc_idx, iorq, idxf[iorq]);
+-+			rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pf=%x, idx_0=%x, idx_1=%x, ibit=%x !\n", p0, p1, pf, idx0, idx1, ibit);
+++			rt2x00_dbg(rt2x00dev, "alc=%u, IorQ=%u, idx_final=%2x\n",
+++				   alc_idx, iorq, idxf[iorq]);
+++			rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pf=%x, idx_0=%x, idx_1=%x, ibit=%x\n",
+++				   p0, p1, pf, idx0, idx1, ibit);
+ +
+-+			if ((bidx != 5) && (pf <= p0) && (pf < p1)) {
+-+				pf = pf;
+++			if (bidx != 5 && pf <= p0 && pf < p1) {
+ +				idxf[iorq] = idxf[iorq];
+ +			} else if (p0 < p1) {
+ +				pf = p0;
+@@ -306,17 +345,15 @@
+ +				pf = p1;
+ +				idxf[iorq] = idx1 & 0x3F;
+ +			}
+-+			rt2x00_dbg(rt2x00dev, "IorQ=%u, idx_final[%u]:%x, pf:%8x\n", iorq, iorq, idxf[iorq], pf);
+++			rt2x00_dbg(rt2x00dev, "IorQ=%u, idx_final[%u]:%x, pf:%8x\n",
+++				   iorq, iorq, idxf[iorq], pf);
+ +
+ +			rt2800_write_dc(rt2x00dev, ch_idx, 0, iorq, idxf[iorq]);
 -+
--+	survey->filled = SURVEY_INFO_TIME |
--+			 SURVEY_INFO_TIME_BUSY |
--+			 SURVEY_INFO_TIME_EXT_BUSY;
+ +		}
+ +		ibit = ibit >> 1;
+ +	}
+ +	dc_result[ch_idx][alc_idx][0] = idxf[0];
+ +	dc_result[ch_idx][alc_idx][1] = idxf[1];
 -+
--+	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;
----- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
--@@ -243,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x
-- 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);
----- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
--@@ -360,6 +360,7 @@ static const struct rt2x00lib_ops rt2800
-- 	.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,
----- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
--@@ -214,6 +214,7 @@ static const struct rt2x00lib_ops rt2800
-- 	.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,
----- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
--@@ -183,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;
--+};
+-+	return;
+ +}
+ +
+ +static void rt2800_iq_search(struct rt2x00_dev *rt2x00dev, u8 ch_idx, u8 *ges, u8 *pes)
+@@ -334,26 +371,25 @@
+ +	u8 bbp = 0;
+ +	char bidx;
+ +
+-+	rt2x00_info(rt2x00dev, "IQCalibration Start!\n");
+ +	for (bidx = 5; bidx >= 1; bidx--) {
+ +		for (gop = 0; gop < 2; gop++) {
+-+			rt2x00_dbg(rt2x00dev, "\n========================================================\n");
+-+
+-+			if ((gop == 1) || (bidx < 4)) {
+++			if (gop == 1 || bidx < 4) {
+ +				if (gop == 0)
+ +					iq_err = gerr;
+ +				else
+ +					iq_err = perr;
+ +
+ +				first_search = (gop == 0) ? (bidx == 3) : (bidx == 5);
+-+				touch_neg_max = (gop) ? ((iq_err & 0x0F) == 0x08) : ((iq_err & 0x3F) == 0x20);
+++				touch_neg_max = (gop) ? ((iq_err & 0x0F) == 0x08) :
+++							((iq_err & 0x3F) == 0x20);
+ +
+ +				if (touch_neg_max) {
+ +					p0 = pf;
+ +					idx0 = iq_err;
+ +				} else {
+ +					idx0 = iq_err - ibit;
+-+					bbp = (ch_idx == 0) ? ((gop == 0) ? 0x28 : 0x29): ((gop == 0) ? 0x46 : 0x47);
+++					bbp = (ch_idx == 0) ? ((gop == 0) ? 0x28 : 0x29) :
+++							      ((gop == 0) ? 0x46 : 0x47);
+ +
+ +					rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +					rt2800_bbp_write(rt2x00dev, 159, idx0);
+@@ -364,26 +400,30 @@
+ +				idx1 = iq_err + (first_search ? 0 : ibit);
+ +				idx1 = (gop == 0) ? (idx1 & 0x0F) : (idx1 & 0x3F);
+ +
+-+				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47;
+++				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 :
+++				      (gop == 0) ? 0x46 : 0x47;
+ +
+ +				rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +				rt2800_bbp_write(rt2x00dev, 159, idx1);
+ +
+ +				p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1);
+ +
+-+				rt2x00_dbg(rt2x00dev, "p0=%x, p1=%x, pwer_final=%x, idx0=%x, idx1=%x, iq_err=%x, gop=%d, ibit=%x !\n", p0, p1, pf, idx0, idx1, iq_err, gop, ibit);
+-+
+-+				if ((!first_search) && (pf <= p0) && (pf < p1)) {
+-+					pf = pf;
+-+				} else if (p0 < p1) {
+-+					pf = p0;
+-+					iq_err = idx0;
+-+				} else {
+-+					pf = p1;
+-+					iq_err = idx1;
+++				rt2x00_dbg(rt2x00dev,
+++					   "p0=%x, p1=%x, pwer_final=%x, idx0=%x, idx1=%x, iq_err=%x, gop=%d, ibit=%x\n",
+++					   p0, p1, pf, idx0, idx1, iq_err, gop, ibit);
+++
+++				if (!(!first_search && pf <= p0 && pf < p1)) {
+++					if (p0 < p1) {
+++						pf = p0;
+++						iq_err = idx0;
+++					} else {
+++						pf = p1;
+++						iq_err = idx1;
+++					}
+ +				}
+ +
+-+				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 : (gop == 0) ? 0x46 : 0x47;
+++				bbp = (ch_idx == 0) ? (gop == 0) ? 0x28 : 0x29 :
+++						      (gop == 0) ? 0x46 : 0x47;
+ +
+ +				rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +				rt2800_bbp_write(rt2x00dev, 159, iq_err);
+@@ -393,8 +433,8 @@
+ +				else
+ +					perr = iq_err;
+ +
+-+				rt2x00_dbg(rt2x00dev, "IQCalibration pf=%8x (%2x, %2x) !\n", pf, gerr & 0x0F, perr & 0x3F);
 -+
--+/*
--  * Channel information structure
--  */
-- struct channel_info {
--@@ -567,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);
--@@ -755,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;
-- 
----- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
--@@ -1057,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(stru
-- 	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;
+++				rt2x00_dbg(rt2x00dev, "IQCalibration pf=%8x (%2x, %2x) !\n",
+++					   pf, gerr & 0x0F, perr & 0x3F);
+ +			}
+ +		}
+ +
+@@ -423,25 +463,21 @@
+ +			rt2800_bbp_write(rt2x00dev, 159, pef & 0x3F);
+ +
+ +			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 1);
+-+			if ((gef == gsta) && (pef == psta)) {
+++			if (gef == gsta && pef == psta) {
+ +				pf = p1;
+ +				gerr = gef;
+ +				perr = pef;
+-+			}
+-+			else if (pf > p1){
+++			} else if (pf > p1) {
+ +				pf = p1;
+ +				gerr = gef;
+ +				perr = pef;
+ +			}
+-+			rt2x00_dbg(rt2x00dev, "Fine IQCalibration p1=%8x pf=%8x (%2x, %2x) !\n", p1, pf, gef & 0x0F, pef & 0x3F);
+++			rt2x00_dbg(rt2x00dev, "Fine IQCalibration p1=%8x pf=%8x (%2x, %2x) !\n",
+++				   p1, pf, gef & 0x0F, pef & 0x3F);
+ +		}
+ +
+ +	ges[ch_idx] = gerr & 0x0F;
+ +	pes[ch_idx] = perr & 0x3F;
 -+
-- 	/*
-- 	 * Initialize Rate list.
-- 	 */
--@@ -1108,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(stru
-- 
-- 	return 0;
-- 
--+ exit_free_rates:
--+	kfree(rates);
--  exit_free_channels:
-- 	kfree(channels);
-- 	rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
----- 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
-- 		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);
--+	}
+-+	rt2x00_info(rt2x00dev, "IQCalibration Done! CH = %u, (gain=%2x, phase=%2x)\n", ch_idx, gerr & 0x0F, perr & 0x3F);
 -+
--+	/*
-- 	 * 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,
+-+	return;
+ +}
+ +
+ +static void rt2800_rf_aux_tx0_loopback(struct rt2x00_dev *rt2x00dev)
+@@ -478,9 +514,9 @@
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 7, 20, 0x20);
+ +}
+ +
+-+void rt2800_loft_iq_calibration(struct rt2x00_dev *rt2x00dev)
+++static void rt2800_loft_iq_calibration(struct rt2x00_dev *rt2x00dev)
+ +{
+-+	rf_reg_pair rf_store[CHAIN_NUM][13];
+++	struct rf_reg_pair rf_store[CHAIN_NUM][13];
+ +	u32 macorg1 = 0;
+ +	u32 macorg2 = 0;
+ +	u32 macorg3 = 0;
+@@ -489,7 +525,7 @@
+ +	u32 orig528 = 0;
+ +	u32 orig52c = 0;
+ +
+-+	u32 savemacsysctrl = 0, mtxcycle = 0;
+++	u32 savemacsysctrl = 0;
+ +	u32 macvalue = 0;
+ +	u32 mac13b8 = 0;
+ +	u32 p0 = 0, p1 = 0;
+@@ -498,11 +534,8 @@
+ +	u8 rfvalue;
+ +	u8 loft_dc_search_result[CHAIN_NUM][RF_ALC_NUM][2];
+ +	u8 ger[CHAIN_NUM], per[CHAIN_NUM];
+-+	u8 rf_gain[] = {0x00, 0x01, 0x02, 0x04, 0x08, 0x0c};
+-+	u8 rfvga_gain_table[] = {0x24, 0x25, 0x26, 0x27, 0x28, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3F};
+ +
+ +	u8 vga_gain[] = {14, 14};
+-+	u8 bbp_2324gain[] = {0x16, 0x14, 0x12, 0x10, 0x0c, 0x08};
+ +	u8 bbp = 0, ch_idx = 0, rf_alc_idx = 0, idx = 0;
+ +	u8 bbpr30, rfb0r39, rfb0r42;
+ +	u8 bbpr1;
+@@ -510,6 +543,11 @@
+ +	u8 bbpr241, bbpr242;
+ +	u8 count_step;
+ +
+++	static const u8 rf_gain[] = {0x00, 0x01, 0x02, 0x04, 0x08, 0x0c};
+++	static const u8 rfvga_gain_table[] = {0x24, 0x25, 0x26, 0x27, 0x28, 0x2c, 0x2d, 0x2e, 0x2f, 0x30,
+++					      0x31, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3F};
+++	static const u8 bbp_2324gain[] = {0x16, 0x14, 0x12, 0x10, 0x0c, 0x08};
+++
+ +	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG);
+ +	macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+@@ -524,29 +562,18 @@
+ +	macvalue &= (~0x04);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
+ +
+-+	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
+-+		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macvalue & 0x01)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_TX)))
+++		rt2x00_warn(rt2x00dev, "RF TX busy in LOFT IQ calibration\n");
+ +
+ +	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	macvalue &= (~0x08);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
+ +
+-+	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
+-+		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macvalue & 0x02)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_RX)))
+++		rt2x00_warn(rt2x00dev, "RF RX busy in LOFT IQ calibration\n");
+ +
+-+	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
+++	for (ch_idx = 0; ch_idx < 2; ch_idx++)
+ +		rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx);
+-+	}
+ +
+ +	bbpr30 = rt2800_bbp_read(rt2x00dev, 30);
+ +	rfb0r39 = rt2800_rfcsr_read_bank(rt2x00dev, 0, 39);
+@@ -561,7 +588,7 @@
+ +
+ +	rt2800_setbbptonegenerator(rt2x00dev);
+ +
+-+	for (ch_idx = 0; ch_idx < 2; ch_idx ++) {
+++	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
+ +		rt2800_bbp_write(rt2x00dev, 23, 0x00);
+ +		rt2800_bbp_write(rt2x00dev, 24, 0x00);
+ +		rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, 0x00);
+@@ -571,18 +598,17 @@
+ +		rt2800_register_write(rt2x00dev, 0x13b8, 0x10);
+ +		udelay(1);
+ +
+-+		if (ch_idx == 0) {
+++		if (ch_idx == 0)
+ +			rt2800_rf_aux_tx0_loopback(rt2x00dev);
+-+		} else {
+++		else
+ +			rt2800_rf_aux_tx1_loopback(rt2x00dev);
+-+		}
+++
+ +		udelay(1);
+ +
+-+		if (ch_idx == 0) {
+++		if (ch_idx == 0)
+ +			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00001004);
+-+		} else {
+++		else
+ +			rt2800_register_write(rt2x00dev, RF_CONTROL0, 0x00002004);
+-+		}
+ +
+ +		rt2800_bbp_write(rt2x00dev, 158, 0x05);
+ +		rt2800_bbp_write(rt2x00dev, 159, 0x00);
+@@ -608,7 +634,8 @@
+ +
+ +			if (rf_alc_idx == 0) {
+ +				rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x21);
+-+				for (;vga_gain[ch_idx] > 0;vga_gain[ch_idx] = vga_gain[ch_idx] - 2) {
+++				for (; vga_gain[ch_idx] > 0;
+++				     vga_gain[ch_idx] = vga_gain[ch_idx] - 2) {
+ +					rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
+ +					rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue);
+ +					rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue);
+@@ -618,19 +645,19 @@
+ +					rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x21);
+ +					p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x0A, 0);
+ +					rt2x00_dbg(rt2x00dev, "LOFT AGC %d %d\n", p0, p1);
+-+					if ((p0 < 7000*7000) && (p1 < (7000*7000))) {
+++					if ((p0 < 7000 * 7000) && (p1 < (7000 * 7000)))
+ +						break;
+-+					}
+ +				}
+ +
+ +				rt2800_write_dc(rt2x00dev, ch_idx, 0, 0, 0x00);
+ +				rt2800_write_dc(rt2x00dev, ch_idx, 0, 1, 0x00);
+ +
+-+				rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]);
+++				rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n", vga_gain[ch_idx],
+++					   rfvga_gain_table[vga_gain[ch_idx]]);
+ +
+ +				if (vga_gain[ch_idx] < 0)
+ +					vga_gain[ch_idx] = 0;
+-+		 	}
+++			}
+ +
+ +			rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
+ +
+@@ -644,7 +671,7 @@
+ +	for (rf_alc_idx = 0; rf_alc_idx < 3; rf_alc_idx++) {
+ +		for (idx = 0; idx < 4; idx++) {
+ +			rt2800_bbp_write(rt2x00dev, 158, 0xB0);
+-+			bbp = (idx<<2) + rf_alc_idx;
+++			bbp = (idx << 2) + rf_alc_idx;
+ +			rt2800_bbp_write(rt2x00dev, 159, bbp);
+ +			rt2x00_dbg(rt2x00dev, " ALC %2x,", bbp);
+ +
+@@ -705,8 +732,6 @@
+ +	rt2800_register_write(rt2x00dev, RF_BYPASS2, orig52c);
+ +	rt2800_register_write(rt2x00dev, 0x13b8, mac13b8);
+ +
+-+	rt2x00_info(rt2x00dev, "LOFT Calibration Done!\n");
+-+
+ +	savemacsysctrl = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	macorg1 = rt2800_register_read(rt2x00dev, TX_PIN_CFG);
+ +	macorg2 = rt2800_register_read(rt2x00dev, RF_CONTROL0);
+@@ -723,24 +748,16 @@
+ +	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	macvalue &= (~0x04);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
+-+	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
+-+		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macvalue & 0x01)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+++
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_TX)))
+++		rt2x00_warn(rt2x00dev, "RF TX busy in LOFT IQ calibration\n");
+ +
+ +	macvalue = rt2800_register_read(rt2x00dev, MAC_SYS_CTRL);
+ +	macvalue &= (~0x08);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, macvalue);
+-+	for (mtxcycle = 0; mtxcycle < 10000; mtxcycle++) {
+-+		macvalue = rt2800_register_read(rt2x00dev, MAC_STATUS_CFG);
+-+		if (macvalue & 0x02)
+-+			udelay(50);
+-+		else
+-+			break;
+-+	}
+++
+++	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY_RX)))
+++		rt2x00_warn(rt2x00dev, "RF RX busy in LOFT IQ calibration\n");
+ +
+ +	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+ +		rt2800_register_write(rt2x00dev, RF_CONTROL3, 0x00000101);
+@@ -776,9 +793,8 @@
+ +
+ +	rt2800_register_write(rt2x00dev, 0x13b8, 0x00000010);
+ +
+-+	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
+++	for (ch_idx = 0; ch_idx < 2; ch_idx++)
+ +		rt2800_rf_configstore(rt2x00dev, rf_store, ch_idx);
+-+	}
+ +
+ +	rt2800_rfcsr_write_dccal(rt2x00dev, 3, 0x3B);
+ +	rt2800_rfcsr_write_dccal(rt2x00dev, 4, 0x3B);
+@@ -788,7 +804,7 @@
+ +	rt2800_bbp_write(rt2x00dev, 158, 0xB0);
+ +	rt2800_bbp_write(rt2x00dev, 159, 0x80);
+ +
+-+	for (ch_idx = 0; ch_idx < 2; ch_idx ++) {
+++	for (ch_idx = 0; ch_idx < 2; ch_idx++) {
+ +		rt2800_bbp_write(rt2x00dev, 23, 0x00);
+ +		rt2800_bbp_write(rt2x00dev, 24, 0x00);
+ +
+@@ -831,7 +847,7 @@
+ +			count_step = 2;
+ +		}
+ +
+-+		for (;vga_gain[ch_idx] < 19; vga_gain[ch_idx]=(vga_gain[ch_idx] + count_step)) {
+++		for (; vga_gain[ch_idx] < 19; vga_gain[ch_idx] = (vga_gain[ch_idx] + count_step)) {
+ +			rfvalue = rfvga_gain_table[vga_gain[ch_idx]];
+ +			rt2800_rfcsr_write_dccal(rt2x00dev, 3, rfvalue);
+ +			rt2800_rfcsr_write_dccal(rt2x00dev, 4, rfvalue);
+@@ -840,37 +856,35 @@
+ +			rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +			rt2800_bbp_write(rt2x00dev, 159, 0x00);
+ +			p0 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0);
+-+			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags))
+ +				p0_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A);
+-+			}
+ +
+ +			bbp = (ch_idx == 0) ? 0x29 : 0x47;
+ +			rt2800_bbp_write(rt2x00dev, 158, bbp);
+ +			rt2800_bbp_write(rt2x00dev, 159, 0x21);
+ +			p1 = rt2800_do_fft_accumulation(rt2x00dev, 0x14, 0);
+-+			if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags)) {
+++			if (test_bit(CAPABILITY_EXTERNAL_PA_TX1, &rt2x00dev->cap_flags))
+ +				p1_idx10 = rt2800_read_fft_accumulation(rt2x00dev, 0x0A);
+-+			}
+ +
+ +			rt2x00_dbg(rt2x00dev, "IQ AGC %d %d\n", p0, p1);
+ +
+ +			if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+ +				rt2x00_dbg(rt2x00dev, "IQ AGC IDX 10 %d %d\n", p0_idx10, p1_idx10);
+-+				if ((p0_idx10 > 7000*7000) || (p1_idx10 > 7000*7000)) {
+-+					if (vga_gain[ch_idx]!=0)
+-+						vga_gain[ch_idx] = vga_gain[ch_idx]-1;
+++				if ((p0_idx10 > 7000 * 7000) || (p1_idx10 > 7000 * 7000)) {
+++					if (vga_gain[ch_idx] != 0)
+++						vga_gain[ch_idx] = vga_gain[ch_idx] - 1;
+ +					break;
+ +				}
+ +			}
+ +
+-+			if ((p0 > 2500*2500) || (p1 > 2500*2500)) {
+++			if ((p0 > 2500 * 2500) || (p1 > 2500 * 2500))
+ +				break;
+-+			}
+ +		}
+ +
+ +		if (vga_gain[ch_idx] > 18)
+ +			vga_gain[ch_idx] = 18;
+-+		rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n",vga_gain[ch_idx], rfvga_gain_table[vga_gain[ch_idx]]);
+++		rt2x00_dbg(rt2x00dev, "Used VGA %d %x\n", vga_gain[ch_idx],
+++			   rfvga_gain_table[vga_gain[ch_idx]]);
+ +
+ +		bbp = (ch_idx == 0) ? 0x29 : 0x47;
+ +		rt2800_bbp_write(rt2x00dev, 158, bbp);
+@@ -915,9 +929,8 @@
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 0, 39, rfb0r39);
+ +	rt2800_rfcsr_write_bank(rt2x00dev, 0, 42, rfb0r42);
+ +
+-+	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags)) {
+++	if (test_bit(CAPABILITY_EXTERNAL_PA_TX0, &rt2x00dev->cap_flags))
+ +		rt2800_bbp_write(rt2x00dev, 4, bbpr4);
+-+	}
+ +
+ +	rt2800_bbp_write(rt2x00dev, 21, 0x01);
+ +	udelay(1);
+@@ -935,16 +948,12 @@
+ +	rt2800_register_write(rt2x00dev, RF_BYPASS3, macorg5);
+ +	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, savemacsysctrl);
+ +	rt2800_register_write(rt2x00dev, 0x13b8, mac13b8);
+-+
+-+	rt2x00_info(rt2x00dev, "TX IQ Calibration Done!\n");
+-+
+-+	return;
+ +}
+ +
+  static void rt2800_bbp_core_soft_reset(struct rt2x00_dev *rt2x00dev,
+  				       bool set_bw, bool is_ht40)
+  {
+-@@ -9672,6 +10609,7 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -9653,6 +10554,7 @@ static void rt2800_init_rfcsr_6352(struc
+  	rt2800_rxdcoc_calibration(rt2x00dev);
+  	rt2800_bw_filter_calibration(rt2x00dev, true);
+  	rt2800_bw_filter_calibration(rt2x00dev, false);
+@@ -963,11 +972,11 @@
+ +#define RF_ALC_NUM	6
+ +#define CHAIN_NUM	2
+ +
+-+typedef struct rf_reg_pair {
+++struct rf_reg_pair {
+ +	u8 bank;
+ +	u8 reg;
+ +	u8 value;
+-+} rf_reg_pair;
+++};
+  
+  /* RT2800 driver data structure */
+  struct rt2800_drv_data {
+diff --git a/package/kernel/mac80211/patches/rt2x00/011-rt2x00-move-helper-functions-up-in-file.patch b/package/kernel/mac80211/patches/rt2x00/011-rt2x00-move-helper-functions-up-in-file.patch
+new file mode 100644
+index 0000000000..07a32b17be
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/011-rt2x00-move-helper-functions-up-in-file.patch
+@@ -0,0 +1,94 @@
++From patchwork Sat Sep 17 20:28:58 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979252
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:28:58 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 11/16] rt2x00: move helper functions up in file
++Message-ID: 
++ <c27baa8efd5c29e2bcb2432925d9cdc5c913a125.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Move register access helper functions up to the head of the file so
++they can be used in all functions.
++
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 40 +++++++++----------
++ 1 file changed, 20 insertions(+), 20 deletions(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -198,6 +198,26 @@ static void rt2800_rfcsr_write_dccal(str
++ 	rt2800_rfcsr_write_bank(rt2x00dev, 7, reg, value);
++ }
++ 
+++static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev,
+++				  const u8 reg, const u8 value)
+++{
+++	rt2800_bbp_write(rt2x00dev, 158, reg);
+++	rt2800_bbp_write(rt2x00dev, 159, value);
+++}
+++
+++static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg)
+++{
+++	rt2800_bbp_write(rt2x00dev, 158, reg);
+++	return rt2800_bbp_read(rt2x00dev, 159);
+++}
+++
+++static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev,
+++				  const u8 reg, const u8 value)
+++{
+++	rt2800_bbp_write(rt2x00dev, 195, reg);
+++	rt2800_bbp_write(rt2x00dev, 196, value);
+++}
+++
++ static u8 rt2800_rfcsr_read(struct rt2x00_dev *rt2x00dev,
++ 			    const unsigned int word)
++ {
++@@ -6947,26 +6967,6 @@ static void rt2800_init_bbp_5592(struct
++ 		rt2800_bbp_write(rt2x00dev, 103, 0xc0);
++ }
++ 
++-static void rt2800_bbp_glrt_write(struct rt2x00_dev *rt2x00dev,
++-				  const u8 reg, const u8 value)
++-{
++-	rt2800_bbp_write(rt2x00dev, 195, reg);
++-	rt2800_bbp_write(rt2x00dev, 196, value);
++-}
++-
++-static void rt2800_bbp_dcoc_write(struct rt2x00_dev *rt2x00dev,
++-				  const u8 reg, const u8 value)
++-{
++-	rt2800_bbp_write(rt2x00dev, 158, reg);
++-	rt2800_bbp_write(rt2x00dev, 159, value);
++-}
++-
++-static u8 rt2800_bbp_dcoc_read(struct rt2x00_dev *rt2x00dev, const u8 reg)
++-{
++-	rt2800_bbp_write(rt2x00dev, 158, reg);
++-	return rt2800_bbp_read(rt2x00dev, 159);
++-}
++-
++ static void rt2800_init_bbp_6352(struct rt2x00_dev *rt2x00dev)
++ {
++ 	u8 bbp;
+diff --git a/package/kernel/mac80211/patches/rt2x00/012-rt2x00-fix-HT20-HT40-bandwidth-switch-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/012-rt2x00-fix-HT20-HT40-bandwidth-switch-on-MT7620.patch
+new file mode 100644
+index 0000000000..e989205ba2
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/012-rt2x00-fix-HT20-HT40-bandwidth-switch-on-MT7620.patch
+@@ -0,0 +1,56 @@
++From patchwork Sat Sep 17 20:29:13 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979253
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:29:13 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 12/16] rt2x00: fix HT20/HT40 bandwidth switch on MT7620
++Message-ID: 
++ <1664d89ba149f7b0bcec18b2a2abaedf49654507.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Add missing configuration of the channel bandwidth filter to the
++channel setup function for MT7620.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 8 ++++++++
++ 1 file changed, 8 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -3855,6 +3855,14 @@ static void rt2800_config_channel_rf7620
++ 		rfcsr |= tx_agc_fc;
++ 		rt2800_rfcsr_write_bank(rt2x00dev, 7, 59, rfcsr);
++ 	}
+++
+++	if (conf_is_ht40(conf)) {
+++		rt2800_bbp_glrt_write(rt2x00dev, 141, 0x10);
+++		rt2800_bbp_glrt_write(rt2x00dev, 157, 0x2f);
+++	} else {
+++		rt2800_bbp_glrt_write(rt2x00dev, 141, 0x1a);
+++		rt2800_bbp_glrt_write(rt2x00dev, 157, 0x40);
+++	}
++ }
++ 
++ static void rt2800_config_alc(struct rt2x00_dev *rt2x00dev,
+diff --git a/package/kernel/mac80211/patches/rt2x00/013-rt2x00-set-correct-TX_SW_CFG1-MAC-register-for-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/013-rt2x00-set-correct-TX_SW_CFG1-MAC-register-for-MT7620.patch
+new file mode 100644
+index 0000000000..3d7af17b16
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/013-rt2x00-set-correct-TX_SW_CFG1-MAC-register-for-MT7620.patch
+@@ -0,0 +1,52 @@
++From patchwork Sat Sep 17 20:29:26 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979254
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:29:26 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 13/16] rt2x00: set correct TX_SW_CFG1 MAC register for
++ MT7620
++Message-ID: 
++ <4be38975ce600a34249e12d09a3cb758c6e71071.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Set correct TX_SW_CFG1 MAC register as it is done also in v3 of the
++vendor driver[1].
++
++[1]: https://gitlab.com/dm38/padavan-ng/-/blob/master/trunk/proprietary/rt_wifi/rtpci/3.0.X.X/mt76x2/chips/rt6352.c#L531
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 2 +-
++ 1 file changed, 1 insertion(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -5966,7 +5966,7 @@ static int rt2800_init_registers(struct
++ 		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_CFG1, 0x000C0001);
++ 		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);
+diff --git a/package/kernel/mac80211/patches/rt2x00/014-rt2x00-set-VGC-gain-for-both-chains-of-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/014-rt2x00-set-VGC-gain-for-both-chains-of-MT7620.patch
+new file mode 100644
+index 0000000000..27b8d92cd2
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/014-rt2x00-set-VGC-gain-for-both-chains-of-MT7620.patch
+@@ -0,0 +1,50 @@
++From patchwork Sat Sep 17 20:29:40 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979255
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:29:40 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 14/16] rt2x00: set VGC gain for both chains of MT7620
++Message-ID: 
++ <29e161397e5c9d9399da0fe87d44458aa2b90a78.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Set bbp66 for all chains of the MT7620.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 3 ++-
++ 1 file changed, 2 insertions(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -5743,7 +5743,8 @@ static inline void rt2800_set_vgc(struct
++ 	if (qual->vgc_level != vgc_level) {
++ 		if (rt2x00_rt(rt2x00dev, RT3572) ||
++ 		    rt2x00_rt(rt2x00dev, RT3593) ||
++-		    rt2x00_rt(rt2x00dev, RT3883)) {
+++		    rt2x00_rt(rt2x00dev, RT3883) ||
+++		    rt2x00_rt(rt2x00dev, RT6352)) {
++ 			rt2800_bbp_write_with_rx_chain(rt2x00dev, 66,
++ 						       vgc_level);
++ 		} else if (rt2x00_rt(rt2x00dev, RT5592)) {
+diff --git a/package/kernel/mac80211/patches/rt2x00/015-rt2x00-set-SoC-wmac-clock-register.patch b/package/kernel/mac80211/patches/rt2x00/015-rt2x00-set-SoC-wmac-clock-register.patch
+new file mode 100644
+index 0000000000..3cadc91da6
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/015-rt2x00-set-SoC-wmac-clock-register.patch
+@@ -0,0 +1,70 @@
++From patchwork Sat Sep 17 20:29:55 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979256
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++Date: Sat, 17 Sep 2022 21:29:55 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 15/16] rt2x00: set SoC wmac clock register
++Message-ID: 
++ <3e275d259f476f597dab91a9c395015ef3fe3284.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Instead of using the default value 33 (pci), set US_CYC_CNT init based
++on Programming guide:
++If available, set chipset bus clock with fallback to cpu clock/3.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 21 +++++++++++++++++++
++ 1 file changed, 21 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -6229,6 +6229,27 @@ static int rt2800_init_registers(struct
++ 		reg = rt2800_register_read(rt2x00dev, US_CYC_CNT);
++ 		rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, 125);
++ 		rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
+++	} else if (rt2x00_is_soc(rt2x00dev)) {
+++		struct clk *clk = clk_get_sys("bus", NULL);
+++		int rate;
+++
+++		if (IS_ERR(clk)) {
+++			clk = clk_get_sys("cpu", NULL);
+++
+++			if (IS_ERR(clk)) {
+++				rate = 125;
+++			} else {
+++				rate = clk_get_rate(clk) / 3000000;
+++				clk_put(clk);
+++			}
+++		} else {
+++			rate = clk_get_rate(clk) / 1000000;
+++			clk_put(clk);
+++		}
+++
+++		reg = rt2800_register_read(rt2x00dev, US_CYC_CNT);
+++		rt2x00_set_field32(&reg, US_CYC_CNT_CLOCK_CYCLE, rate);
+++		rt2800_register_write(rt2x00dev, US_CYC_CNT, reg);
++ 	}
++ 
++ 	reg = rt2800_register_read(rt2x00dev, HT_FBK_CFG0);
+diff --git a/package/kernel/mac80211/patches/rt2x00/016-rt2x00-correctly-set-BBP-register-86-for-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/016-rt2x00-correctly-set-BBP-register-86-for-MT7620.patch
+new file mode 100644
+index 0000000000..5ddbbf1dd6
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/016-rt2x00-correctly-set-BBP-register-86-for-MT7620.patch
+@@ -0,0 +1,79 @@
++From patchwork Sat Sep 17 20:30:09 2022
++Content-Type: text/plain; charset="utf-8"
++MIME-Version: 1.0
++Content-Transfer-Encoding: 7bit
++X-Patchwork-Submitter: Daniel Golle <daniel@makrotopia.org>
++X-Patchwork-Id: 12979257
++X-Patchwork-Delegate: kvalo@adurom.com
++Return-Path: <linux-wireless-owner@kernel.org>
++X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on
++	aws-us-west-2-korg-lkml-1.web.codeaurora.org
++Received: from vger.kernel.org (vger.kernel.org [23.128.96.18])
++	by smtp.lore.kernel.org (Postfix) with ESMTP id E9118ECAAA1
++	for <linux-wireless@archiver.kernel.org>;
++ Sat, 17 Sep 2022 20:30:22 +0000 (UTC)
++Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand
++        id S229639AbiIQUaV (ORCPT
++        <rfc822;linux-wireless@archiver.kernel.org>);
++        Sat, 17 Sep 2022 16:30:21 -0400
++Received: from lindbergh.monkeyblade.net ([23.128.96.19]:53912 "EHLO
++        lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org
++        with ESMTP id S229628AbiIQUaT (ORCPT
++        <rfc822;linux-wireless@vger.kernel.org>);
++        Sat, 17 Sep 2022 16:30:19 -0400
++Received: from fudo.makrotopia.org (fudo.makrotopia.org
++ [IPv6:2a07:2ec0:3002::71])
++        by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1AEA822B27
++        for <linux-wireless@vger.kernel.org>;
++ Sat, 17 Sep 2022 13:30:16 -0700 (PDT)
++Received: from local
++        by fudo.makrotopia.org with esmtpsa
++ (TLS1.3:TLS_AES_256_GCM_SHA384:256)
++         (Exim 4.96)
++        (envelope-from <daniel@makrotopia.org>)
++        id 1oZeS7-0003ra-0k;
++        Sat, 17 Sep 2022 22:30:15 +0200
++Date: Sat, 17 Sep 2022 21:30:09 +0100
++From: Daniel Golle <daniel@makrotopia.org>
++To: linux-wireless@vger.kernel.org, Stanislaw Gruszka <stf_xl@wp.pl>,
++        Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++        "David S. Miller" <davem@davemloft.net>,
++        Eric Dumazet <edumazet@google.com>,
++        Jakub Kicinski <kuba@kernel.org>,
++        Paolo Abeni <pabeni@redhat.com>,
++        Johannes Berg <johannes.berg@intel.com>
++Subject: [PATCH v3 16/16] rt2x00: correctly set BBP register 86 for MT7620
++Message-ID: 
++ <257267247ee4fa7ebc6a5d0c4948b3f8119c0d77.1663445157.git.daniel@makrotopia.org>
++References: <cover.1663445157.git.daniel@makrotopia.org>
++MIME-Version: 1.0
++Content-Disposition: inline
++In-Reply-To: <cover.1663445157.git.daniel@makrotopia.org>
++Precedence: bulk
++List-ID: <linux-wireless.vger.kernel.org>
++X-Mailing-List: linux-wireless@vger.kernel.org
++
++Instead of 0 set the correct value for BBP register 86 for MT7620.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++Acked-by: Stanislaw Gruszka <stf_xl@wp.pl>
++---
++ drivers/net/wireless/ralink/rt2x00/rt2800lib.c | 5 ++++-
++ 1 file changed, 4 insertions(+), 1 deletion(-)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -4225,7 +4225,10 @@ static void rt2800_config_channel(struct
++ 		rt2800_bbp_write(rt2x00dev, 62, 0x37 - rt2x00dev->lna_gain);
++ 		rt2800_bbp_write(rt2x00dev, 63, 0x37 - rt2x00dev->lna_gain);
++ 		rt2800_bbp_write(rt2x00dev, 64, 0x37 - rt2x00dev->lna_gain);
++-		rt2800_bbp_write(rt2x00dev, 86, 0);
+++		if (rt2x00_rt(rt2x00dev, RT6352))
+++			rt2800_bbp_write(rt2x00dev, 86, 0x38);
+++		else
+++			rt2800_bbp_write(rt2x00dev, 86, 0);
++ 	}
++ 
++ 	if (rf->channel <= 14) {
+diff --git a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
+index e74d9a9aa0..ba16e85510 100644
+--- a/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
++++ b/package/kernel/mac80211/patches/rt2x00/602-rt2x00-introduce-rt2x00eeprom.patch
+@@ -1,6 +1,6 @@
+ --- a/local-symbols
+ +++ b/local-symbols
+-@@ -332,6 +332,7 @@ RT2X00_LIB_FIRMWARE=
++@@ -345,6 +345,7 @@ RT2X00_LIB_FIRMWARE=
+  RT2X00_LIB_CRYPTO=
+  RT2X00_LIB_LEDS=
+  RT2X00_LIB_DEBUGFS=
+@@ -48,7 +48,7 @@
+  obj-$(CPTCFG_RT2X00_LIB_MMIO)		+= rt2x00mmio.o
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+-@@ -37,6 +37,8 @@ struct rt2800_drv_data {
++@@ -47,6 +47,8 @@ struct rt2800_drv_data {
+  	struct ieee80211_sta *wcid_to_sta[STA_IDS_SIZE];
+  };
+  
+@@ -57,7 +57,7 @@
+  struct rt2800_ops {
+  	u32 (*register_read)(struct rt2x00_dev *rt2x00dev,
+  			      const unsigned int offset);
+-@@ -135,6 +137,15 @@ static inline int rt2800_read_eeprom(str
++@@ -145,6 +147,15 @@ static inline int rt2800_read_eeprom(str
+  {
+  	const struct rt2800_ops *rt2800ops = rt2x00dev->ops->drv;
+  
+@@ -105,7 +105,7 @@
+  	.drv_init_registers	= rt2800mmio_init_registers,
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+-@@ -694,6 +694,7 @@ enum rt2x00_capability_flags {
++@@ -703,6 +703,7 @@ enum rt2x00_capability_flags {
+  	REQUIRE_HT_TX_DESC,
+  	REQUIRE_PS_AUTOWAKE,
+  	REQUIRE_DELAYED_RFKILL,
+@@ -113,7 +113,7 @@
+  
+  	/*
+  	 * Capabilities
+-@@ -970,6 +971,11 @@ struct rt2x00_dev {
++@@ -980,6 +981,11 @@ struct rt2x00_dev {
+  	const struct firmware *fw;
+  
+  	/*
+@@ -127,7 +127,7 @@
+  	DECLARE_KFIFO_PTR(txstatus_fifo, u32);
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1406,6 +1406,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
++@@ -1419,6 +1419,10 @@ int rt2x00lib_probe_dev(struct rt2x00_de
+  	INIT_DELAYED_WORK(&rt2x00dev->autowakeup_work, rt2x00lib_autowakeup);
+  	INIT_WORK(&rt2x00dev->sleep_work, rt2x00lib_sleep);
+  
+@@ -138,7 +138,7 @@
+  	/*
+  	 * Let the driver probe the device to detect the capabilities.
+  	 */
+-@@ -1549,6 +1553,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
++@@ -1559,6 +1563,11 @@ void rt2x00lib_remove_dev(struct rt2x00_
+  	 * Free the driver data.
+  	 */
+  	kfree(rt2x00dev->drv_data);
+@@ -193,7 +193,7 @@
+ +	if (pdata && pdata->eeprom_file_name)
+ +		return pdata->eeprom_file_name;
+ +
+-+	return NULL
+++	return NULL;
+ +}
+ +
+ +static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
+diff --git a/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch b/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch
+index 9dffef1812..431e090237 100644
+--- a/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch
++++ b/package/kernel/mac80211/patches/rt2x00/603-rt2x00-of_load_eeprom_filename.patch
+@@ -8,7 +8,7 @@
+  
+  #include "rt2x00.h"
+  #include "rt2x00lib.h"
+-@@ -34,11 +35,21 @@ static const char *
++@@ -34,10 +35,20 @@ static const char *
+  rt2x00lib_get_eeprom_file_name(struct rt2x00_dev *rt2x00dev)
+  {
+  	struct rt2x00_platform_data *pdata = rt2x00dev->dev->platform_data;
+@@ -20,14 +20,12 @@
+  	if (pdata && pdata->eeprom_file_name)
+  		return pdata->eeprom_file_name;
+  
+--	return NULL
+ +#ifdef CONFIG_OF
+ +	np = rt2x00dev->dev->of_node;
+ +	if (np && of_property_read_string(np, "ralink,eeprom", &eep) == 0)
+ +	    return eep;
+ +#endif
+ +
+-+	return NULL;
++ 	return NULL;
+  }
+  
+- static int rt2x00lib_request_eeprom_file(struct rt2x00_dev *rt2x00dev)
+diff --git a/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
+index 6a8e594d5e..ffee2189d2 100644
+--- a/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
++++ b/package/kernel/mac80211/patches/rt2x00/606-rt2x00-allow_disabling_bands_through_platform_data.patch
+@@ -12,7 +12,7 @@
+  #endif /* _RT2X00_PLATFORM_H */
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1012,6 +1012,22 @@ static int rt2x00lib_probe_hw_modes(stru
++@@ -1007,6 +1007,22 @@ static int rt2x00lib_probe_hw_modes(stru
+  	unsigned int num_rates;
+  	unsigned int i;
+  
+@@ -37,7 +37,7 @@
+  		num_rates += 4;
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+-@@ -399,6 +399,7 @@ struct hw_mode_spec {
++@@ -408,6 +408,7 @@ struct hw_mode_spec {
+  	unsigned int supported_bands;
+  #define SUPPORT_BAND_2GHZ	0x00000001
+  #define SUPPORT_BAND_5GHZ	0x00000002
+diff --git a/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
+index b5b2c61037..37553bb80a 100644
+--- a/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
++++ b/package/kernel/mac80211/patches/rt2x00/607-rt2x00-add_platform_data_mac_addr.patch
+@@ -1,19 +1,18 @@
+ --- 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 ieee80
++@@ -989,6 +989,12 @@ static void rt2x00lib_rate(struct ieee80
+  
+  void rt2x00lib_set_mac_address(struct rt2x00_dev *rt2x00dev, u8 *eeprom_mac_addr)
+  {
+ +	struct rt2x00_platform_data *pdata;
+- 	const char *mac_addr;
+- 
+++
+ +	pdata = rt2x00dev->dev->platform_data;
+ +	if (pdata && pdata->mac_address)
+ +		ether_addr_copy(eeprom_mac_addr, pdata->mac_address);
+ +
+- 	mac_addr = of_get_mac_address(rt2x00dev->dev->of_node);
+- 	if (!IS_ERR(mac_addr))
+- 		ether_addr_copy(eeprom_mac_addr, mac_addr);
++ 	of_get_mac_address(rt2x00dev->dev->of_node, eeprom_mac_addr);
++ 
++ 	if (!is_valid_ether_addr(eeprom_mac_addr)) {
+ --- a/include/linux/rt2x00_platform.h
+ +++ b/include/linux/rt2x00_platform.h
+ @@ -14,6 +14,7 @@
+diff --git a/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
+index ff8b2c947b..6211809c0a 100644
+--- a/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
++++ b/package/kernel/mac80211/patches/rt2x00/608-rt2x00-allow_disabling_bands_through_dts.patch
+@@ -1,6 +1,6 @@
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1016,6 +1016,16 @@ static int rt2x00lib_probe_hw_modes(stru
++@@ -1012,6 +1012,16 @@ static int rt2x00lib_probe_hw_modes(stru
+  	struct ieee80211_rate *rates;
+  	unsigned int num_rates;
+  	unsigned int i;
+diff --git a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
+index 039c6f6afc..acc8a8edb8 100644
+--- a/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
++++ b/package/kernel/mac80211/patches/rt2x00/610-rt2x00-change-led-polarity-from-OF.patch
+@@ -8,7 +8,7 @@
+  
+  #include "rt2x00.h"
+  #include "rt2800lib.h"
+-@@ -9530,6 +9531,17 @@ static int rt2800_init_eeprom(struct rt2
++@@ -11131,6 +11132,17 @@ static int rt2800_init_eeprom(struct rt2
+  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_assoc, LED_TYPE_ASSOC);
+  	rt2800_init_led(rt2x00dev, &rt2x00dev->led_qual, LED_TYPE_QUALITY);
+  
+diff --git a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
+index 88d6dd559b..5ef5fc8def 100644
+--- a/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
++++ b/package/kernel/mac80211/patches/rt2x00/611-rt2x00-add-AP+STA-support.patch
+@@ -1,6 +1,6 @@
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1344,7 +1344,7 @@ static inline void rt2x00lib_set_if_comb
++@@ -1358,7 +1358,7 @@ static inline void rt2x00lib_set_if_comb
+  	 */
+  	if_limit = &rt2x00dev->if_limits_ap;
+  	if_limit->max = rt2x00dev->ops->max_ap_intf;
+diff --git a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch b/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
+deleted file mode 100644
+index fca1fb2cd4..0000000000
+--- a/package/kernel/mac80211/patches/rt2x00/612-rt2x00-led-tpt-trigger-support.patch
++++ /dev/null
+@@ -1,44 +0,0 @@
+-From: David Bauer <mail@david-bauer.net>
+-Date: Mon, 16 Dec 2019 20:47:06 +0100
+-Subject: [PATCH] rt2x00: add throughput LED trigger
+-
+-This adds a (currently missing) throughput LED trigger for the rt2x00
+-driver. Previously, LED triggers had to be assigned to the netdev, which
+-was limited to a single VAP.
+-
+-Signed-off-by: David Bauer <mail@david-bauer.net>
+-Tested-by: Christoph Krapp <achterin@googlemail.com>
+-
+---- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1129,6 +1129,19 @@ static void rt2x00lib_remove_hw(struct r
+- 	kfree(rt2x00dev->spec.channels_info);
+- }
+- 
+-+static const struct ieee80211_tpt_blink rt2x00_tpt_blink[] = {
+-+	{ .throughput = 0 * 1024, .blink_time = 334 },
+-+	{ .throughput = 1 * 1024, .blink_time = 260 },
+-+	{ .throughput = 2 * 1024, .blink_time = 220 },
+-+	{ .throughput = 5 * 1024, .blink_time = 190 },
+-+	{ .throughput = 10 * 1024, .blink_time = 170 },
+-+	{ .throughput = 25 * 1024, .blink_time = 150 },
+-+	{ .throughput = 54 * 1024, .blink_time = 130 },
+-+	{ .throughput = 120 * 1024, .blink_time = 110 },
+-+	{ .throughput = 265 * 1024, .blink_time = 80 },
+-+	{ .throughput = 586 * 1024, .blink_time = 50 },
+-+};
+-+
+- static int rt2x00lib_probe_hw(struct rt2x00_dev *rt2x00dev)
+- {
+- 	struct hw_mode_spec *spec = &rt2x00dev->spec;
+-@@ -1210,6 +1223,10 @@ static int rt2x00lib_probe_hw(struct rt2
+- 
+- #undef RT2X00_TASKLET_INIT
+- 
+-+	ieee80211_create_tpt_led_trigger(rt2x00dev->hw,
+-+		IEEE80211_TPT_LEDTRIG_FL_RADIO, rt2x00_tpt_blink,
+-+		ARRAY_SIZE(rt2x00_tpt_blink));
+-+
+- 	/*
+- 	 * Register HW.
+- 	 */
+diff --git a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch b/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
+deleted file mode 100644
+index 31a7baeee7..0000000000
+--- a/package/kernel/mac80211/patches/rt2x00/992-rt2x00-save-survey-for-every-channel-visited.patch
++++ /dev/null
+@@ -1,183 +0,0 @@
+---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-@@ -1238,6 +1238,8 @@ void rt2800_watchdog(struct rt2x00_dev *
+- 	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:
+-@@ -1274,6 +1276,18 @@ void rt2800_watchdog(struct rt2x00_dev *
+- }
+- 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)
+- {
+-@@ -12199,26 +12213,30 @@ int rt2800_get_survey(struct ieee80211_h
+- {
+- 	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);
+--
+--	if (idle || 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->channel = &rt2x00dev->bands[band].channels[idx];
+-+
+-+	survey->filled = SURVEY_INFO_TIME |
+-+			 SURVEY_INFO_TIME_BUSY |
+-+			 SURVEY_INFO_TIME_EXT_BUSY;
+-+
+-+	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;
+---- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.h
+-@@ -243,6 +243,7 @@ bool rt2800_txstatus_timeout(struct rt2x
+- 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);
+---- a/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800pci.c
+-@@ -360,6 +360,7 @@ static const struct rt2x00lib_ops rt2800
+- 	.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,
+---- a/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2800soc.c
+-@@ -214,6 +214,7 @@ static const struct rt2x00lib_ops rt2800
+- 	.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,
+---- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+-@@ -183,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 {
+-@@ -567,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);
+-@@ -755,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;
+- 
+---- a/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-+++ b/drivers/net/wireless/ralink/rt2x00/rt2x00dev.c
+-@@ -1057,6 +1057,12 @@ static int rt2x00lib_probe_hw_modes(stru
+- 	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.
+- 	 */
+-@@ -1108,6 +1114,8 @@ static int rt2x00lib_probe_hw_modes(stru
+- 
+- 	return 0;
+- 
+-+ exit_free_rates:
+-+	kfree(rates);
+-  exit_free_channels:
+- 	kfree(channels);
+- 	rt2x00_err(rt2x00dev, "Allocation ieee80211 modes failed\n");
+---- 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
+- 		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/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch b/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch
+new file mode 100644
+index 0000000000..deaa03be6c
+--- /dev/null
++++ b/package/kernel/mac80211/patches/rt2x00/994-rt2x00-import-support-for-external-LNA-on-MT7620.patch
+@@ -0,0 +1,161 @@
++From 0fce1109f894ec7fcd72cb098843a1eff786716a Mon Sep 17 00:00:00 2001
++From: Daniel Golle <daniel@makrotopia.org>
++Date: Fri, 16 Sep 2022 20:49:42 +0100
++Subject: [PATCH 16/16] rt2x00: import support for external LNA on MT7620
++To: linux-wireless@vger.kernel.org,
++    Stanislaw Gruszka <stf_xl@wp.pl>,
++    Helmut Schaa <helmut.schaa@googlemail.com>
++Cc: Kalle Valo <kvalo@kernel.org>,
++    David S. Miller <davem@davemloft.net>,
++    Eric Dumazet <edumazet@google.com>,
++    Jakub Kicinski <kuba@kernel.org>,
++    Paolo Abeni <pabeni@redhat.com>,
++    Johannes Berg <johannes.berg@intel.com>
++
++In order to carry out calibration on boards with ePA or eLNA the PA pin
++needs to be switch to GPIO mode on MT7620. Implement that by selecting
++pinctrl state "pa_gpio" which should be defined for MT7620 boards with
++eLNA or ePA beside the "default" state.
++
++Reported-by: Serge Vasilugin <vasilugin@yandex.ru>
++Signed-off-by: Daniel Golle <daniel@makrotopia.org>
++---
++ .../net/wireless/ralink/rt2x00/rt2800lib.c    | 58 +++++++++++++++++++
++ drivers/net/wireless/ralink/rt2x00/rt2x00.h   |  5 ++
++ .../net/wireless/ralink/rt2x00/rt2x00soc.c    | 15 +++++
++ 3 files changed, 78 insertions(+)
++
++--- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
++@@ -304,6 +304,24 @@ static void rt2800_rf_write(struct rt2x0
++ 	mutex_unlock(&rt2x00dev->csr_mutex);
++ }
++ 
+++void rt6352_enable_pa_pin(struct rt2x00_dev *rt2x00dev, int enable)
+++{
+++	if (!rt2x00dev->pinctrl)
+++		return;
+++
+++	if (enable) {
+++		if (!rt2x00dev->pins_default)
+++			return;
+++
+++		pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_default);
+++	} else {
+++		if (!rt2x00dev->pins_pa_gpio)
+++			return;
+++
+++		pinctrl_select_state(rt2x00dev->pinctrl, rt2x00dev->pins_pa_gpio);
+++	}
+++}
+++
++ static const unsigned int rt2800_eeprom_map[EEPROM_WORD_COUNT] = {
++ 	[EEPROM_CHIP_ID]		= 0x0000,
++ 	[EEPROM_VERSION]		= 0x0001,
++@@ -4469,6 +4487,29 @@ static void rt2800_config_channel(struct
++ 			rt2800_register_write(rt2x00dev, TX1_RF_GAIN_ATTEN,
++ 					      0x6C6C6B6C);
++ 		}
+++
+++		if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
+++			reg = rt2800_register_read(rt2x00dev, RF_CONTROL3);
+++			reg |= 0x00000101;
+++			rt2800_register_write(rt2x00dev, RF_CONTROL3, reg);
+++
+++			reg = rt2800_register_read(rt2x00dev, RF_BYPASS3);
+++			reg |= 0x00000101;
+++			rt2800_register_write(rt2x00dev, RF_BYPASS3, reg);
+++
+++			rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
+++			rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
+++			rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42);
+++			rt2800_bbp_write(rt2x00dev, 75, 0x68);
+++			rt2800_bbp_write(rt2x00dev, 76, 0x4C);
+++			rt2800_bbp_write(rt2x00dev, 79, 0x1C);
+++			rt2800_bbp_write(rt2x00dev, 80, 0x0C);
+++			rt2800_bbp_write(rt2x00dev, 82, 0xB6);
+++			/* bank 0 RF reg 42 and glrt BBP reg 141 will be set in
+++			 * config channel function in dependence of channel and
+++			 * HT20/HT40 so don't touch it
+++			 */
+++		}
++ 	}
++ 
++ 	bbp = rt2800_bbp_read(rt2x00dev, 4);
++@@ -10583,6 +10624,7 @@ static void rt2800_init_rfcsr_6352(struc
++ 	rt2800_rfcsr_write_dccal(rt2x00dev, 5, 0x00);
++ 	rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
++ 
+++	rt6352_enable_pa_pin(rt2x00dev, 0);
++ 	rt2800_r_calibration(rt2x00dev);
++ 	rt2800_rf_self_txdc_cal(rt2x00dev);
++ 	rt2800_rxdcoc_calibration(rt2x00dev);
++@@ -10590,6 +10632,22 @@ static void rt2800_init_rfcsr_6352(struc
++ 	rt2800_bw_filter_calibration(rt2x00dev, false);
++ 	rt2800_loft_iq_calibration(rt2x00dev);
++ 	rt2800_rxiq_calibration(rt2x00dev);
+++	rt6352_enable_pa_pin(rt2x00dev, 1);
+++
+++	if (rt2x00_has_cap_external_lna_bg(rt2x00dev)) {
+++		rt2800_rfcsr_write_chanreg(rt2x00dev, 14, 0x66);
+++		rt2800_rfcsr_write_chanreg(rt2x00dev, 17, 0x20);
+++		rt2800_rfcsr_write_chanreg(rt2x00dev, 18, 0x42);
+++		rt2800_bbp_write(rt2x00dev, 75, 0x68);
+++		rt2800_bbp_write(rt2x00dev, 76, 0x4C);
+++		rt2800_bbp_write(rt2x00dev, 79, 0x1C);
+++		rt2800_bbp_write(rt2x00dev, 80, 0x0C);
+++		rt2800_bbp_write(rt2x00dev, 82, 0xB6);
+++		/* bank 0 RF reg 42 and glrt BBP reg 141 will be set in config
+++		 * channel function in dependence of channel and HT20/HT40,
+++		 * so don't touch them here.
+++		 */
+++	}
++ }
++ 
++ static void rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
++--- a/drivers/net/wireless/ralink/rt2x00/rt2x00.h
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00.h
++@@ -28,6 +28,7 @@
++ #include <linux/average.h>
++ #include <linux/usb.h>
++ #include <linux/clk.h>
+++#include <linux/pinctrl/consumer.h>
++ #include <linux/rt2x00_platform.h>
++ 
++ #include <net/mac80211.h>
++@@ -1029,6 +1030,11 @@ struct rt2x00_dev {
++ 
++ 	/* Clock for System On Chip devices. */
++ 	struct clk *clk;
+++
+++	/* pinctrl and states for System On Chip devices with PA/LNA. */
+++	struct pinctrl *pinctrl;
+++	struct pinctrl_state *pins_default;
+++	struct pinctrl_state *pins_pa_gpio;
++ };
++ 
++ struct rt2x00_bar_list_entry {
++--- a/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
+++++ b/drivers/net/wireless/ralink/rt2x00/rt2x00soc.c
++@@ -97,6 +97,21 @@ int rt2x00soc_probe(struct platform_devi
++ 	if (retval)
++ 		goto exit_free_reg;
++ 
+++	rt2x00dev->pinctrl = devm_pinctrl_get(&pdev->dev);
+++	if (IS_ERR(rt2x00dev->pinctrl)) {
+++		rt2x00dev->pinctrl = NULL;
+++		rt2x00dev->pins_default = NULL;
+++		rt2x00dev->pins_pa_gpio = NULL;
+++	} else {
+++		rt2x00dev->pins_default = pinctrl_lookup_state(rt2x00dev->pinctrl, "default");
+++		if (IS_ERR(rt2x00dev->pins_default))
+++			rt2x00dev->pins_default = NULL;
+++
+++		rt2x00dev->pins_pa_gpio = pinctrl_lookup_state(rt2x00dev->pinctrl, "pa_gpio");
+++		if (IS_ERR(rt2x00dev->pins_pa_gpio))
+++			rt2x00dev->pins_pa_gpio = NULL;
+++	}
+++
++ 	return 0;
++ 
++ exit_free_reg:
+diff --git a/package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch b/package/kernel/mac80211/patches/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch
+similarity index 100%
+rename from package/kernel/mac80211/patches/rt2x00/990-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch
+rename to package/kernel/mac80211/patches/rt2x00/995-rt2x00-mt7620-introduce-accessors-for-CHIP_VER-register.patch
+diff --git a/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch b/package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
+similarity index 95%
+rename from package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
+rename to package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
+index 3de00b2267..dab6e05ffd 100644
+--- a/package/kernel/mac80211/patches/rt2x00/991-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
++++ b/package/kernel/mac80211/patches/rt2x00/996-rt2x00-mt7620-differentiate-based-on-SoC-CHIP_VER.patch
+@@ -1,6 +1,6 @@
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800.h
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800.h
+-@@ -1042,6 +1042,11 @@
++@@ -1044,6 +1044,11 @@
+  #define MIMO_PS_CFG_RX_STBY_POL		FIELD32(0x00000010)
+  #define MIMO_PS_CFG_RX_RX_STBY0		FIELD32(0x00000020)
+  
+@@ -14,7 +14,7 @@
+   */
+ --- a/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+ +++ b/drivers/net/wireless/ralink/rt2x00/rt2800lib.c
+-@@ -3685,14 +3685,16 @@ static void rt2800_config_channel_rf7620
++@@ -3778,14 +3778,16 @@ static void rt2800_config_channel_rf7620
+  	rt2x00_set_field8(&rfcsr, RFCSR19_K, rf->rf4);
+  	rt2800_rfcsr_write(rt2x00dev, 19, rfcsr);
+  
+@@ -39,7 +39,7 @@
+  
+  	rfcsr = rt2800_rfcsr_read(rt2x00dev, 1);
+  	rt2x00_set_field8(&rfcsr, RFCSR1_TX2_EN_MT7620,
+-@@ -3726,18 +3728,23 @@ static void rt2800_config_channel_rf7620
++@@ -3819,18 +3821,23 @@ static void rt2800_config_channel_rf7620
+  		rt2800_rfcsr_write_dccal(rt2x00dev, 59, 0x20);
+  	}
+  
+@@ -73,9 +73,9 @@
+  
+  	if (!test_bit(DEVICE_STATE_SCANNING, &rt2x00dev->flags)) {
+  		if (conf_is_ht40(conf)) {
+-@@ -3837,25 +3844,29 @@ static void rt2800_config_alc(struct rt2
+- 	if (i == 10000)
+- 		rt2x00_warn(rt2x00dev, "Wait MAC Status to MAX !!!\n");
++@@ -3929,25 +3936,29 @@ static void rt2800_config_alc(struct rt2
++ 	if (unlikely(rt2800_wait_bbp_rf_ready(rt2x00dev, MAC_STATUS_CFG_BBP_RF_BUSY)))
++ 		rt2x00_warn(rt2x00dev, "RF busy while configuring ALC\n");
+  
+ -	if (chan->center_freq > 2457) {
+ -		bbp = rt2800_bbp_read(rt2x00dev, 30);
+@@ -121,12 +121,12 @@
+  	rt2800_register_write(rt2x00dev, MAC_SYS_CTRL, mac_sys_ctrl);
+  
+  	rt2800_vco_calibration(rt2x00dev);
+-@@ -5887,18 +5898,33 @@ static int rt2800_init_registers(struct
++@@ -6011,18 +6022,33 @@ static int rt2800_init_registers(struct
+  	} 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_CFG1, 0x000C0001);
+ -		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);
+@@ -150,7 +150,7 @@
+ +					      0x00550055);
+ +		} else {
+ +			rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000401);
+-+			rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0000);
+++			rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x000C0001);
+ +			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);
+@@ -167,7 +167,7 @@
+  		reg = rt2800_register_read(rt2x00dev, TX_ALC_CFG_1);
+  		rt2x00_set_field32(&reg, TX_ALC_CFG_1_ROS_BUSY_EN, 0);
+  		rt2800_register_write(rt2x00dev, TX_ALC_CFG_1, reg);
+-@@ -7042,14 +7068,16 @@ static void rt2800_init_bbp_6352(struct
++@@ -7127,14 +7153,16 @@ static void rt2800_init_bbp_6352(struct
+  	rt2800_bbp_write(rt2x00dev, 188, 0x00);
+  	rt2800_bbp_write(rt2x00dev, 189, 0x00);
+  
+@@ -192,7 +192,7 @@
+  
+  	/* BBP for G band GLRT function (BBP_128 ~ BBP_221) */
+  	rt2800_bbp_glrt_write(rt2x00dev, 0, 0x00);
+-@@ -10388,31 +10416,36 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -10408,31 +10436,36 @@ static void rt2800_init_rfcsr_6352(struc
+  	rt2800_rfcsr_write(rt2x00dev, 42, 0x5B);
+  	rt2800_rfcsr_write(rt2x00dev, 43, 0x00);
+  
+@@ -254,7 +254,7 @@
+  
+  	/* Initialize RF channel register to default value */
+  	rt2800_rfcsr_write_chanreg(rt2x00dev, 0, 0x03);
+-@@ -10478,63 +10511,71 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -10498,63 +10531,71 @@ static void rt2800_init_rfcsr_6352(struc
+  
+  	rt2800_rfcsr_write_bank(rt2x00dev, 6, 45, 0xC5);
+  
+@@ -383,7 +383,7 @@
+  
+  	/* Initialize RF DC calibration register to default value */
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 0, 0x47);
+-@@ -10597,12 +10638,17 @@ static void rt2800_init_rfcsr_6352(struc
++@@ -10617,12 +10658,17 @@ static void rt2800_init_rfcsr_6352(struc
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 62, 0x00);
+  	rt2800_rfcsr_write_dccal(rt2x00dev, 63, 0x00);
+  
+@@ -404,5 +404,5 @@
+ +		rt2800_rfcsr_write_dccal(rt2x00dev, 17, 0x7C);
+ +	}
+  
++ 	rt6352_enable_pa_pin(rt2x00dev, 0);
+  	rt2800_r_calibration(rt2x00dev);
+- 	rt2800_rf_self_txdc_cal(rt2x00dev);
 diff --git a/package/kernel/mac80211/patches/rtl/002-v5.13-rtlwifi-implement-set_tim-by-update-beacon-content.patch b/package/kernel/mac80211/patches/rtl/002-v5.13-rtlwifi-implement-set_tim-by-update-beacon-content.patch
 deleted file mode 100644
 index 3daf65e967..0000000000
@@ -5292,7 +9323,7 @@ diff --git a/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_
 similarity index 97%
 rename from package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 rename to package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
-index f58d2eb4cb..777c93cb90 100644
+index f58d2eb4cb..1ceb2be25c 100644
 --- a/package/kernel/mac80211/patches/subsys/306-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 +++ b/package/kernel/mac80211/patches/subsys/303-mac80211-set-up-the-fwd_skb-dev-for-mesh-forwarding.patch
 @@ -52,7 +52,7 @@ Signed-off-by: Xing Song <xing.song@mediatek.com>
@@ -5300,7 +9331,7 @@ index f58d2eb4cb..777c93cb90 100644
  --- a/net/mac80211/rx.c
  +++ b/net/mac80211/rx.c
 -@@ -2941,6 +2941,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
-+@@ -2949,6 +2949,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
++@@ -2948,6 +2948,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80
   	if (!fwd_skb)
   		goto out;
   
@@ -5358,7 +9389,7 @@ index 1c940d3db2..c43cd3acb9 100644
   
 diff --git a/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch
 new file mode 100644
-index 0000000000..c534d1570a
+index 0000000000..fba0912e80
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/307-mac80211_hwsim-make-6-GHz-channels-usable.patch
 @@ -0,0 +1,74 @@
@@ -5375,7 +9406,7 @@ index 0000000000..c534d1570a
 +
 +--- a/drivers/net/wireless/mac80211_hwsim.c
 ++++ b/drivers/net/wireless/mac80211_hwsim.c
-+@@ -3001,15 +3001,19 @@ static void mac80211_hwsim_he_capab(stru
++@@ -3004,15 +3004,19 @@ static void mac80211_hwsim_he_capab(stru
 + {
 + 	u16 n_iftype_data;
 + 
@@ -5398,7 +9429,7 @@ index 0000000000..c534d1570a
 + 		return;
 + 	}
 + 
-+@@ -3299,6 +3303,12 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3302,6 +3306,12 @@ static int mac80211_hwsim_new_radio(stru
 + 			sband->vht_cap.vht_mcs.tx_mcs_map =
 + 				sband->vht_cap.vht_mcs.rx_mcs_map;
 + 			break;
@@ -5411,7 +9442,7 @@ index 0000000000..c534d1570a
 + 		case NL80211_BAND_S1GHZ:
 + 			memcpy(&sband->s1g_cap, &hwsim_s1g_cap,
 + 			       sizeof(sband->s1g_cap));
-+@@ -3309,6 +3319,13 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3312,6 +3322,13 @@ static int mac80211_hwsim_new_radio(stru
 + 			continue;
 + 		}
 + 
@@ -5425,7 +9456,7 @@ index 0000000000..c534d1570a
 + 		sband->ht_cap.ht_supported = true;
 + 		sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
 + 				    IEEE80211_HT_CAP_GRN_FLD |
-+@@ -3322,10 +3339,6 @@ static int mac80211_hwsim_new_radio(stru
++@@ -3325,10 +3342,6 @@ static int mac80211_hwsim_new_radio(stru
 + 		sband->ht_cap.mcs.rx_mask[0] = 0xff;
 + 		sband->ht_cap.mcs.rx_mask[1] = 0xff;
 + 		sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
@@ -5438,7 +9469,7 @@ index 0000000000..c534d1570a
 + 	/* By default all radios belong to the first group */
 diff --git a/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch
 new file mode 100644
-index 0000000000..272d84f35e
+index 0000000000..4b9d874cfe
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/308-mac80211-add-support-for-.ndo_fill_forward_path.patch
 @@ -0,0 +1,178 @@
@@ -5513,7 +9544,7 @@ index 0000000000..272d84f35e
 + #endif /* __MAC80211_DRIVER_OPS */
 +--- a/net/mac80211/ieee80211_i.h
 ++++ b/net/mac80211/ieee80211_i.h
-+@@ -1485,7 +1485,7 @@ struct ieee80211_local {
++@@ -1490,7 +1490,7 @@ struct ieee80211_local {
 + };
 + 
 + static inline struct ieee80211_sub_if_data *
@@ -5625,9 +9656,21 @@ similarity index 100%
 rename from package/kernel/mac80211/patches/subsys/353-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch
 rename to package/kernel/mac80211/patches/subsys/309-mac80211-minstrel_ht-fix-MINSTREL_FRAC-macro.patch
 diff --git a/package/kernel/mac80211/patches/subsys/354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch b/package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch
-similarity index 100%
+similarity index 94%
 rename from package/kernel/mac80211/patches/subsys/354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch
 rename to package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch
+index 16bcbc2ef9..3be43b8782 100644
+--- a/package/kernel/mac80211/patches/subsys/354-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch
++++ b/package/kernel/mac80211/patches/subsys/310-mac80211-minstrel_ht-reduce-fluctuations-in-rate-pro.patch
+@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ 
+ --- a/net/mac80211/rc80211_minstrel_ht.c
+ +++ b/net/mac80211/rc80211_minstrel_ht.c
+-@@ -700,7 +700,8 @@ minstrel_ht_calc_rate_stats(struct minst
++@@ -703,7 +703,8 @@ minstrel_ht_calc_rate_stats(struct minst
+  	unsigned int cur_prob;
+  
+  	if (unlikely(mrs->attempts > 0)) {
 diff --git a/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch b/package/kernel/mac80211/patches/subsys/310-net-fq_impl-bulk-free-packets-from-a-flow-on-overmem.patch
 deleted file mode 100644
 index 05a888006e..0000000000
@@ -5730,18 +9773,45 @@ index 05a888006e..0000000000
 - 		fq->overlimit++;
 - 		if (oom) {
 diff --git a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch b/package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
-similarity index 93%
+similarity index 90%
 rename from package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
 rename to package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
-index aec2e07781..a6817bd4a6 100644
+index aec2e07781..13bed48ec6 100644
 --- a/package/kernel/mac80211/patches/subsys/355-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
 +++ b/package/kernel/mac80211/patches/subsys/311-mac80211-minstrel_ht-rework-rate-downgrade-code-and-.patch
+@@ -18,7 +18,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+ 
+ --- a/net/mac80211/rc80211_minstrel_ht.c
+ +++ b/net/mac80211/rc80211_minstrel_ht.c
+-@@ -511,6 +511,14 @@ minstrel_ht_set_best_prob_rate(struct mi
++@@ -514,6 +514,14 @@ minstrel_ht_set_best_prob_rate(struct mi
+  	int cur_tp_avg, cur_group, cur_idx;
+  	int max_gpr_group, max_gpr_idx;
+  	int max_gpr_tp_avg, max_gpr_prob;
+@@ -33,7 +33,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+  
+  	cur_group = MI_RATE_GROUP(index);
+  	cur_idx = MI_RATE_IDX(index);
+-@@ -532,11 +540,6 @@ minstrel_ht_set_best_prob_rate(struct mi
++@@ -535,11 +543,6 @@ minstrel_ht_set_best_prob_rate(struct mi
+  	    !minstrel_ht_is_legacy_group(max_tp_group))
+  		return;
+  
+@@ -45,7 +45,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
+  	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;
+-@@ -594,40 +597,6 @@ minstrel_ht_assign_best_tp_rates(struct
++@@ -597,40 +600,6 @@ minstrel_ht_assign_best_tp_rates(struct
+  
+  }
+  
 @@ -86,7 +86,7 @@ Signed-off-by: Felix Fietkau <nbd@nbd.name>
   static u16
   __minstrel_ht_get_sample_rate(struct minstrel_ht_sta *mi,
   			      enum minstrel_sample_type type)
 -@@ -1111,8 +1080,6 @@ minstrel_ht_update_stats(struct minstrel
-+@@ -1107,8 +1076,6 @@ minstrel_ht_update_stats(struct minstrel
++@@ -1110,8 +1079,6 @@ minstrel_ht_update_stats(struct minstrel
   
   	mi->max_prob_rate = tmp_max_prob_rate;
   
@@ -5750,7 +9820,7 @@ index aec2e07781..a6817bd4a6 100644
   
   #ifdef CPTCFG_MAC80211_DEBUGFS
 -@@ -1157,7 +1124,7 @@ minstrel_ht_txstat_valid(struct minstrel
-+@@ -1153,7 +1120,7 @@ minstrel_ht_txstat_valid(struct minstrel
++@@ -1156,7 +1123,7 @@ minstrel_ht_txstat_valid(struct minstrel
   }
   
   static void
@@ -5759,7 +9829,7 @@ index aec2e07781..a6817bd4a6 100644
   	int group, orig_group;
   
 -@@ -1172,11 +1139,7 @@ minstrel_downgrade_rate(struct minstrel_
-+@@ -1168,11 +1135,7 @@ minstrel_downgrade_rate(struct minstrel_
++@@ -1171,11 +1138,7 @@ minstrel_downgrade_rate(struct minstrel_
   		    minstrel_mcs_groups[orig_group].streams)
   			continue;
   
@@ -5768,7 +9838,7 @@ index aec2e07781..a6817bd4a6 100644
   }
   
 -@@ -1210,7 +1173,7 @@ minstrel_ht_tx_status(void *priv, struct
-+@@ -1183,7 +1146,7 @@ minstrel_ht_tx_status(void *priv, struct
++@@ -1186,7 +1149,7 @@ minstrel_ht_tx_status(void *priv, struct
   	struct ieee80211_tx_info *info = st->info;
   	struct minstrel_ht_sta *mi = priv_sta;
   	struct ieee80211_tx_rate *ar = info->status.rates;
@@ -5777,7 +9847,7 @@ index aec2e07781..a6817bd4a6 100644
   	u32 update_interval = mp->update_interval;
   	bool last, update = false;
 -@@ -1256,18 +1219,13 @@ minstrel_ht_tx_status(void *priv, struct
-+@@ -1233,18 +1196,13 @@ minstrel_ht_tx_status(void *priv, struct
++@@ -1236,18 +1199,13 @@ minstrel_ht_tx_status(void *priv, struct
   		/*
   		 * check for sudden death of spatial multiplexing,
   		 * downgrade to a lower number of streams if necessary.
@@ -6524,7 +10594,7 @@ index 1d7bbee400..0000000000
 - 	spin_unlock_bh(&fq->lock);
 diff --git a/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch
 new file mode 100644
-index 0000000000..4fc8b592c2
+index 0000000000..429886d701
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/313-nl80211-MBSSID-and-EMA-support-in-AP-mode.patch
 @@ -0,0 +1,493 @@
@@ -6768,7 +10838,7 @@ index 0000000000..4fc8b592c2
 + static const struct nla_policy nl80211_policy[NUM_NL80211_ATTR] = {
 + 	[0] = { .strict_start_type = NL80211_ATTR_HE_OBSS_PD },
 + 	[NL80211_ATTR_WIPHY] = { .type = NLA_U32 },
-+@@ -783,6 +793,9 @@ static const struct nla_policy nl80211_p
++@@ -788,6 +798,9 @@ static const struct nla_policy nl80211_p
 + 	[NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
 + 	[NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
 + 	[NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
@@ -6778,7 +10848,7 @@ index 0000000000..4fc8b592c2
 + };
 + 
 + /* policy for the key attributes */
-+@@ -2231,6 +2244,35 @@ fail:
++@@ -2236,6 +2249,35 @@ fail:
 + 	return -ENOBUFS;
 + }
 + 
@@ -6814,7 +10884,7 @@ index 0000000000..4fc8b592c2
 + struct nl80211_dump_wiphy_state {
 + 	s64 filter_wiphy;
 + 	long start;
-+@@ -2816,6 +2858,9 @@ static int nl80211_send_wiphy(struct cfg
++@@ -2821,6 +2863,9 @@ static int nl80211_send_wiphy(struct cfg
 + 		if (nl80211_put_sar_specs(rdev, msg))
 + 			goto nla_put_failure;
 + 
@@ -6824,7 +10894,7 @@ index 0000000000..4fc8b592c2
 + 		/* done */
 + 		state->split_start = 0;
 + 		break;
-+@@ -5005,6 +5050,96 @@ static int validate_beacon_tx_rate(struc
++@@ -5020,6 +5065,96 @@ static int validate_beacon_tx_rate(struc
 + 	return 0;
 + }
 + 
@@ -6921,7 +10991,7 @@ index 0000000000..4fc8b592c2
 + static int nl80211_parse_beacon(struct cfg80211_registered_device *rdev,
 + 				struct nlattr *attrs[],
 + 				struct cfg80211_beacon_data *bcn)
-+@@ -5085,6 +5220,17 @@ static int nl80211_parse_beacon(struct c
++@@ -5100,6 +5235,17 @@ static int nl80211_parse_beacon(struct c
 + 		bcn->ftm_responder = -1;
 + 	}
 + 
@@ -6939,7 +11009,7 @@ index 0000000000..4fc8b592c2
 + 	return 0;
 + }
 + 
-+@@ -5541,6 +5687,17 @@ static int nl80211_start_ap(struct sk_bu
++@@ -5556,6 +5702,17 @@ static int nl80211_start_ap(struct sk_bu
 + 			goto out;
 + 	}
 + 
@@ -6957,7 +11027,7 @@ index 0000000000..4fc8b592c2
 + 	nl80211_calculate_ap_params(&params);
 + 
 + 	if (info->attrs[NL80211_ATTR_EXTERNAL_AUTH_SUPPORT])
-+@@ -5562,6 +5719,11 @@ static int nl80211_start_ap(struct sk_bu
++@@ -5577,6 +5734,11 @@ static int nl80211_start_ap(struct sk_bu
 + 
 + out:
 + 	kfree(params.acl);
@@ -6969,7 +11039,7 @@ index 0000000000..4fc8b592c2
 + 
 + 	return err;
 + }
-+@@ -5586,12 +5748,14 @@ static int nl80211_set_beacon(struct sk_
++@@ -5601,12 +5763,14 @@ static int nl80211_set_beacon(struct sk_
 + 
 + 	err = nl80211_parse_beacon(rdev, info->attrs, &params);
 + 	if (err)
@@ -6985,7 +11055,7 @@ index 0000000000..4fc8b592c2
 + 	return err;
 + }
 + 
-+@@ -9268,12 +9432,14 @@ static int nl80211_channel_switch(struct
++@@ -9283,12 +9447,14 @@ static int nl80211_channel_switch(struct
 + 
 + 	err = nl80211_parse_beacon(rdev, info->attrs, &params.beacon_after);
 + 	if (err)
@@ -7003,7 +11073,7 @@ index 0000000000..4fc8b592c2
 + 
 + 	err = nla_parse_nested_deprecated(csa_attrs, NL80211_ATTR_MAX,
 + 					  info->attrs[NL80211_ATTR_CSA_IES],
-+@@ -9392,6 +9558,8 @@ skip_beacons:
++@@ -9407,6 +9573,8 @@ skip_beacons:
 + 	wdev_unlock(wdev);
 + 
 + free:
@@ -7012,7 +11082,7 @@ index 0000000000..4fc8b592c2
 + 	kfree(csa_attrs);
 + 	return err;
 + }
-+@@ -14939,6 +15107,8 @@ static int nl80211_color_change(struct s
++@@ -14959,6 +15127,8 @@ static int nl80211_color_change(struct s
 + 	wdev_unlock(wdev);
 + 
 + out:
@@ -7023,7 +11093,7 @@ index 0000000000..4fc8b592c2
 + }
 diff --git a/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch b/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch
 new file mode 100644
-index 0000000000..90c56b4e43
+index 0000000000..2038ee69db
 --- /dev/null
 +++ b/package/kernel/mac80211/patches/subsys/314-cfg80211-implement-APIs-for-dedicated-radar-detectio.patch
 @@ -0,0 +1,378 @@
@@ -7315,7 +11385,7 @@ index 0000000000..90c56b4e43
 ++}
 +--- a/net/wireless/nl80211.c
 ++++ b/net/wireless/nl80211.c
-+@@ -796,6 +796,7 @@ static const struct nla_policy nl80211_p
++@@ -801,6 +801,7 @@ static const struct nla_policy nl80211_p
 + 	[NL80211_ATTR_MBSSID_CONFIG] =
 + 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
 + 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
@@ -7323,7 +11393,7 @@ index 0000000000..90c56b4e43
 + };
 + 
 + /* policy for the key attributes */
-+@@ -9272,12 +9273,6 @@ static int nl80211_start_radar_detection
++@@ -9287,12 +9288,6 @@ static int nl80211_start_radar_detection
 + 	if (err)
 + 		return err;
 + 
@@ -7336,7 +11406,7 @@ index 0000000000..90c56b4e43
 + 	err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
 + 	if (err < 0)
 + 		return err;
-+@@ -9288,6 +9283,16 @@ static int nl80211_start_radar_detection
++@@ -9303,6 +9298,16 @@ static int nl80211_start_radar_detection
 + 	if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
 + 		return -EINVAL;
 + 
@@ -8142,1877 +12212,3647 @@ index d2ba140e6f..0000000000
 - 	TP_ARGS(local, sdata)
 - );
 - 
---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),
--@@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr,
-- 	)
-- );
+--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),
+-@@ -2788,6 +2788,22 @@ TRACE_EVENT(drv_sta_set_4addr,
+- 	)
+- );
+- 
+-+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),
+-+
+-+	TP_ARGS(local, sdata, sta, enabled)
+-+);
+-+
+-+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 */
+- 
+- #undef TRACE_INCLUDE_PATH
+diff --git a/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch
+new file mode 100644
+index 0000000000..362bb885d7
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch
+@@ -0,0 +1,99 @@
++From: Lorenzo Bianconi <lorenzo@kernel.org>
++Date: Wed, 3 Nov 2021 18:02:35 +0100
++Subject: [PATCH] cfg80211: fix possible NULL pointer dereference in
++ cfg80211_stop_offchan_radar_detection
++
++Fix the following NULL pointer dereference in
++cfg80211_stop_offchan_radar_detection routine that occurs when hostapd
++is stopped during the CAC on offchannel chain:
++
++Sat Jan  1 0[  779.567851]   ESR = 0x96000005
++0:12:50 2000 dae[  779.572346]   EC = 0x25: DABT (current EL), IL = 32 bits
++mon.debug hostap[  779.578984]   SET = 0, FnV = 0
++d: hostapd_inter[  779.583445]   EA = 0, S1PTW = 0
++face_deinit_free[  779.587936] Data abort info:
++: num_bss=1 conf[  779.592224]   ISV = 0, ISS = 0x00000005
++->num_bss=1
++Sat[  779.597403]   CM = 0, WnR = 0
++ Jan  1 00:12:50[  779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000
++ 2000 daemon.deb[  779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
++ug hostapd: host[  779.619657] Internal error: Oops: 96000005 [#1] SMP
++[  779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0
++[  779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT)
++[  779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--)
++[  779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211]
++[  779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211]
++[  779.800731] sp : ffffffc01204b7e0
++[  779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00
++[  779.809340] x27: 0000000000000000 x26: ffffffc008cb3050
++[  779.814644] x25: 0000000000000000 x24: 0000000000000002
++[  779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0
++[  779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00
++[  779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0
++[  779.835860] x17: 00000000ffffffff x16: 0000000000000000
++[  779.841164] x15: 0000000040d59200 x14: 00000000000019c0
++[  779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6
++[  779.851771] x11: 0000000000000141 x10: 0000000000000820
++[  779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038
++[  779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038
++[  779.867683] x5 : 0000000000000e90 x4 : 0000000000000038
++[  779.872987] x3 : 0000000000000002 x2 : 0000000000000004
++[  779.878291] x1 : 0000000000000000 x0 : 0000000000000000
++[  779.883594] Call trace:
++[  779.886039]  cfg80211_chandef_valid+0x10/0x490 [cfg80211]
++[  779.891434]  cfg80211_check_station_change+0x3190/0x3950 [cfg80211]
++[  779.897697]  nl80211_radar_notify+0x138/0x19c [cfg80211]
++[  779.903005]  cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211]
++[  779.909616]  __cfg80211_leave+0x2c/0x190 [cfg80211]
++[  779.914490]  cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211]
++[  779.920404]  raw_notifier_call_chain+0x50/0x70
++[  779.924841]  call_netdevice_notifiers_info+0x54/0xa0
++[  779.929796]  __dev_close_many+0x40/0x100
++[  779.933712]  __dev_change_flags+0x98/0x190
++[  779.937800]  dev_change_flags+0x20/0x60
++[  779.941628]  devinet_ioctl+0x534/0x6d0
++[  779.945370]  inet_ioctl+0x1bc/0x230
++[  779.948849]  sock_do_ioctl+0x44/0x200
++[  779.952502]  sock_ioctl+0x268/0x4c0
++[  779.955985]  __arm64_sys_ioctl+0xac/0xd0
++[  779.959900]  el0_svc_common.constprop.0+0x60/0x110
++[  779.964682]  do_el0_svc+0x1c/0x24
++[  779.967990]  el0_svc+0x10/0x1c
++[  779.971036]  el0_sync_handler+0x9c/0x120
++[  779.974950]  el0_sync+0x148/0x180
++[  779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000)
++[  779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]---
++[  779.996400] Kernel panic - not syncing: Oops: Fatal exception
++[  780.002139] SMP: stopping secondary CPUs
++[  780.006057] Kernel Offset: disabled
++[  780.009537] CPU features: 0x0000002,04002004
++[  780.013796] Memory Limit: none
++
++Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW")
++Reported-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
++Tested-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/mlme.c
+++++ b/net/wireless/mlme.c
++@@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg8
++ 
++ 	lockdep_assert_wiphy(&rdev->wiphy);
++ 
+++	if (!cfg80211_chandef_valid(chandef))
+++		return;
+++
++ 	if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev)
++ 		return;
++ 
++@@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detecti
++ 
++ 	rdev_set_radar_offchan(rdev, NULL);
++ 
++-	__cfg80211_offchan_cac_event(rdev, NULL, NULL,
+++	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
++ 				     NL80211_RADAR_CAC_ABORTED);
++ }
+diff --git a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch b/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch
+deleted file mode 100644
+index 91987ed759..0000000000
+--- a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch
++++ /dev/null
+@@ -1,116 +0,0 @@
+-From: Markus Theil <markus.theil@tu-ilmenau.de>
+-Date: Sat, 6 Feb 2021 12:51:12 +0100
+-Subject: [PATCH] mac80211: enable QoS support for nl80211 ctrl port
+-
+-This patch unifies sending control port frames
+-over nl80211 and AF_PACKET sockets a little more.
+-
+-Before this patch, EAPOL frames got QoS prioritization
+-only when using AF_PACKET sockets.
+-
+-__ieee80211_select_queue only selects a QoS-enabled queue
+-for control port frames, when the control port protocol
+-is set correctly on the skb. For the AF_PACKET path this
+-works, but the nl80211 path used ETH_P_802_3.
+-
+-Another check for injected frames in wme.c then prevented
+-the QoS TID to be copied in the frame.
+-
+-In order to fix this, get rid of the frame injection marking
+-for nl80211 ctrl port and set the correct ethernet protocol.
+-
+-Please note:
+-An erlier version of this path tried to prevent
+-frame aggregation for control port frames in order to speed up
+-the initial connection setup a little. This seemed to cause
+-issues on my older Intel dvm-based hardware, and was therefore
+-removed again. Future commits which try to reintroduce this
+-have to check carefully how hw behaves with aggregated and
+-non-aggregated traffic for the same TID.
+-My NIC: Intel(R) Centrino(R) Ultimate-N 6300 AGN, REV=0x74
+-
+-Reported-by: kernel test robot <lkp@intel.com>
+-Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
+-Link: https://lore.kernel.org/r/20210206115112.567881-1-markus.theil@tu-ilmenau.de
+-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+----
+-
+---- a/net/mac80211/status.c
+-+++ b/net/mac80211/status.c
+-@@ -628,16 +628,12 @@ static void ieee80211_report_ack_skb(str
+- 		u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie;
+- 		struct ieee80211_sub_if_data *sdata;
+- 		struct ieee80211_hdr *hdr = (void *)skb->data;
+--		__be16 ethertype = 0;
+--
+--		if (skb->len >= ETH_HLEN && skb->protocol == cpu_to_be16(ETH_P_802_3))
+--			skb_copy_bits(skb, 2 * ETH_ALEN, &ethertype, ETH_TLEN);
+- 
+- 		rcu_read_lock();
+- 		sdata = ieee80211_sdata_from_skb(local, skb);
+- 		if (sdata) {
+--			if (ethertype == sdata->control_port_protocol ||
+--			    ethertype == cpu_to_be16(ETH_P_PREAUTH))
+-+			if (skb->protocol == sdata->control_port_protocol ||
+-+			    skb->protocol == cpu_to_be16(ETH_P_PREAUTH))
+- 				cfg80211_control_port_tx_status(&sdata->wdev,
+- 								cookie,
+- 								skb->data,
+---- a/net/mac80211/tx.c
+-+++ b/net/mac80211/tx.c
+-@@ -1195,9 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su
+- 			tx->sta = rcu_dereference(sdata->u.vlan.sta);
+- 			if (!tx->sta && sdata->wdev.use_4addr)
+- 				return TX_DROP;
+--		} else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+--					  IEEE80211_TX_CTL_INJECTED) ||
+--			   tx->sdata->control_port_protocol == tx->skb->protocol) {
+-+		} else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
+- 			tx->sta = sta_info_get_bss(sdata, hdr->addr1);
+- 		}
+- 		if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
+-@@ -5455,6 +5453,7 @@ int ieee80211_tx_control_port(struct wip
+- {
+- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+- 	struct ieee80211_local *local = sdata->local;
+-+	struct sta_info *sta;
+- 	struct sk_buff *skb;
+- 	struct ethhdr *ehdr;
+- 	u32 ctrl_flags = 0;
+-@@ -5477,8 +5476,7 @@ int ieee80211_tx_control_port(struct wip
+- 	if (cookie)
+- 		ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
+- 
+--	flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
+--		 IEEE80211_TX_CTL_INJECTED;
+-+	flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX;
 - 
--+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),
+- 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+- 			    sizeof(struct ethhdr) + len);
+-@@ -5495,10 +5493,25 @@ int ieee80211_tx_control_port(struct wip
+- 	ehdr->h_proto = proto;
+- 
+- 	skb->dev = dev;
+--	skb->protocol = htons(ETH_P_802_3);
+-+	skb->protocol = proto;
+- 	skb_reset_network_header(skb);
+- 	skb_reset_mac_header(skb);
+- 
+-+	/* update QoS header to prioritize control port frames if possible,
+-+	 * priorization also happens for control port frames send over
+-+	 * AF_PACKET
+-+	 */
+-+	rcu_read_lock();
 -+
--+	TP_ARGS(local, sdata, sta, enabled)
--+);
+-+	if (ieee80211_lookup_ra_sta(sdata, skb, &sta) == 0 && !IS_ERR(sta)) {
+-+		u16 queue = __ieee80211_select_queue(sdata, sta, skb);
 -+
--+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),
+-+		skb_set_queue_mapping(skb, queue);
+-+		skb_get_hash(skb);
+-+	}
 -+
--+	TP_ARGS(local, sdata, sta, enabled)
--+);
+-+	rcu_read_unlock();
 -+
-- #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
+- 	/* mutex lock is only needed for incrementing the cookie counter */
+- 	mutex_lock(&local->mtx);
 - 
-- #undef TRACE_INCLUDE_PATH
-diff --git a/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch
+diff --git a/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch
+new file mode 100644
+index 0000000000..df7afefb34
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch
+@@ -0,0 +1,136 @@
++From: Lorenzo Bianconi <lorenzo@kernel.org>
++Date: Tue, 16 Nov 2021 12:41:52 +0100
++Subject: [PATCH] cfg80211: schedule offchan_cac_abort_wk in
++ cfg80211_radar_event
++
++If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event
++routine adding offchan parameter to cfg80211_radar_event signature.
++Rename cfg80211_radar_event in __cfg80211_radar_event and introduce
++the two following inline helpers:
++- cfg80211_radar_event
++- cfg80211_offchan_radar_event
++Doing so the drv will not need to run cfg80211_offchan_cac_abort() after
++radar detection on the offchannel chain.
++
++Tested-by: Owen Peng <owen.peng@mediatek.com>
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/include/net/cfg80211.h
+++++ b/include/net/cfg80211.h
++@@ -7580,15 +7580,33 @@ void cfg80211_cqm_txe_notify(struct net_
++ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
++ 
++ /**
++- * cfg80211_radar_event - radar detection event
+++ * __cfg80211_radar_event - radar detection event
++  * @wiphy: the wiphy
++  * @chandef: chandef for the current channel
+++ * @offchan: the radar has been detected on the offchannel chain
++  * @gfp: context flags
++  *
++  * This function is called when a radar is detected on the current chanenl.
++  */
++-void cfg80211_radar_event(struct wiphy *wiphy,
++-			  struct cfg80211_chan_def *chandef, gfp_t gfp);
+++void __cfg80211_radar_event(struct wiphy *wiphy,
+++			    struct cfg80211_chan_def *chandef,
+++			    bool offchan, gfp_t gfp);
+++
+++static inline void
+++cfg80211_radar_event(struct wiphy *wiphy,
+++		     struct cfg80211_chan_def *chandef,
+++		     gfp_t gfp)
+++{
+++	__cfg80211_radar_event(wiphy, chandef, false, gfp);
+++}
+++
+++static inline void
+++cfg80211_offchan_radar_event(struct wiphy *wiphy,
+++			     struct cfg80211_chan_def *chandef,
+++			     gfp_t gfp)
+++{
+++	__cfg80211_radar_event(wiphy, chandef, true, gfp);
+++}
++ 
++ /**
++  * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event
++--- a/net/wireless/mlme.c
+++++ b/net/wireless/mlme.c
++@@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(s
++ }
++ 
++ 
++-void cfg80211_radar_event(struct wiphy *wiphy,
++-			  struct cfg80211_chan_def *chandef,
++-			  gfp_t gfp)
+++void __cfg80211_radar_event(struct wiphy *wiphy,
+++			    struct cfg80211_chan_def *chandef,
+++			    bool offchan, gfp_t gfp)
++ {
++ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++ 
++-	trace_cfg80211_radar_event(wiphy, chandef);
+++	trace_cfg80211_radar_event(wiphy, chandef, offchan);
++ 
++ 	/* only set the chandef supplied channel to unavailable, in
++ 	 * case the radar is detected on only one of multiple channels
++@@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy *
++ 	 */
++ 	cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
++ 
+++	if (offchan)
+++		queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
+++
++ 	cfg80211_sched_dfs_chan_update(rdev);
++ 
++ 	nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
++@@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy *
++ 	memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
++ 	queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
++ }
++-EXPORT_SYMBOL(cfg80211_radar_event);
+++EXPORT_SYMBOL(__cfg80211_radar_event);
++ 
++ void cfg80211_cac_event(struct net_device *netdev,
++ 			const struct cfg80211_chan_def *chandef,
++@@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg8
++ 		rdev->offchan_radar_wdev = NULL;
++ 		break;
++ 	case NL80211_RADAR_CAC_ABORTED:
++-		cancel_delayed_work(&rdev->offchan_cac_done_wk);
+++		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
+++			return;
++ 		wdev = rdev->offchan_radar_wdev;
++ 		rdev->offchan_radar_wdev = NULL;
++ 		break;
++--- a/net/wireless/trace.h
+++++ b/net/wireless/trace.h
++@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_n
++ );
++ 
++ TRACE_EVENT(cfg80211_radar_event,
++-	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
++-	TP_ARGS(wiphy, chandef),
+++	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
+++		 bool offchan),
+++	TP_ARGS(wiphy, chandef, offchan),
++ 	TP_STRUCT__entry(
++ 		WIPHY_ENTRY
++ 		CHAN_DEF_ENTRY
+++		__field(bool, offchan)
++ 	),
++ 	TP_fast_assign(
++ 		WIPHY_ASSIGN;
++ 		CHAN_DEF_ASSIGN(chandef);
+++		__entry->offchan = offchan;
++ 	),
++-	TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
++-		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
+++	TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d",
+++		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan)
++ );
++ 
++ TRACE_EVENT(cfg80211_cac_event,
+diff --git a/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch
+new file mode 100644
+index 0000000000..a1b6e3c80d
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch
+@@ -0,0 +1,220 @@
++From: Lorenzo Bianconi <lorenzo@kernel.org>
++Date: Tue, 16 Nov 2021 15:03:36 +0100
++Subject: [PATCH] cfg80211: allow continuous radar monitoring on offchannel
++ chain
++
++Allow continuous radar detection on the offchannel chain in order
++to switch to the monitored channel whenever the underlying driver
++reports a radar pattern on the main channel.
++
++Tested-by: Owen Peng <owen.peng@mediatek.com>
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/wireless/chan.c
+++++ b/net/wireless/chan.c
++@@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan(
++ 	return false;
++ }
++ 
+++static bool
+++cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
+++				 struct ieee80211_channel *channel)
+++{
+++	if (!rdev->offchan_radar_wdev)
+++		return false;
+++
+++	if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef))
+++		return false;
+++
+++	return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel);
+++}
+++
++ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
++ 				  struct ieee80211_channel *chan)
++ {
++@@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct
++ 
++ 		if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
++ 			return true;
+++
+++		if (cfg80211_offchan_chain_is_active(rdev, chan))
+++			return true;
++ 	}
++ 
++ 	return false;
++--- a/net/wireless/mlme.c
+++++ b/net/wireless/mlme.c
++@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8
++ 	if (!cfg80211_chandef_valid(chandef))
++ 		return;
++ 
++-	if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev)
+++	if (!rdev->offchan_radar_wdev)
++ 		return;
++ 
++ 	switch (event) {
++@@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg8
++ 		queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
++ 		cfg80211_sched_dfs_chan_update(rdev);
++ 		wdev = rdev->offchan_radar_wdev;
++-		rdev->offchan_radar_wdev = NULL;
++ 		break;
++ 	case NL80211_RADAR_CAC_ABORTED:
++ 		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
++ 			return;
++ 		wdev = rdev->offchan_radar_wdev;
++-		rdev->offchan_radar_wdev = NULL;
++ 		break;
++ 	case NL80211_RADAR_CAC_STARTED:
++-		WARN_ON(!wdev);
++-		rdev->offchan_radar_wdev = wdev;
++ 		break;
++ 	default:
++ 		return;
++@@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg802
++ 			   enum nl80211_radar_event event)
++ {
++ 	wiphy_lock(&rdev->wiphy);
++-	__cfg80211_offchan_cac_event(rdev, NULL, chandef, event);
+++	__cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev,
+++				     chandef, event);
++ 	wiphy_unlock(&rdev->wiphy);
++ }
++ 
++@@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(s
++ 				     NL80211_EXT_FEATURE_RADAR_OFFCHAN))
++ 		return -EOPNOTSUPP;
++ 
++-	if (rdev->offchan_radar_wdev)
+++	/* Offchannel chain already locked by another wdev */
+++	if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev)
+++		return -EBUSY;
+++
+++	/* CAC already in progress on the offchannel chain */
+++	if (rdev->offchan_radar_wdev == wdev &&
+++	    delayed_work_pending(&rdev->offchan_cac_done_wk))
++ 		return -EBUSY;
++ 
++ 	err = rdev_set_radar_offchan(rdev, chandef);
++@@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(s
++ 		cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
++ 
++ 	rdev->offchan_radar_chandef = *chandef;
+++	rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */
+++
++ 	__cfg80211_offchan_cac_event(rdev, wdev, chandef,
++ 				     NL80211_RADAR_CAC_STARTED);
++ 	queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk,
++@@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detecti
++ 		return;
++ 
++ 	rdev_set_radar_offchan(rdev, NULL);
+++	rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */
++ 
++ 	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
++ 				     NL80211_RADAR_CAC_ABORTED);
++--- a/net/wireless/nl80211.c
+++++ b/net/wireless/nl80211.c
++@@ -9278,42 +9278,60 @@ static int nl80211_start_radar_detection
++ 	struct cfg80211_chan_def chandef;
++ 	enum nl80211_dfs_regions dfs_region;
++ 	unsigned int cac_time_ms;
++-	int err;
+++	int err = -EINVAL;
+++
+++	flush_delayed_work(&rdev->dfs_update_channels_wk);
+++
+++	wiphy_lock(wiphy);
++ 
++ 	dfs_region = reg_get_dfs_region(wiphy);
++ 	if (dfs_region == NL80211_DFS_UNSET)
++-		return -EINVAL;
+++		goto unlock;
++ 
++ 	err = nl80211_parse_chandef(rdev, info, &chandef);
++ 	if (err)
++-		return err;
+++		goto unlock;
++ 
++ 	err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
++ 	if (err < 0)
++-		return err;
+++		goto unlock;
++ 
++-	if (err == 0)
++-		return -EINVAL;
+++	if (err == 0) {
+++		err = -EINVAL;
+++		goto unlock;
+++	}
++ 
++-	if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
++-		return -EINVAL;
+++	if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) {
+++		err = -EINVAL;
+++		goto unlock;
+++	}
++ 
++-	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN]))
++-		return cfg80211_start_offchan_radar_detection(rdev, wdev,
++-							      &chandef);
+++	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) {
+++		err = cfg80211_start_offchan_radar_detection(rdev, wdev,
+++							     &chandef);
+++		goto unlock;
+++	}
++ 
++-	if (netif_carrier_ok(dev))
++-		return -EBUSY;
+++	if (netif_carrier_ok(dev)) {
+++		err = -EBUSY;
+++		goto unlock;
+++	}
++ 
++-	if (wdev->cac_started)
++-		return -EBUSY;
+++	if (wdev->cac_started) {
+++		err = -EBUSY;
+++		goto unlock;
+++	}
++ 
++ 	/* CAC start is offloaded to HW and can't be started manually */
++-	if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
++-		return -EOPNOTSUPP;
+++	if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) {
+++		err = -EOPNOTSUPP;
+++		goto unlock;
+++	}
++ 
++-	if (!rdev->ops->start_radar_detection)
++-		return -EOPNOTSUPP;
+++	if (!rdev->ops->start_radar_detection) {
+++		err = -EOPNOTSUPP;
+++		goto unlock;
+++	}
++ 
++ 	cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
++ 	if (WARN_ON(!cac_time_ms))
++@@ -9326,6 +9344,9 @@ static int nl80211_start_radar_detection
++ 		wdev->cac_start_time = jiffies;
++ 		wdev->cac_time_ms = cac_time_ms;
++ 	}
+++unlock:
+++	wiphy_unlock(wiphy);
+++
++ 	return err;
++ }
++ 
++@@ -15961,7 +15982,8 @@ static const struct genl_small_ops nl802
++ 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
++ 		.doit = nl80211_start_radar_detection,
++ 		.flags = GENL_UNS_ADMIN_PERM,
++-		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
+++		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+++				  NL80211_FLAG_NO_WIPHY_MTX,
++ 	},
++ 	{
++ 		.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
+diff --git a/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch
 new file mode 100644
-index 0000000000..362bb885d7
+index 0000000000..eb80afbccb
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/316-cfg80211-fix-possible-NULL-pointer-dereference-in-cf.patch
-@@ -0,0 +1,99 @@
++++ b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch
+@@ -0,0 +1,67 @@
 +From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Wed, 3 Nov 2021 18:02:35 +0100
-+Subject: [PATCH] cfg80211: fix possible NULL pointer dereference in
-+ cfg80211_stop_offchan_radar_detection
-+
-+Fix the following NULL pointer dereference in
-+cfg80211_stop_offchan_radar_detection routine that occurs when hostapd
-+is stopped during the CAC on offchannel chain:
++Date: Sat, 23 Oct 2021 11:10:51 +0200
++Subject: [PATCH] mac80211: introduce set_radar_offchan callback
 +
-+Sat Jan  1 0[  779.567851]   ESR = 0x96000005
-+0:12:50 2000 dae[  779.572346]   EC = 0x25: DABT (current EL), IL = 32 bits
-+mon.debug hostap[  779.578984]   SET = 0, FnV = 0
-+d: hostapd_inter[  779.583445]   EA = 0, S1PTW = 0
-+face_deinit_free[  779.587936] Data abort info:
-+: num_bss=1 conf[  779.592224]   ISV = 0, ISS = 0x00000005
-+->num_bss=1
-+Sat[  779.597403]   CM = 0, WnR = 0
-+ Jan  1 00:12:50[  779.601749] user pgtable: 4k pages, 39-bit VAs, pgdp=00000000418b2000
-+ 2000 daemon.deb[  779.609601] [0000000000000000] pgd=0000000000000000, p4d=0000000000000000, pud=0000000000000000
-+ug hostapd: host[  779.619657] Internal error: Oops: 96000005 [#1] SMP
-+[  779.770810] CPU: 0 PID: 2202 Comm: hostapd Not tainted 5.10.75 #0
-+[  779.776892] Hardware name: MediaTek MT7622 RFB1 board (DT)
-+[  779.782370] pstate: 80000005 (Nzcv daif -PAN -UAO -TCO BTYPE=--)
-+[  779.788384] pc : cfg80211_chandef_valid+0x10/0x490 [cfg80211]
-+[  779.794128] lr : cfg80211_check_station_change+0x3190/0x3950 [cfg80211]
-+[  779.800731] sp : ffffffc01204b7e0
-+[  779.804036] x29: ffffffc01204b7e0 x28: ffffff80039bdc00
-+[  779.809340] x27: 0000000000000000 x26: ffffffc008cb3050
-+[  779.814644] x25: 0000000000000000 x24: 0000000000000002
-+[  779.819948] x23: ffffff8002630000 x22: ffffff8003e748d0
-+[  779.825252] x21: 0000000000000cc0 x20: ffffff8003da4a00
-+[  779.830556] x19: 0000000000000000 x18: ffffff8001bf7ce0
-+[  779.835860] x17: 00000000ffffffff x16: 0000000000000000
-+[  779.841164] x15: 0000000040d59200 x14: 00000000000019c0
-+[  779.846467] x13: 00000000000001c8 x12: 000636b9e9dab1c6
-+[  779.851771] x11: 0000000000000141 x10: 0000000000000820
-+[  779.857076] x9 : 0000000000000000 x8 : ffffff8003d7d038
-+[  779.862380] x7 : 0000000000000000 x6 : ffffff8003d7d038
-+[  779.867683] x5 : 0000000000000e90 x4 : 0000000000000038
-+[  779.872987] x3 : 0000000000000002 x2 : 0000000000000004
-+[  779.878291] x1 : 0000000000000000 x0 : 0000000000000000
-+[  779.883594] Call trace:
-+[  779.886039]  cfg80211_chandef_valid+0x10/0x490 [cfg80211]
-+[  779.891434]  cfg80211_check_station_change+0x3190/0x3950 [cfg80211]
-+[  779.897697]  nl80211_radar_notify+0x138/0x19c [cfg80211]
-+[  779.903005]  cfg80211_stop_offchan_radar_detection+0x7c/0x8c [cfg80211]
-+[  779.909616]  __cfg80211_leave+0x2c/0x190 [cfg80211]
-+[  779.914490]  cfg80211_register_netdevice+0x1c0/0x6d0 [cfg80211]
-+[  779.920404]  raw_notifier_call_chain+0x50/0x70
-+[  779.924841]  call_netdevice_notifiers_info+0x54/0xa0
-+[  779.929796]  __dev_close_many+0x40/0x100
-+[  779.933712]  __dev_change_flags+0x98/0x190
-+[  779.937800]  dev_change_flags+0x20/0x60
-+[  779.941628]  devinet_ioctl+0x534/0x6d0
-+[  779.945370]  inet_ioctl+0x1bc/0x230
-+[  779.948849]  sock_do_ioctl+0x44/0x200
-+[  779.952502]  sock_ioctl+0x268/0x4c0
-+[  779.955985]  __arm64_sys_ioctl+0xac/0xd0
-+[  779.959900]  el0_svc_common.constprop.0+0x60/0x110
-+[  779.964682]  do_el0_svc+0x1c/0x24
-+[  779.967990]  el0_svc+0x10/0x1c
-+[  779.971036]  el0_sync_handler+0x9c/0x120
-+[  779.974950]  el0_sync+0x148/0x180
-+[  779.978259] Code: a9bc7bfd 910003fd a90153f3 aa0003f3 (f9400000)
-+[  779.984344] ---[ end trace 0e67b4f5d6cdeec7 ]---
-+[  779.996400] Kernel panic - not syncing: Oops: Fatal exception
-+[  780.002139] SMP: stopping secondary CPUs
-+[  780.006057] Kernel Offset: disabled
-+[  780.009537] CPU features: 0x0000002,04002004
-+[  780.013796] Memory Limit: none
++Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops
++in order to configure a dedicated offchannel chain available on some hw
++(e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime.
 +
-+Fixes: b8f5facf286b ("cfg80211: implement APIs for dedicated radar detection HW")
-+Reported-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
 +Tested-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
 +Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/c2e34c065bf8839c5ffa45498ae154021a72a520.1635958796.git.lorenzo@kernel.org
++Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org
 +Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 +---
 +
-+--- a/net/wireless/mlme.c
-++++ b/net/wireless/mlme.c
-+@@ -982,6 +982,9 @@ __cfg80211_offchan_cac_event(struct cfg8
-+ 
-+ 	lockdep_assert_wiphy(&rdev->wiphy);
++--- a/include/net/mac80211.h
+++++ b/include/net/mac80211.h
++@@ -3937,6 +3937,14 @@ struct ieee80211_prep_tx_info {
++  *	twt structure.
++  * @twt_teardown_request: Update the hw with TWT teardown request received
++  *	from the peer.
+++ * @set_radar_offchan: Configure dedicated offchannel chain available for
+++ *	radar/CAC detection on some hw. This chain can't be used to transmit
+++ *	or receive frames and it is bounded to a running wdev.
+++ *	Offchannel radar/CAC detection allows to avoid the CAC downtime
+++ *	switching to a different channel during CAC detection on the selected
+++ *	radar channel.
+++ *	The caller is expected to set chandef pointer to NULL in order to
+++ *	disable offchannel CAC/radar detection.
++  * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
++  *	resolve a path for hardware flow offloading
++  */
++@@ -4267,6 +4275,8 @@ struct ieee80211_ops {
++ 			      struct ieee80211_twt_setup *twt);
++ 	void (*twt_teardown_request)(struct ieee80211_hw *hw,
++ 				     struct ieee80211_sta *sta, u8 flowid);
+++	int (*set_radar_offchan)(struct ieee80211_hw *hw,
+++				 struct cfg80211_chan_def *chandef);
++ #if LINUX_VERSION_IS_GEQ(5,10,0)
++ 	int (*net_fill_forward_path)(struct ieee80211_hw *hw,
++ 				     struct ieee80211_vif *vif,
++--- a/net/mac80211/cfg.c
+++++ b/net/mac80211/cfg.c
++@@ -4344,6 +4344,18 @@ out:
++ 	return err;
++ }
 + 
-++	if (!cfg80211_chandef_valid(chandef))
-++		return;
+++static int
+++ieee80211_set_radar_offchan(struct wiphy *wiphy,
+++			    struct cfg80211_chan_def *chandef)
+++{
+++	struct ieee80211_local *local = wiphy_priv(wiphy);
 ++
-+ 	if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev)
-+ 		return;
-+ 
-+@@ -1096,6 +1099,6 @@ void cfg80211_stop_offchan_radar_detecti
-+ 
-+ 	rdev_set_radar_offchan(rdev, NULL);
-+ 
-+-	__cfg80211_offchan_cac_event(rdev, NULL, NULL,
-++	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
-+ 				     NL80211_RADAR_CAC_ABORTED);
-+ }
-diff --git a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch b/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch
-deleted file mode 100644
-index 91987ed759..0000000000
---- a/package/kernel/mac80211/patches/subsys/316-mac80211-enable-QoS-support-for-nl80211-ctrl-port.patch
-+++ /dev/null
-@@ -1,116 +0,0 @@
--From: Markus Theil <markus.theil@tu-ilmenau.de>
--Date: Sat, 6 Feb 2021 12:51:12 +0100
--Subject: [PATCH] mac80211: enable QoS support for nl80211 ctrl port
--
--This patch unifies sending control port frames
--over nl80211 and AF_PACKET sockets a little more.
--
--Before this patch, EAPOL frames got QoS prioritization
--only when using AF_PACKET sockets.
--
--__ieee80211_select_queue only selects a QoS-enabled queue
--for control port frames, when the control port protocol
--is set correctly on the skb. For the AF_PACKET path this
--works, but the nl80211 path used ETH_P_802_3.
--
--Another check for injected frames in wme.c then prevented
--the QoS TID to be copied in the frame.
--
--In order to fix this, get rid of the frame injection marking
--for nl80211 ctrl port and set the correct ethernet protocol.
--
--Please note:
--An erlier version of this path tried to prevent
--frame aggregation for control port frames in order to speed up
--the initial connection setup a little. This seemed to cause
--issues on my older Intel dvm-based hardware, and was therefore
--removed again. Future commits which try to reintroduce this
--have to check carefully how hw behaves with aggregated and
--non-aggregated traffic for the same TID.
--My NIC: Intel(R) Centrino(R) Ultimate-N 6300 AGN, REV=0x74
--
--Reported-by: kernel test robot <lkp@intel.com>
--Signed-off-by: Markus Theil <markus.theil@tu-ilmenau.de>
--Link: https://lore.kernel.org/r/20210206115112.567881-1-markus.theil@tu-ilmenau.de
--Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-----
--
----- a/net/mac80211/status.c
--+++ b/net/mac80211/status.c
--@@ -628,16 +628,12 @@ static void ieee80211_report_ack_skb(str
-- 		u64 cookie = IEEE80211_SKB_CB(skb)->ack.cookie;
-- 		struct ieee80211_sub_if_data *sdata;
-- 		struct ieee80211_hdr *hdr = (void *)skb->data;
---		__be16 ethertype = 0;
---
---		if (skb->len >= ETH_HLEN && skb->protocol == cpu_to_be16(ETH_P_802_3))
---			skb_copy_bits(skb, 2 * ETH_ALEN, &ethertype, ETH_TLEN);
-- 
-- 		rcu_read_lock();
-- 		sdata = ieee80211_sdata_from_skb(local, skb);
-- 		if (sdata) {
---			if (ethertype == sdata->control_port_protocol ||
---			    ethertype == cpu_to_be16(ETH_P_PREAUTH))
--+			if (skb->protocol == sdata->control_port_protocol ||
--+			    skb->protocol == cpu_to_be16(ETH_P_PREAUTH))
-- 				cfg80211_control_port_tx_status(&sdata->wdev,
-- 								cookie,
-- 								skb->data,
----- a/net/mac80211/tx.c
--+++ b/net/mac80211/tx.c
--@@ -1195,9 +1195,7 @@ ieee80211_tx_prepare(struct ieee80211_su
-- 			tx->sta = rcu_dereference(sdata->u.vlan.sta);
-- 			if (!tx->sta && sdata->wdev.use_4addr)
-- 				return TX_DROP;
---		} else if (info->flags & (IEEE80211_TX_INTFL_NL80211_FRAME_TX |
---					  IEEE80211_TX_CTL_INJECTED) ||
---			   tx->sdata->control_port_protocol == tx->skb->protocol) {
--+		} else if (tx->sdata->control_port_protocol == tx->skb->protocol) {
-- 			tx->sta = sta_info_get_bss(sdata, hdr->addr1);
-- 		}
-- 		if (!tx->sta && !is_multicast_ether_addr(hdr->addr1))
--@@ -5455,6 +5453,7 @@ int ieee80211_tx_control_port(struct wip
-- {
-- 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-- 	struct ieee80211_local *local = sdata->local;
--+	struct sta_info *sta;
-- 	struct sk_buff *skb;
-- 	struct ethhdr *ehdr;
-- 	u32 ctrl_flags = 0;
--@@ -5477,8 +5476,7 @@ int ieee80211_tx_control_port(struct wip
-- 	if (cookie)
-- 		ctrl_flags |= IEEE80211_TX_CTL_REQ_TX_STATUS;
-- 
---	flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX |
---		 IEEE80211_TX_CTL_INJECTED;
--+	flags |= IEEE80211_TX_INTFL_NL80211_FRAME_TX;
-- 
-- 	skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-- 			    sizeof(struct ethhdr) + len);
--@@ -5495,10 +5493,25 @@ int ieee80211_tx_control_port(struct wip
-- 	ehdr->h_proto = proto;
-- 
-- 	skb->dev = dev;
---	skb->protocol = htons(ETH_P_802_3);
--+	skb->protocol = proto;
-- 	skb_reset_network_header(skb);
-- 	skb_reset_mac_header(skb);
-- 
--+	/* update QoS header to prioritize control port frames if possible,
--+	 * priorization also happens for control port frames send over
--+	 * AF_PACKET
--+	 */
--+	rcu_read_lock();
--+
--+	if (ieee80211_lookup_ra_sta(sdata, skb, &sta) == 0 && !IS_ERR(sta)) {
--+		u16 queue = __ieee80211_select_queue(sdata, sta, skb);
--+
--+		skb_set_queue_mapping(skb, queue);
--+		skb_get_hash(skb);
--+	}
--+
--+	rcu_read_unlock();
--+
-- 	/* mutex lock is only needed for incrementing the cookie counter */
-- 	mutex_lock(&local->mtx);
-- 
-diff --git a/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch
+++	if (!local->ops->set_radar_offchan)
+++		return -EOPNOTSUPP;
+++
+++	return local->ops->set_radar_offchan(&local->hw, chandef);
+++}
+++
++ const struct cfg80211_ops mac80211_config_ops = {
++ 	.add_virtual_intf = ieee80211_add_iface,
++ 	.del_virtual_intf = ieee80211_del_iface,
++@@ -4448,4 +4460,5 @@ const struct cfg80211_ops mac80211_confi
++ 	.reset_tid_config = ieee80211_reset_tid_config,
++ 	.set_sar_specs = ieee80211_set_sar_specs,
++ 	.color_change = ieee80211_color_change,
+++	.set_radar_offchan = ieee80211_set_radar_offchan,
++ };
+diff --git a/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch
 new file mode 100644
-index 0000000000..df7afefb34
+index 0000000000..483b87cd88
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/317-cfg80211-schedule-offchan_cac_abort_wk-in-cfg80211_r.patch
-@@ -0,0 +1,136 @@
++++ b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch
+@@ -0,0 +1,532 @@
 +From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Tue, 16 Nov 2021 12:41:52 +0100
-+Subject: [PATCH] cfg80211: schedule offchan_cac_abort_wk in
-+ cfg80211_radar_event
++Date: Mon, 29 Nov 2021 14:11:24 +0100
++Subject: [PATCH] cfg80211: rename offchannel_chain structs to background_chain
++ to avoid confusion with ETSI standard
 +
-+If necessary schedule offchan_cac_abort_wk work in cfg80211_radar_event
-+routine adding offchan parameter to cfg80211_radar_event signature.
-+Rename cfg80211_radar_event in __cfg80211_radar_event and introduce
-+the two following inline helpers:
-+- cfg80211_radar_event
-+- cfg80211_offchan_radar_event
-+Doing so the drv will not need to run cfg80211_offchan_cac_abort() after
-+radar detection on the offchannel chain.
++ETSI standard defines "Offchannel CAC" as:
++"Off-Channel CAC is performed by a number of non-continuous checks
++spread over a period in time. This period, which is required to
++determine the presence of radar signals, is defined as the Off-Channel
++CAC Time..
++Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time
++4 hours..".
++mac80211 implementation refers to a dedicated hw chain used for continuous
++radar monitoring. Rename offchannel_* references to background_* in
++order to avoid confusion with ETSI standard.
 +
-+Tested-by: Owen Peng <owen.peng@mediatek.com>
 +Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/3ff583e021e3343a3ced54a7b09b5e184d1880dc.1637062727.git.lorenzo@kernel.org
++Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org
 +Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 +---
 +
 +--- a/include/net/cfg80211.h
 ++++ b/include/net/cfg80211.h
-+@@ -7580,15 +7580,33 @@ void cfg80211_cqm_txe_notify(struct net_
-+ void cfg80211_cqm_beacon_loss_notify(struct net_device *dev, gfp_t gfp);
++@@ -4058,14 +4058,14 @@ struct mgmt_frame_regs {
++  *
++  * @color_change: Initiate a color change.
++  *
++- * @set_radar_offchan: Configure dedicated offchannel chain available for
+++ * @set_radar_background: Configure dedicated offchannel chain available for
++  *	radar/CAC detection on some hw. This chain can't be used to transmit
++  *	or receive frames and it is bounded to a running wdev.
++- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
+++ *	Background radar/CAC detection allows to avoid the CAC downtime
++  *	switching to a different channel during CAC detection on the selected
++  *	radar channel.
++  *	The caller is expected to set chandef pointer to NULL in order to
++- *	disable offchannel CAC/radar detection.
+++ *	disable background CAC/radar detection.
++  */
++ struct cfg80211_ops {
++ 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
++@@ -4396,8 +4396,8 @@ struct cfg80211_ops {
++ 	int	(*color_change)(struct wiphy *wiphy,
++ 				struct net_device *dev,
++ 				struct cfg80211_color_change_settings *params);
++-	int	(*set_radar_offchan)(struct wiphy *wiphy,
++-				     struct cfg80211_chan_def *chandef);
+++	int	(*set_radar_background)(struct wiphy *wiphy,
+++					struct cfg80211_chan_def *chandef);
++ };
++ 
++ /*
++@@ -7601,9 +7601,9 @@ cfg80211_radar_event(struct wiphy *wiphy
++ }
++ 
++ static inline void
++-cfg80211_offchan_radar_event(struct wiphy *wiphy,
++-			     struct cfg80211_chan_def *chandef,
++-			     gfp_t gfp)
+++cfg80211_background_radar_event(struct wiphy *wiphy,
+++				struct cfg80211_chan_def *chandef,
+++				gfp_t gfp)
++ {
++ 	__cfg80211_radar_event(wiphy, chandef, true, gfp);
++ }
++@@ -7638,13 +7638,13 @@ void cfg80211_cac_event(struct net_devic
++ 			enum nl80211_radar_event event, gfp_t gfp);
 + 
 + /**
-+- * cfg80211_radar_event - radar detection event
-++ * __cfg80211_radar_event - radar detection event
++- * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event
+++ * cfg80211_background_cac_abort - Channel Availability Check offchan abort event
 +  * @wiphy: the wiphy
-+  * @chandef: chandef for the current channel
-++ * @offchan: the radar has been detected on the offchannel chain
-+  * @gfp: context flags
 +  *
-+  * This function is called when a radar is detected on the current chanenl.
++  * This function is called by the driver when a Channel Availability Check
++  * (CAC) is aborted by a offchannel dedicated chain.
 +  */
-+-void cfg80211_radar_event(struct wiphy *wiphy,
-+-			  struct cfg80211_chan_def *chandef, gfp_t gfp);
-++void __cfg80211_radar_event(struct wiphy *wiphy,
-++			    struct cfg80211_chan_def *chandef,
-++			    bool offchan, gfp_t gfp);
-++
-++static inline void
-++cfg80211_radar_event(struct wiphy *wiphy,
-++		     struct cfg80211_chan_def *chandef,
-++		     gfp_t gfp)
-++{
-++	__cfg80211_radar_event(wiphy, chandef, false, gfp);
-++}
-++
-++static inline void
-++cfg80211_offchan_radar_event(struct wiphy *wiphy,
-++			     struct cfg80211_chan_def *chandef,
-++			     gfp_t gfp)
-++{
-++	__cfg80211_radar_event(wiphy, chandef, true, gfp);
-++}
++-void cfg80211_offchan_cac_abort(struct wiphy *wiphy);
+++void cfg80211_background_cac_abort(struct wiphy *wiphy);
 + 
 + /**
-+  * cfg80211_sta_opmode_change_notify - STA's ht/vht operation mode change event
-+--- a/net/wireless/mlme.c
-++++ b/net/wireless/mlme.c
-+@@ -905,13 +905,13 @@ void cfg80211_dfs_channels_update_work(s
-+ }
++  * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
++--- a/include/net/mac80211.h
+++++ b/include/net/mac80211.h
++@@ -3937,14 +3937,14 @@ struct ieee80211_prep_tx_info {
++  *	twt structure.
++  * @twt_teardown_request: Update the hw with TWT teardown request received
++  *	from the peer.
++- * @set_radar_offchan: Configure dedicated offchannel chain available for
+++ * @set_radar_background: Configure dedicated offchannel chain available for
++  *	radar/CAC detection on some hw. This chain can't be used to transmit
++  *	or receive frames and it is bounded to a running wdev.
++- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
+++ *	Background radar/CAC detection allows to avoid the CAC downtime
++  *	switching to a different channel during CAC detection on the selected
++  *	radar channel.
++  *	The caller is expected to set chandef pointer to NULL in order to
++- *	disable offchannel CAC/radar detection.
+++ *	disable background CAC/radar detection.
++  * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
++  *	resolve a path for hardware flow offloading
++  */
++@@ -4275,8 +4275,8 @@ struct ieee80211_ops {
++ 			      struct ieee80211_twt_setup *twt);
++ 	void (*twt_teardown_request)(struct ieee80211_hw *hw,
++ 				     struct ieee80211_sta *sta, u8 flowid);
++-	int (*set_radar_offchan)(struct ieee80211_hw *hw,
++-				 struct cfg80211_chan_def *chandef);
+++	int (*set_radar_background)(struct ieee80211_hw *hw,
+++				    struct cfg80211_chan_def *chandef);
++ #if LINUX_VERSION_IS_GEQ(5,10,0)
++ 	int (*net_fill_forward_path)(struct ieee80211_hw *hw,
++ 				     struct ieee80211_vif *vif,
++--- a/include/uapi/linux/nl80211.h
+++++ b/include/uapi/linux/nl80211.h
++@@ -2608,10 +2608,10 @@ enum nl80211_commands {
++  *	Mandatory parameter for the transmitting interface to enable MBSSID.
++  *	Optional for the non-transmitting interfaces.
++  *
++- * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for
++- *	radar/CAC detection on some hw. This chain can't be used to transmit
++- *	or receive frames and it is bounded to a running wdev.
++- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
+++ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain
+++ *	available for radar/CAC detection on some hw. This chain can't be used
+++ *	to transmit or receive frames and it is bounded to a running wdev.
+++ *	Background radar/CAC detection allows to avoid the CAC downtime
++  *	switching on a different channel during CAC detection on the selected
++  *	radar channel.
++  *
++@@ -3121,7 +3121,7 @@ enum nl80211_attrs {
++ 	NL80211_ATTR_MBSSID_CONFIG,
++ 	NL80211_ATTR_MBSSID_ELEMS,
 + 
++-	NL80211_ATTR_RADAR_OFFCHAN,
+++	NL80211_ATTR_RADAR_BACKGROUND,
 + 
-+-void cfg80211_radar_event(struct wiphy *wiphy,
-+-			  struct cfg80211_chan_def *chandef,
-+-			  gfp_t gfp)
-++void __cfg80211_radar_event(struct wiphy *wiphy,
-++			    struct cfg80211_chan_def *chandef,
-++			    bool offchan, gfp_t gfp)
++ 	/* add attributes here, update the policy in nl80211.c */
++ 
++@@ -6022,7 +6022,7 @@ enum nl80211_feature_flags {
++  * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
++  *	detection and change announcemnts.
++  *
++- * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC
+++ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
++  *	detection.
++  *
++  * @NUM_NL80211_EXT_FEATURES: number of extended features.
++@@ -6090,7 +6090,7 @@ enum nl80211_ext_feature_index {
++ 	NL80211_EXT_FEATURE_SECURE_RTT,
++ 	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
++ 	NL80211_EXT_FEATURE_BSS_COLOR,
++-	NL80211_EXT_FEATURE_RADAR_OFFCHAN,
+++	NL80211_EXT_FEATURE_RADAR_BACKGROUND,
++ 
++ 	/* add new features before the definition below */
++ 	NUM_NL80211_EXT_FEATURES,
++--- a/net/mac80211/cfg.c
+++++ b/net/mac80211/cfg.c
++@@ -4345,15 +4345,15 @@ out:
++ }
++ 
++ static int
++-ieee80211_set_radar_offchan(struct wiphy *wiphy,
++-			    struct cfg80211_chan_def *chandef)
+++ieee80211_set_radar_background(struct wiphy *wiphy,
+++			       struct cfg80211_chan_def *chandef)
 + {
-+ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++ 	struct ieee80211_local *local = wiphy_priv(wiphy);
 + 
-+-	trace_cfg80211_radar_event(wiphy, chandef);
-++	trace_cfg80211_radar_event(wiphy, chandef, offchan);
++-	if (!local->ops->set_radar_offchan)
+++	if (!local->ops->set_radar_background)
++ 		return -EOPNOTSUPP;
 + 
-+ 	/* only set the chandef supplied channel to unavailable, in
-+ 	 * case the radar is detected on only one of multiple channels
-+@@ -919,6 +919,9 @@ void cfg80211_radar_event(struct wiphy *
-+ 	 */
-+ 	cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
++-	return local->ops->set_radar_offchan(&local->hw, chandef);
+++	return local->ops->set_radar_background(&local->hw, chandef);
++ }
 + 
-++	if (offchan)
-++		queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
-++
-+ 	cfg80211_sched_dfs_chan_update(rdev);
++ const struct cfg80211_ops mac80211_config_ops = {
++@@ -4460,5 +4460,5 @@ const struct cfg80211_ops mac80211_confi
++ 	.reset_tid_config = ieee80211_reset_tid_config,
++ 	.set_sar_specs = ieee80211_set_sar_specs,
++ 	.color_change = ieee80211_color_change,
++-	.set_radar_offchan = ieee80211_set_radar_offchan,
+++	.set_radar_background = ieee80211_set_radar_background,
++ };
++--- a/net/wireless/chan.c
+++++ b/net/wireless/chan.c
++@@ -716,13 +716,13 @@ static bool
++ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
++ 				 struct ieee80211_channel *channel)
++ {
++-	if (!rdev->offchan_radar_wdev)
+++	if (!rdev->background_radar_wdev)
++ 		return false;
 + 
-+ 	nl80211_radar_notify(rdev, chandef, NL80211_RADAR_DETECTED, NULL, gfp);
-+@@ -926,7 +929,7 @@ void cfg80211_radar_event(struct wiphy *
-+ 	memcpy(&rdev->radar_chandef, chandef, sizeof(struct cfg80211_chan_def));
-+ 	queue_work(cfg80211_wq, &rdev->propagate_radar_detect_wk);
++-	if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef))
+++	if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
++ 		return false;
++ 
++-	return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel);
+++	return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel);
 + }
-+-EXPORT_SYMBOL(cfg80211_radar_event);
-++EXPORT_SYMBOL(__cfg80211_radar_event);
 + 
-+ void cfg80211_cac_event(struct net_device *netdev,
-+ 			const struct cfg80211_chan_def *chandef,
-+@@ -998,7 +1001,8 @@ __cfg80211_offchan_cac_event(struct cfg8
-+ 		rdev->offchan_radar_wdev = NULL;
-+ 		break;
-+ 	case NL80211_RADAR_CAC_ABORTED:
-+-		cancel_delayed_work(&rdev->offchan_cac_done_wk);
-++		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
-++			return;
-+ 		wdev = rdev->offchan_radar_wdev;
-+ 		rdev->offchan_radar_wdev = NULL;
-+ 		break;
-+--- a/net/wireless/trace.h
-++++ b/net/wireless/trace.h
-+@@ -3022,18 +3022,21 @@ TRACE_EVENT(cfg80211_ch_switch_started_n
-+ );
++ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
++--- a/net/wireless/core.c
+++++ b/net/wireless/core.c
++@@ -543,9 +543,10 @@ use_default_name:
++ 	INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);
++ 	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
++ 	INIT_WORK(&rdev->event_work, cfg80211_event_work);
++-	INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk);
++-	INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk,
++-			  cfg80211_offchan_cac_done_wk);
+++	INIT_WORK(&rdev->background_cac_abort_wk,
+++		  cfg80211_background_cac_abort_wk);
+++	INIT_DELAYED_WORK(&rdev->background_cac_done_wk,
+++			  cfg80211_background_cac_done_wk);
 + 
-+ TRACE_EVENT(cfg80211_radar_event,
-+-	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
-+-	TP_ARGS(wiphy, chandef),
-++	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef,
-++		 bool offchan),
-++	TP_ARGS(wiphy, chandef, offchan),
-+ 	TP_STRUCT__entry(
-+ 		WIPHY_ENTRY
-+ 		CHAN_DEF_ENTRY
-++		__field(bool, offchan)
-+ 	),
-+ 	TP_fast_assign(
-+ 		WIPHY_ASSIGN;
-+ 		CHAN_DEF_ASSIGN(chandef);
-++		__entry->offchan = offchan;
-+ 	),
-+-	TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
-+-		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
-++	TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", offchan %d",
-++		  WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->offchan)
-+ );
++ 	init_waitqueue_head(&rdev->dev_wait);
++ 
++@@ -1055,13 +1056,13 @@ void wiphy_unregister(struct wiphy *wiph
++ 	cancel_work_sync(&rdev->conn_work);
++ 	flush_work(&rdev->event_work);
++ 	cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
++-	cancel_delayed_work_sync(&rdev->offchan_cac_done_wk);
+++	cancel_delayed_work_sync(&rdev->background_cac_done_wk);
++ 	flush_work(&rdev->destroy_work);
++ 	flush_work(&rdev->sched_scan_stop_wk);
++ 	flush_work(&rdev->propagate_radar_detect_wk);
++ 	flush_work(&rdev->propagate_cac_done_wk);
++ 	flush_work(&rdev->mgmt_registrations_update_wk);
++-	flush_work(&rdev->offchan_cac_abort_wk);
+++	flush_work(&rdev->background_cac_abort_wk);
++ 
++ #ifdef CONFIG_PM
++ 	if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
++@@ -1210,7 +1211,7 @@ void __cfg80211_leave(struct cfg80211_re
++ 
++ 	cfg80211_pmsr_wdev_down(wdev);
++ 
++-	cfg80211_stop_offchan_radar_detection(wdev);
+++	cfg80211_stop_background_radar_detection(wdev);
++ 
++ 	switch (wdev->iftype) {
++ 	case NL80211_IFTYPE_ADHOC:
++--- a/net/wireless/core.h
+++++ b/net/wireless/core.h
++@@ -84,10 +84,10 @@ struct cfg80211_registered_device {
 + 
-+ TRACE_EVENT(cfg80211_cac_event,
-diff --git a/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch
-new file mode 100644
-index 0000000000..567743d84d
---- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/318-cfg80211-allow-continuous-radar-monitoring-on-offcha.patch
-@@ -0,0 +1,220 @@
-+From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Tue, 16 Nov 2021 15:03:36 +0100
-+Subject: [PATCH] cfg80211: allow continuous radar monitoring on offchannel
-+ chain
-+
-+Allow continuous radar detection on the offchannel chain in order
-+to switch to the monitored channel whenever the underlying driver
-+reports a radar pattern on the main channel.
-+
-+Tested-by: Owen Peng <owen.peng@mediatek.com>
-+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/d46217310a49b14ff0e9c002f0a6e0547d70fd2c.1637071350.git.lorenzo@kernel.org
-+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-+---
-+
-+--- a/net/wireless/chan.c
-++++ b/net/wireless/chan.c
-+@@ -712,6 +712,19 @@ static bool cfg80211_is_wiphy_oper_chan(
-+ 	return false;
-+ }
++ 	struct delayed_work dfs_update_channels_wk;
 + 
-++static bool
-++cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
-++				 struct ieee80211_channel *channel)
-++{
-++	if (!rdev->offchan_radar_wdev)
-++		return false;
-++
-++	if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef))
-++		return false;
-++
-++	return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel);
-++}
-++
-+ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
-+ 				  struct ieee80211_channel *chan)
-+ {
-+@@ -728,6 +741,9 @@ bool cfg80211_any_wiphy_oper_chan(struct
++-	struct wireless_dev *offchan_radar_wdev;
++-	struct cfg80211_chan_def offchan_radar_chandef;
++-	struct delayed_work offchan_cac_done_wk;
++-	struct work_struct offchan_cac_abort_wk;
+++	struct wireless_dev *background_radar_wdev;
+++	struct cfg80211_chan_def background_radar_chandef;
+++	struct delayed_work background_cac_done_wk;
+++	struct work_struct background_cac_abort_wk;
 + 
-+ 		if (cfg80211_is_wiphy_oper_chan(&rdev->wiphy, chan))
-+ 			return true;
-++
-++		if (cfg80211_offchan_chain_is_active(rdev, chan))
-++			return true;
-+ 	}
++ 	/* netlink port which started critical protocol (0 means not started) */
++ 	u32 crit_proto_nlportid;
++@@ -497,15 +497,15 @@ cfg80211_chandef_dfs_cac_time(struct wip
++ void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
 + 
-+ 	return false;
++ int
++-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
++-				       struct wireless_dev *wdev,
++-				       struct cfg80211_chan_def *chandef);
+++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
+++					  struct wireless_dev *wdev,
+++					  struct cfg80211_chan_def *chandef);
++ 
++-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev);
+++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev);
++ 
++-void cfg80211_offchan_cac_done_wk(struct work_struct *work);
+++void cfg80211_background_cac_done_wk(struct work_struct *work);
++ 
++-void cfg80211_offchan_cac_abort_wk(struct work_struct *work);
+++void cfg80211_background_cac_abort_wk(struct work_struct *work);
++ 
++ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
++ 				  struct ieee80211_channel *chan);
 +--- a/net/wireless/mlme.c
 ++++ b/net/wireless/mlme.c
++@@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy
++ 	cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
++ 
++ 	if (offchan)
++-		queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
+++		queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
++ 
++ 	cfg80211_sched_dfs_chan_update(rdev);
++ 
++@@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_devic
++ EXPORT_SYMBOL(cfg80211_cac_event);
++ 
++ static void
++-__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev,
++-			     struct wireless_dev *wdev,
++-			     const struct cfg80211_chan_def *chandef,
++-			     enum nl80211_radar_event event)
+++__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
+++				struct wireless_dev *wdev,
+++				const struct cfg80211_chan_def *chandef,
+++				enum nl80211_radar_event event)
++ {
++ 	struct wiphy *wiphy = &rdev->wiphy;
++ 	struct net_device *netdev;
 +@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8
 + 	if (!cfg80211_chandef_valid(chandef))
 + 		return;
 + 
-+-	if (event != NL80211_RADAR_CAC_STARTED && !rdev->offchan_radar_wdev)
-++	if (!rdev->offchan_radar_wdev)
++-	if (!rdev->offchan_radar_wdev)
+++	if (!rdev->background_radar_wdev)
 + 		return;
 + 
 + 	switch (event) {
-+@@ -998,17 +998,13 @@ __cfg80211_offchan_cac_event(struct cfg8
++@@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg8
++ 		memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
 + 		queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
 + 		cfg80211_sched_dfs_chan_update(rdev);
-+ 		wdev = rdev->offchan_radar_wdev;
-+-		rdev->offchan_radar_wdev = NULL;
++-		wdev = rdev->offchan_radar_wdev;
+++		wdev = rdev->background_radar_wdev;
 + 		break;
 + 	case NL80211_RADAR_CAC_ABORTED:
-+ 		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
++-		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
+++		if (!cancel_delayed_work(&rdev->background_cac_done_wk))
 + 			return;
-+ 		wdev = rdev->offchan_radar_wdev;
-+-		rdev->offchan_radar_wdev = NULL;
++-		wdev = rdev->offchan_radar_wdev;
+++		wdev = rdev->background_radar_wdev;
 + 		break;
 + 	case NL80211_RADAR_CAC_STARTED:
-+-		WARN_ON(!wdev);
-+-		rdev->offchan_radar_wdev = wdev;
 + 		break;
-+ 	default:
-+ 		return;
-+@@ -1024,7 +1020,8 @@ cfg80211_offchan_cac_event(struct cfg802
-+ 			   enum nl80211_radar_event event)
++@@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg8
++ }
++ 
++ static void
++-cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev,
++-			   const struct cfg80211_chan_def *chandef,
++-			   enum nl80211_radar_event event)
+++cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
+++			      const struct cfg80211_chan_def *chandef,
+++			      enum nl80211_radar_event event)
 + {
 + 	wiphy_lock(&rdev->wiphy);
-+-	__cfg80211_offchan_cac_event(rdev, NULL, chandef, event);
-++	__cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev,
-++				     chandef, event);
++-	__cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev,
++-				     chandef, event);
+++	__cfg80211_background_cac_event(rdev, rdev->background_radar_wdev,
+++					chandef, event);
 + 	wiphy_unlock(&rdev->wiphy);
 + }
 + 
-+@@ -1071,7 +1068,13 @@ cfg80211_start_offchan_radar_detection(s
-+ 				     NL80211_EXT_FEATURE_RADAR_OFFCHAN))
++-void cfg80211_offchan_cac_done_wk(struct work_struct *work)
+++void cfg80211_background_cac_done_wk(struct work_struct *work)
++ {
++ 	struct delayed_work *delayed_work = to_delayed_work(work);
++ 	struct cfg80211_registered_device *rdev;
++ 
++ 	rdev = container_of(delayed_work, struct cfg80211_registered_device,
++-			    offchan_cac_done_wk);
++-	cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef,
++-				   NL80211_RADAR_CAC_FINISHED);
+++			    background_cac_done_wk);
+++	cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
+++				      NL80211_RADAR_CAC_FINISHED);
++ }
++ 
++-void cfg80211_offchan_cac_abort_wk(struct work_struct *work)
+++void cfg80211_background_cac_abort_wk(struct work_struct *work)
++ {
++ 	struct cfg80211_registered_device *rdev;
++ 
++ 	rdev = container_of(work, struct cfg80211_registered_device,
++-			    offchan_cac_abort_wk);
++-	cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef,
++-				   NL80211_RADAR_CAC_ABORTED);
+++			    background_cac_abort_wk);
+++	cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
+++				      NL80211_RADAR_CAC_ABORTED);
++ }
++ 
++-void cfg80211_offchan_cac_abort(struct wiphy *wiphy)
+++void cfg80211_background_cac_abort(struct wiphy *wiphy)
++ {
++ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++ 
++-	queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
+++	queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
++ }
++-EXPORT_SYMBOL(cfg80211_offchan_cac_abort);
+++EXPORT_SYMBOL(cfg80211_background_cac_abort);
++ 
++ int
++-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
++-				       struct wireless_dev *wdev,
++-				       struct cfg80211_chan_def *chandef)
+++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
+++					  struct wireless_dev *wdev,
+++					  struct cfg80211_chan_def *chandef)
++ {
++ 	unsigned int cac_time_ms;
++ 	int err;
++@@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(s
++ 	lockdep_assert_wiphy(&rdev->wiphy);
++ 
++ 	if (!wiphy_ext_feature_isset(&rdev->wiphy,
++-				     NL80211_EXT_FEATURE_RADAR_OFFCHAN))
+++				     NL80211_EXT_FEATURE_RADAR_BACKGROUND))
 + 		return -EOPNOTSUPP;
 + 
-+-	if (rdev->offchan_radar_wdev)
-++	/* Offchannel chain already locked by another wdev */
-++	if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev)
-++		return -EBUSY;
-++
-++	/* CAC already in progress on the offchannel chain */
-++	if (rdev->offchan_radar_wdev == wdev &&
-++	    delayed_work_pending(&rdev->offchan_cac_done_wk))
++ 	/* Offchannel chain already locked by another wdev */
++-	if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev)
+++	if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev)
 + 		return -EBUSY;
 + 
-+ 	err = rdev_set_radar_offchan(rdev, chandef);
-+@@ -1083,6 +1086,8 @@ cfg80211_start_offchan_radar_detection(s
++ 	/* CAC already in progress on the offchannel chain */
++-	if (rdev->offchan_radar_wdev == wdev &&
++-	    delayed_work_pending(&rdev->offchan_cac_done_wk))
+++	if (rdev->background_radar_wdev == wdev &&
+++	    delayed_work_pending(&rdev->background_cac_done_wk))
++ 		return -EBUSY;
++ 
++-	err = rdev_set_radar_offchan(rdev, chandef);
+++	err = rdev_set_radar_background(rdev, chandef);
++ 	if (err)
++ 		return err;
++ 
++@@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(s
++ 	if (!cac_time_ms)
 + 		cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
 + 
-+ 	rdev->offchan_radar_chandef = *chandef;
-++	rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */
-++
-+ 	__cfg80211_offchan_cac_event(rdev, wdev, chandef,
-+ 				     NL80211_RADAR_CAC_STARTED);
-+ 	queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk,
-+@@ -1102,6 +1107,7 @@ void cfg80211_stop_offchan_radar_detecti
++-	rdev->offchan_radar_chandef = *chandef;
++-	rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */
+++	rdev->background_radar_chandef = *chandef;
+++	rdev->background_radar_wdev = wdev; /* Get offchain ownership */
++ 
++-	__cfg80211_offchan_cac_event(rdev, wdev, chandef,
++-				     NL80211_RADAR_CAC_STARTED);
++-	queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk,
+++	__cfg80211_background_cac_event(rdev, wdev, chandef,
+++					NL80211_RADAR_CAC_STARTED);
+++	queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk,
++ 			   msecs_to_jiffies(cac_time_ms));
++ 
++ 	return 0;
++ }
++ 
++-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev)
+++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
++ {
++ 	struct wiphy *wiphy = wdev->wiphy;
++ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++ 
++ 	lockdep_assert_wiphy(wiphy);
++ 
++-	if (wdev != rdev->offchan_radar_wdev)
+++	if (wdev != rdev->background_radar_wdev)
 + 		return;
 + 
-+ 	rdev_set_radar_offchan(rdev, NULL);
-++	rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */
++-	rdev_set_radar_offchan(rdev, NULL);
++-	rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */
+++	rdev_set_radar_background(rdev, NULL);
+++	rdev->background_radar_wdev = NULL; /* Release offchain ownership */
 + 
-+ 	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
-+ 				     NL80211_RADAR_CAC_ABORTED);
++-	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
++-				     NL80211_RADAR_CAC_ABORTED);
+++	__cfg80211_background_cac_event(rdev, wdev,
+++					&rdev->background_radar_chandef,
+++					NL80211_RADAR_CAC_ABORTED);
++ }
 +--- a/net/wireless/nl80211.c
 ++++ b/net/wireless/nl80211.c
-+@@ -9263,42 +9263,60 @@ static int nl80211_start_radar_detection
-+ 	struct cfg80211_chan_def chandef;
-+ 	enum nl80211_dfs_regions dfs_region;
-+ 	unsigned int cac_time_ms;
-+-	int err;
-++	int err = -EINVAL;
-++
-++	flush_delayed_work(&rdev->dfs_update_channels_wk);
-++
-++	wiphy_lock(wiphy);
-+ 
-+ 	dfs_region = reg_get_dfs_region(wiphy);
-+ 	if (dfs_region == NL80211_DFS_UNSET)
-+-		return -EINVAL;
-++		goto unlock;
-+ 
-+ 	err = nl80211_parse_chandef(rdev, info, &chandef);
-+ 	if (err)
-+-		return err;
-++		goto unlock;
-+ 
-+ 	err = cfg80211_chandef_dfs_required(wiphy, &chandef, wdev->iftype);
-+ 	if (err < 0)
-+-		return err;
-++		goto unlock;
++@@ -801,7 +801,7 @@ static const struct nla_policy nl80211_p
++ 	[NL80211_ATTR_MBSSID_CONFIG] =
++ 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
++ 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
++-	[NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG },
+++	[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
++ };
 + 
-+-	if (err == 0)
-+-		return -EINVAL;
-++	if (err == 0) {
-++		err = -EINVAL;
-++		goto unlock;
-++	}
++ /* policy for the key attributes */
++@@ -9306,9 +9306,9 @@ static int nl80211_start_radar_detection
++ 		goto unlock;
++ 	}
 + 
-+-	if (!cfg80211_chandef_dfs_usable(wiphy, &chandef))
-+-		return -EINVAL;
-++	if (!cfg80211_chandef_dfs_usable(wiphy, &chandef)) {
-++		err = -EINVAL;
-++		goto unlock;
-++	}
++-	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) {
++-		err = cfg80211_start_offchan_radar_detection(rdev, wdev,
++-							     &chandef);
+++	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) {
+++		err = cfg80211_start_background_radar_detection(rdev, wdev,
+++								&chandef);
++ 		goto unlock;
++ 	}
 + 
-+-	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN]))
-+-		return cfg80211_start_offchan_radar_detection(rdev, wdev,
-+-							      &chandef);
-++	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) {
-++		err = cfg80211_start_offchan_radar_detection(rdev, wdev,
-++							     &chandef);
-++		goto unlock;
-++	}
++--- a/net/wireless/rdev-ops.h
+++++ b/net/wireless/rdev-ops.h
++@@ -1382,17 +1382,17 @@ static inline int rdev_color_change(stru
++ }
 + 
-+-	if (netif_carrier_ok(dev))
-+-		return -EBUSY;
-++	if (netif_carrier_ok(dev)) {
-++		err = -EBUSY;
-++		goto unlock;
-++	}
++ static inline int
++-rdev_set_radar_offchan(struct cfg80211_registered_device *rdev,
++-		       struct cfg80211_chan_def *chandef)
+++rdev_set_radar_background(struct cfg80211_registered_device *rdev,
+++			  struct cfg80211_chan_def *chandef)
++ {
++ 	struct wiphy *wiphy = &rdev->wiphy;
++ 	int ret;
 + 
-+-	if (wdev->cac_started)
-+-		return -EBUSY;
-++	if (wdev->cac_started) {
-++		err = -EBUSY;
-++		goto unlock;
-++	}
++-	if (!rdev->ops->set_radar_offchan)
+++	if (!rdev->ops->set_radar_background)
++ 		return -EOPNOTSUPP;
 + 
-+ 	/* CAC start is offloaded to HW and can't be started manually */
-+-	if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD))
-+-		return -EOPNOTSUPP;
-++	if (wiphy_ext_feature_isset(wiphy, NL80211_EXT_FEATURE_DFS_OFFLOAD)) {
-++		err = -EOPNOTSUPP;
-++		goto unlock;
-++	}
++-	trace_rdev_set_radar_offchan(wiphy, chandef);
++-	ret = rdev->ops->set_radar_offchan(wiphy, chandef);
+++	trace_rdev_set_radar_background(wiphy, chandef);
+++	ret = rdev->ops->set_radar_background(wiphy, chandef);
++ 	trace_rdev_return_int(wiphy, ret);
 + 
-+-	if (!rdev->ops->start_radar_detection)
-+-		return -EOPNOTSUPP;
-++	if (!rdev->ops->start_radar_detection) {
-++		err = -EOPNOTSUPP;
-++		goto unlock;
-++	}
++ 	return ret;
++--- a/net/wireless/trace.h
+++++ b/net/wireless/trace.h
++@@ -3646,7 +3646,7 @@ TRACE_EVENT(cfg80211_bss_color_notify,
++ 		  __entry->color_bitmap)
++ );
 + 
-+ 	cac_time_ms = cfg80211_chandef_dfs_cac_time(&rdev->wiphy, &chandef);
-+ 	if (WARN_ON(!cac_time_ms))
-+@@ -9311,6 +9329,9 @@ static int nl80211_start_radar_detection
-+ 		wdev->cac_start_time = jiffies;
-+ 		wdev->cac_time_ms = cac_time_ms;
-+ 	}
-++unlock:
-++	wiphy_unlock(wiphy);
-++
-+ 	return err;
-+ }
++-TRACE_EVENT(rdev_set_radar_offchan,
+++TRACE_EVENT(rdev_set_radar_background,
++ 	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
 + 
-+@@ -15941,7 +15962,8 @@ static const struct genl_small_ops nl802
-+ 		.validate = GENL_DONT_VALIDATE_STRICT | GENL_DONT_VALIDATE_DUMP,
-+ 		.doit = nl80211_start_radar_detection,
-+ 		.flags = GENL_UNS_ADMIN_PERM,
-+-		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP,
-++		.internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
-++				  NL80211_FLAG_NO_WIPHY_MTX,
-+ 	},
-+ 	{
-+ 		.cmd = NL80211_CMD_GET_PROTOCOL_FEATURES,
-diff --git a/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch
++ 	TP_ARGS(wiphy, chandef),
+diff --git a/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch
 new file mode 100644
-index 0000000000..eb80afbccb
+index 0000000000..a135e3d1b5
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/319-mac80211-introduce-set_radar_offchan-callback.patch
-@@ -0,0 +1,67 @@
-+From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Sat, 23 Oct 2021 11:10:51 +0200
-+Subject: [PATCH] mac80211: introduce set_radar_offchan callback
++++ b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch
+@@ -0,0 +1,144 @@
++From: John Crispin <john@phrozen.org>
++Date: Wed, 15 Sep 2021 19:54:35 -0700
++Subject: [PATCH] mac80211: MBSSID support in interface handling
 +
-+Similar to cfg80211, introduce set_radar_offchan callback in mac80211_ops
-+in order to configure a dedicated offchannel chain available on some hw
-+(e.g. mt7915) to perform offchannel CAC detection and avoid tx/rx downtime.
++Configure multiple BSSID and enhanced multi-BSSID advertisement (EMA)
++parameters in mac80211 for AP mode.
 +
-+Tested-by: Evelyn Tsai <evelyn.tsai@mediatek.com>
-+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/201110606d4f3a7dfdf31440e351f2e2c375d4f0.1634979655.git.lorenzo@kernel.org
++For each interface, 'mbssid_tx_vif' points to the transmitting interface of
++the MBSSID set. The pointer is set to NULL if MBSSID is disabled.
++
++Function ieee80211_stop() is modified to always bring down all the
++non-transmitting interfaces first and the transmitting interface last.
++
++Signed-off-by: John Crispin <john@phrozen.org>
++Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
++Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
++Link: https://lore.kernel.org/r/20210916025437.29138-3-alokad@codeaurora.org
++[slightly change logic to be more obvious]
 +Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 +---
 +
 +--- a/include/net/mac80211.h
 ++++ b/include/net/mac80211.h
-+@@ -3937,6 +3937,14 @@ struct ieee80211_prep_tx_info {
-+  *	twt structure.
-+  * @twt_teardown_request: Update the hw with TWT teardown request received
-+  *	from the peer.
-++ * @set_radar_offchan: Configure dedicated offchannel chain available for
-++ *	radar/CAC detection on some hw. This chain can't be used to transmit
-++ *	or receive frames and it is bounded to a running wdev.
-++ *	Offchannel radar/CAC detection allows to avoid the CAC downtime
-++ *	switching to a different channel during CAC detection on the selected
-++ *	radar channel.
-++ *	The caller is expected to set chandef pointer to NULL in order to
-++ *	disable offchannel CAC/radar detection.
-+  * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
-+  *	resolve a path for hardware flow offloading
++@@ -1719,6 +1719,7 @@ enum ieee80211_offload_flags {
++  *	write-protected by sdata_lock and local->mtx so holding either is fine
++  *	for read access.
++  * @color_change_color: the bss color that will be used after the change.
+++ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
 +  */
-+@@ -4267,6 +4275,8 @@ struct ieee80211_ops {
-+ 			      struct ieee80211_twt_setup *twt);
-+ 	void (*twt_teardown_request)(struct ieee80211_hw *hw,
-+ 				     struct ieee80211_sta *sta, u8 flowid);
-++	int (*set_radar_offchan)(struct ieee80211_hw *hw,
-++				 struct cfg80211_chan_def *chandef);
-+ #if LINUX_VERSION_IS_GEQ(5,10,0)
-+ 	int (*net_fill_forward_path)(struct ieee80211_hw *hw,
-+ 				     struct ieee80211_vif *vif,
++ struct ieee80211_vif {
++ 	enum nl80211_iftype type;
++@@ -1750,6 +1751,8 @@ struct ieee80211_vif {
++ 	bool color_change_active;
++ 	u8 color_change_color;
++ 
+++	struct ieee80211_vif *mbssid_tx_vif;
+++
++ 	/* must be last */
++ 	u8 drv_priv[] __aligned(sizeof(void *));
++ };
 +--- a/net/mac80211/cfg.c
 ++++ b/net/mac80211/cfg.c
-+@@ -4344,6 +4344,18 @@ out:
-+ 	return err;
++@@ -112,6 +112,36 @@ static int ieee80211_set_mon_options(str
++ 	return 0;
++ }
++ 
+++static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
+++					   struct cfg80211_mbssid_config params)
+++{
+++	struct ieee80211_sub_if_data *tx_sdata;
+++
+++	sdata->vif.mbssid_tx_vif = NULL;
+++	sdata->vif.bss_conf.bssid_index = 0;
+++	sdata->vif.bss_conf.nontransmitted = false;
+++	sdata->vif.bss_conf.ema_ap = false;
+++
+++	if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev)
+++		return -EINVAL;
+++
+++	tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev);
+++	if (!tx_sdata)
+++		return -EINVAL;
+++
+++	if (tx_sdata == sdata) {
+++		sdata->vif.mbssid_tx_vif = &sdata->vif;
+++	} else {
+++		sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
+++		sdata->vif.bss_conf.nontransmitted = true;
+++		sdata->vif.bss_conf.bssid_index = params.index;
+++	}
+++	if (params.ema)
+++		sdata->vif.bss_conf.ema_ap = true;
+++
+++	return 0;
+++}
+++
++ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
++ 						const char *name,
++ 						unsigned char name_assign_type,
++@@ -1107,6 +1137,14 @@ static int ieee80211_start_ap(struct wip
++ 			changed |= BSS_CHANGED_HE_BSS_COLOR;
++ 	}
++ 
+++	if (sdata->vif.type == NL80211_IFTYPE_AP &&
+++	    params->mbssid_config.tx_wdev) {
+++		err = ieee80211_set_ap_mbssid_options(sdata,
+++						      params->mbssid_config);
+++		if (err)
+++			return err;
+++	}
+++
++ 	mutex_lock(&local->mtx);
++ 	err = ieee80211_vif_use_channel(sdata, &params->chandef,
++ 					IEEE80211_CHANCTX_SHARED);
++--- a/net/mac80211/iface.c
+++++ b/net/mac80211/iface.c
++@@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct iee
++ 		ieee80211_add_virtual_monitor(local);
 + }
 + 
-++static int
-++ieee80211_set_radar_offchan(struct wiphy *wiphy,
-++			    struct cfg80211_chan_def *chandef)
+++static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
 ++{
-++	struct ieee80211_local *local = wiphy_priv(wiphy);
+++	struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata;
+++	struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif;
 ++
-++	if (!local->ops->set_radar_offchan)
-++		return -EOPNOTSUPP;
+++	if (!tx_vif)
+++		return;
 ++
-++	return local->ops->set_radar_offchan(&local->hw, chandef);
+++	tx_sdata = vif_to_sdata(tx_vif);
+++	sdata->vif.mbssid_tx_vif = NULL;
+++
+++	list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
+++				 &tx_sdata->local->interfaces, list) {
+++		if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
+++		    non_tx_sdata->vif.mbssid_tx_vif == tx_vif &&
+++		    ieee80211_sdata_running(non_tx_sdata)) {
+++			non_tx_sdata->vif.mbssid_tx_vif = NULL;
+++			dev_close(non_tx_sdata->wdev.netdev);
+++		}
+++	}
+++
+++	if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) {
+++		tx_sdata->vif.mbssid_tx_vif = NULL;
+++		dev_close(tx_sdata->wdev.netdev);
+++	}
 ++}
 ++
-+ const struct cfg80211_ops mac80211_config_ops = {
-+ 	.add_virtual_intf = ieee80211_add_iface,
-+ 	.del_virtual_intf = ieee80211_del_iface,
-+@@ -4448,4 +4460,5 @@ const struct cfg80211_ops mac80211_confi
-+ 	.reset_tid_config = ieee80211_reset_tid_config,
-+ 	.set_sar_specs = ieee80211_set_sar_specs,
-+ 	.color_change = ieee80211_color_change,
-++	.set_radar_offchan = ieee80211_set_radar_offchan,
-+ };
-diff --git a/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch
++ static int ieee80211_stop(struct net_device *dev)
++ {
++ 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
++ 
++-	/* close all dependent VLAN interfaces before locking wiphy */
+++	/* close dependent VLAN and MBSSID interfaces before locking wiphy */
++ 	if (sdata->vif.type == NL80211_IFTYPE_AP) {
++ 		struct ieee80211_sub_if_data *vlan, *tmpsdata;
++ 
++ 		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
++ 					 u.vlan.list)
++ 			dev_close(vlan->dev);
+++
+++		ieee80211_stop_mbssid(sdata);
++ 	}
++ 
++ 	wiphy_lock(sdata->local->hw.wiphy);
+diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
 new file mode 100644
-index 0000000000..c3a4c0db25
+index 0000000000..fdbcce9450
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/320-cfg80211-rename-offchannel_chain-structs-to-backgrou.patch
-@@ -0,0 +1,532 @@
++++ b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
+@@ -0,0 +1,326 @@
 +From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Mon, 29 Nov 2021 14:11:24 +0100
-+Subject: [PATCH] cfg80211: rename offchannel_chain structs to background_chain
-+ to avoid confusion with ETSI standard
++Date: Thu, 24 Feb 2022 12:54:58 +0100
++Subject: [PATCH] mac80211: MBSSID beacon handling in AP mode
 +
-+ETSI standard defines "Offchannel CAC" as:
-+"Off-Channel CAC is performed by a number of non-continuous checks
-+spread over a period in time. This period, which is required to
-+determine the presence of radar signals, is defined as the Off-Channel
-+CAC Time..
-+Minimum Off-Channel CAC Time 6 minutes and Maximum Off-Channel CAC Time
-+4 hours..".
-+mac80211 implementation refers to a dedicated hw chain used for continuous
-+radar monitoring. Rename offchannel_* references to background_* in
-+order to avoid confusion with ETSI standard.
++Add new fields in struct beacon_data to store all MBSSID elements.
++Generate a beacon template which includes all MBSSID elements.
++Move CSA offset to reflect the MBSSID element length.
 +
++Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
++Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
++Co-developed-by: John Crispin <john@phrozen.org>
++Signed-off-by: John Crispin <john@phrozen.org>
 +Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/4204cc1d648d76b44557981713231e030a3bd991.1638190762.git.lorenzo@kernel.org
++Tested-by: Money Wang <money.wang@mediatek.com>
++Link: https://lore.kernel.org/r/5322db3c303f431adaf191ab31c45e151dde5465.1645702516.git.lorenzo@kernel.org
++[small cleanups]
 +Signed-off-by: Johannes Berg <johannes.berg@intel.com>
 +---
 +
-+--- a/include/net/cfg80211.h
-++++ b/include/net/cfg80211.h
-+@@ -4058,14 +4058,14 @@ struct mgmt_frame_regs {
-+  *
-+  * @color_change: Initiate a color change.
-+  *
-+- * @set_radar_offchan: Configure dedicated offchannel chain available for
-++ * @set_radar_background: Configure dedicated offchannel chain available for
-+  *	radar/CAC detection on some hw. This chain can't be used to transmit
-+  *	or receive frames and it is bounded to a running wdev.
-+- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
-++ *	Background radar/CAC detection allows to avoid the CAC downtime
-+  *	switching to a different channel during CAC detection on the selected
-+  *	radar channel.
-+  *	The caller is expected to set chandef pointer to NULL in order to
-+- *	disable offchannel CAC/radar detection.
-++ *	disable background CAC/radar detection.
-+  */
-+ struct cfg80211_ops {
-+ 	int	(*suspend)(struct wiphy *wiphy, struct cfg80211_wowlan *wow);
-+@@ -4396,8 +4396,8 @@ struct cfg80211_ops {
-+ 	int	(*color_change)(struct wiphy *wiphy,
-+ 				struct net_device *dev,
-+ 				struct cfg80211_color_change_settings *params);
-+-	int	(*set_radar_offchan)(struct wiphy *wiphy,
-+-				     struct cfg80211_chan_def *chandef);
-++	int	(*set_radar_background)(struct wiphy *wiphy,
-++					struct cfg80211_chan_def *chandef);
-+ };
-+ 
-+ /*
-+@@ -7601,9 +7601,9 @@ cfg80211_radar_event(struct wiphy *wiphy
-+ }
-+ 
-+ static inline void
-+-cfg80211_offchan_radar_event(struct wiphy *wiphy,
-+-			     struct cfg80211_chan_def *chandef,
-+-			     gfp_t gfp)
-++cfg80211_background_radar_event(struct wiphy *wiphy,
-++				struct cfg80211_chan_def *chandef,
-++				gfp_t gfp)
-+ {
-+ 	__cfg80211_radar_event(wiphy, chandef, true, gfp);
-+ }
-+@@ -7638,13 +7638,13 @@ void cfg80211_cac_event(struct net_devic
-+ 			enum nl80211_radar_event event, gfp_t gfp);
-+ 
-+ /**
-+- * cfg80211_offchan_cac_abort - Channel Availability Check offchan abort event
-++ * cfg80211_background_cac_abort - Channel Availability Check offchan abort event
-+  * @wiphy: the wiphy
-+  *
-+  * This function is called by the driver when a Channel Availability Check
-+  * (CAC) is aborted by a offchannel dedicated chain.
-+  */
-+-void cfg80211_offchan_cac_abort(struct wiphy *wiphy);
-++void cfg80211_background_cac_abort(struct wiphy *wiphy);
-+ 
-+ /**
-+  * cfg80211_gtk_rekey_notify - notify userspace about driver rekeying
 +--- a/include/net/mac80211.h
 ++++ b/include/net/mac80211.h
-+@@ -3937,14 +3937,14 @@ struct ieee80211_prep_tx_info {
-+  *	twt structure.
-+  * @twt_teardown_request: Update the hw with TWT teardown request received
-+  *	from the peer.
-+- * @set_radar_offchan: Configure dedicated offchannel chain available for
-++ * @set_radar_background: Configure dedicated offchannel chain available for
-+  *	radar/CAC detection on some hw. This chain can't be used to transmit
-+  *	or receive frames and it is bounded to a running wdev.
-+- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
-++ *	Background radar/CAC detection allows to avoid the CAC downtime
-+  *	switching to a different channel during CAC detection on the selected
-+  *	radar channel.
-+  *	The caller is expected to set chandef pointer to NULL in order to
-+- *	disable offchannel CAC/radar detection.
-++ *	disable background CAC/radar detection.
-+  * @net_fill_forward_path: Called from .ndo_fill_forward_path in order to
-+  *	resolve a path for hardware flow offloading
-+  */
-+@@ -4275,8 +4275,8 @@ struct ieee80211_ops {
-+ 			      struct ieee80211_twt_setup *twt);
-+ 	void (*twt_teardown_request)(struct ieee80211_hw *hw,
-+ 				     struct ieee80211_sta *sta, u8 flowid);
-+-	int (*set_radar_offchan)(struct ieee80211_hw *hw,
-+-				 struct cfg80211_chan_def *chandef);
-++	int (*set_radar_background)(struct ieee80211_hw *hw,
-++				    struct cfg80211_chan_def *chandef);
-+ #if LINUX_VERSION_IS_GEQ(5,10,0)
-+ 	int (*net_fill_forward_path)(struct ieee80211_hw *hw,
-+ 				     struct ieee80211_vif *vif,
-+--- a/include/uapi/linux/nl80211.h
-++++ b/include/uapi/linux/nl80211.h
-+@@ -2608,10 +2608,10 @@ enum nl80211_commands {
-+  *	Mandatory parameter for the transmitting interface to enable MBSSID.
-+  *	Optional for the non-transmitting interfaces.
-+  *
-+- * @NL80211_ATTR_RADAR_OFFCHAN: Configure dedicated offchannel chain available for
-+- *	radar/CAC detection on some hw. This chain can't be used to transmit
-+- *	or receive frames and it is bounded to a running wdev.
-+- *	Offchannel radar/CAC detection allows to avoid the CAC downtime
-++ * @NL80211_ATTR_RADAR_BACKGROUND: Configure dedicated offchannel chain
-++ *	available for radar/CAC detection on some hw. This chain can't be used
-++ *	to transmit or receive frames and it is bounded to a running wdev.
-++ *	Background radar/CAC detection allows to avoid the CAC downtime
-+  *	switching on a different channel during CAC detection on the selected
-+  *	radar channel.
-+  *
-+@@ -3121,7 +3121,7 @@ enum nl80211_attrs {
-+ 	NL80211_ATTR_MBSSID_CONFIG,
-+ 	NL80211_ATTR_MBSSID_ELEMS,
-+ 
-+-	NL80211_ATTR_RADAR_OFFCHAN,
-++	NL80211_ATTR_RADAR_BACKGROUND,
-+ 
-+ 	/* add attributes here, update the policy in nl80211.c */
-+ 
-+@@ -6022,7 +6022,7 @@ enum nl80211_feature_flags {
-+  * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
-+  *	detection and change announcemnts.
-+  *
-+- * @NL80211_EXT_FEATURE_RADAR_OFFCHAN: Device supports offchannel radar/CAC
-++ * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
-+  *	detection.
-+  *
-+  * @NUM_NL80211_EXT_FEATURES: number of extended features.
-+@@ -6090,7 +6090,7 @@ enum nl80211_ext_feature_index {
-+ 	NL80211_EXT_FEATURE_SECURE_RTT,
-+ 	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
-+ 	NL80211_EXT_FEATURE_BSS_COLOR,
-+-	NL80211_EXT_FEATURE_RADAR_OFFCHAN,
-++	NL80211_EXT_FEATURE_RADAR_BACKGROUND,
++@@ -4938,12 +4938,14 @@ void ieee80211_report_low_ack(struct iee
++  * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets
++  *	to countdown counters.  This array can contain zero values which
++  *	should be ignored.
+++ * @mbssid_off: position of the multiple bssid element
++  */
++ struct ieee80211_mutable_offsets {
++ 	u16 tim_offset;
++ 	u16 tim_length;
 + 
-+ 	/* add new features before the definition below */
-+ 	NUM_NL80211_EXT_FEATURES,
++ 	u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM];
+++	u16 mbssid_off;
++ };
++ 
++ /**
 +--- a/net/mac80211/cfg.c
 ++++ b/net/mac80211/cfg.c
-+@@ -4345,15 +4345,15 @@ out:
++@@ -989,11 +989,29 @@ static int ieee80211_set_ftm_responder_p
++ 	return 0;
 + }
 + 
-+ static int
-+-ieee80211_set_radar_offchan(struct wiphy *wiphy,
-+-			    struct cfg80211_chan_def *chandef)
-++ieee80211_set_radar_background(struct wiphy *wiphy,
-++			       struct cfg80211_chan_def *chandef)
+++static int
+++ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst,
+++			     struct cfg80211_mbssid_elems *src)
+++{
+++	int i, offset = 0;
+++
+++	for (i = 0; i < src->cnt; i++) {
+++		memcpy(pos + offset, src->elem[i].data, src->elem[i].len);
+++		dst->elem[i].len = src->elem[i].len;
+++		dst->elem[i].data = pos + offset;
+++		offset += dst->elem[i].len;
+++	}
+++	dst->cnt = src->cnt;
+++
+++	return offset;
+++}
+++
++ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
++ 				   struct cfg80211_beacon_data *params,
++ 				   const struct ieee80211_csa_settings *csa,
++ 				   const struct ieee80211_color_change_settings *cca)
 + {
-+ 	struct ieee80211_local *local = wiphy_priv(wiphy);
+++	struct cfg80211_mbssid_elems *mbssid = NULL;
++ 	struct beacon_data *new, *old;
++ 	int new_head_len, new_tail_len;
++ 	int size, err;
++@@ -1021,6 +1039,17 @@ static int ieee80211_assign_beacon(struc
 + 
-+-	if (!local->ops->set_radar_offchan)
-++	if (!local->ops->set_radar_background)
-+ 		return -EOPNOTSUPP;
++ 	size = sizeof(*new) + new_head_len + new_tail_len;
 + 
-+-	return local->ops->set_radar_offchan(&local->hw, chandef);
-++	return local->ops->set_radar_background(&local->hw, chandef);
-+ }
+++	/* new or old multiple BSSID elements? */
+++	if (params->mbssid_ies) {
+++		mbssid = params->mbssid_ies;
+++		size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
+++		size += ieee80211_get_mbssid_beacon_len(mbssid);
+++	} else if (old && old->mbssid_ies) {
+++		mbssid = old->mbssid_ies;
+++		size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
+++		size += ieee80211_get_mbssid_beacon_len(mbssid);
+++	}
+++
++ 	new = kzalloc(size, GFP_KERNEL);
++ 	if (!new)
++ 		return -ENOMEM;
++@@ -1029,12 +1058,20 @@ static int ieee80211_assign_beacon(struc
 + 
-+ const struct cfg80211_ops mac80211_config_ops = {
-+@@ -4460,5 +4460,5 @@ const struct cfg80211_ops mac80211_confi
-+ 	.reset_tid_config = ieee80211_reset_tid_config,
-+ 	.set_sar_specs = ieee80211_set_sar_specs,
-+ 	.color_change = ieee80211_color_change,
-+-	.set_radar_offchan = ieee80211_set_radar_offchan,
-++	.set_radar_background = ieee80211_set_radar_background,
-+ };
-+--- a/net/wireless/chan.c
-++++ b/net/wireless/chan.c
-+@@ -716,13 +716,13 @@ static bool
-+ cfg80211_offchan_chain_is_active(struct cfg80211_registered_device *rdev,
-+ 				 struct ieee80211_channel *channel)
-+ {
-+-	if (!rdev->offchan_radar_wdev)
-++	if (!rdev->background_radar_wdev)
-+ 		return false;
++ 	/*
++ 	 * pointers go into the block we allocated,
++-	 * memory is | beacon_data | head | tail |
+++	 * memory is | beacon_data | head | tail | mbssid_ies
++ 	 */
++ 	new->head = ((u8 *) new) + sizeof(*new);
++ 	new->tail = new->head + new_head_len;
++ 	new->head_len = new_head_len;
++ 	new->tail_len = new_tail_len;
+++	/* copy in optional mbssid_ies */
+++	if (mbssid) {
+++		u8 *pos = new->tail + new->tail_len;
+++
+++		new->mbssid_ies = (void *)pos;
+++		pos += struct_size(new->mbssid_ies, elem, mbssid->cnt);
+++		ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid);
+++	}
 + 
-+-	if (!cfg80211_chandef_valid(&rdev->offchan_radar_chandef))
-++	if (!cfg80211_chandef_valid(&rdev->background_radar_chandef))
-+ 		return false;
++ 	if (csa) {
++ 		new->cntdwn_current_counter = csa->count;
++@@ -1332,8 +1369,11 @@ static int ieee80211_stop_ap(struct wiph
 + 
-+-	return cfg80211_is_sub_chan(&rdev->offchan_radar_chandef, channel);
-++	return cfg80211_is_sub_chan(&rdev->background_radar_chandef, channel);
-+ }
++ 	mutex_unlock(&local->mtx);
 + 
-+ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
-+--- a/net/wireless/core.c
-++++ b/net/wireless/core.c
-+@@ -543,9 +543,10 @@ use_default_name:
-+ 	INIT_WORK(&rdev->rfkill_block, cfg80211_rfkill_block_work);
-+ 	INIT_WORK(&rdev->conn_work, cfg80211_conn_work);
-+ 	INIT_WORK(&rdev->event_work, cfg80211_event_work);
-+-	INIT_WORK(&rdev->offchan_cac_abort_wk, cfg80211_offchan_cac_abort_wk);
-+-	INIT_DELAYED_WORK(&rdev->offchan_cac_done_wk,
-+-			  cfg80211_offchan_cac_done_wk);
-++	INIT_WORK(&rdev->background_cac_abort_wk,
-++		  cfg80211_background_cac_abort_wk);
-++	INIT_DELAYED_WORK(&rdev->background_cac_done_wk,
-++			  cfg80211_background_cac_done_wk);
++-	kfree(sdata->u.ap.next_beacon);
++-	sdata->u.ap.next_beacon = NULL;
+++	if (sdata->u.ap.next_beacon) {
+++		kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++		kfree(sdata->u.ap.next_beacon);
+++		sdata->u.ap.next_beacon = NULL;
+++	}
 + 
-+ 	init_waitqueue_head(&rdev->dev_wait);
++ 	/* turn off carrier for this interface and dependent VLANs */
++ 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
++@@ -3126,12 +3166,24 @@ cfg80211_beacon_dup(struct cfg80211_beac
 + 
-+@@ -1055,13 +1056,13 @@ void wiphy_unregister(struct wiphy *wiph
-+ 	cancel_work_sync(&rdev->conn_work);
-+ 	flush_work(&rdev->event_work);
-+ 	cancel_delayed_work_sync(&rdev->dfs_update_channels_wk);
-+-	cancel_delayed_work_sync(&rdev->offchan_cac_done_wk);
-++	cancel_delayed_work_sync(&rdev->background_cac_done_wk);
-+ 	flush_work(&rdev->destroy_work);
-+ 	flush_work(&rdev->sched_scan_stop_wk);
-+ 	flush_work(&rdev->propagate_radar_detect_wk);
-+ 	flush_work(&rdev->propagate_cac_done_wk);
-+ 	flush_work(&rdev->mgmt_registrations_update_wk);
-+-	flush_work(&rdev->offchan_cac_abort_wk);
-++	flush_work(&rdev->background_cac_abort_wk);
++ 	len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
++ 	      beacon->proberesp_ies_len + beacon->assocresp_ies_len +
++-	      beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
+++	      beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len +
+++	      ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
 + 
-+ #ifdef CONFIG_PM
-+ 	if (rdev->wiphy.wowlan_config && rdev->ops->set_wakeup)
-+@@ -1210,7 +1211,7 @@ void __cfg80211_leave(struct cfg80211_re
++ 	new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
++ 	if (!new_beacon)
++ 		return NULL;
 + 
-+ 	cfg80211_pmsr_wdev_down(wdev);
+++	if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) {
+++		new_beacon->mbssid_ies =
+++			kzalloc(struct_size(new_beacon->mbssid_ies,
+++					    elem, beacon->mbssid_ies->cnt),
+++				GFP_KERNEL);
+++		if (!new_beacon->mbssid_ies) {
+++			kfree(new_beacon);
+++			return NULL;
+++		}
+++	}
+++
++ 	pos = (u8 *)(new_beacon + 1);
++ 	if (beacon->head_len) {
++ 		new_beacon->head_len = beacon->head_len;
++@@ -3169,6 +3221,10 @@ cfg80211_beacon_dup(struct cfg80211_beac
++ 		memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
++ 		pos += beacon->probe_resp_len;
++ 	}
+++	if (beacon->mbssid_ies && beacon->mbssid_ies->cnt)
+++		pos += ieee80211_copy_mbssid_beacon(pos,
+++						    new_beacon->mbssid_ies,
+++						    beacon->mbssid_ies);
 + 
-+-	cfg80211_stop_offchan_radar_detection(wdev);
-++	cfg80211_stop_background_radar_detection(wdev);
++ 	/* might copy -1, meaning no changes requested */
++ 	new_beacon->ftm_responder = beacon->ftm_responder;
++@@ -3206,8 +3262,11 @@ static int ieee80211_set_after_csa_beaco
++ 	case NL80211_IFTYPE_AP:
++ 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
++ 					      NULL, NULL);
++-		kfree(sdata->u.ap.next_beacon);
++-		sdata->u.ap.next_beacon = NULL;
+++		if (sdata->u.ap.next_beacon) {
+++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++			kfree(sdata->u.ap.next_beacon);
+++			sdata->u.ap.next_beacon = NULL;
+++		}
 + 
-+ 	switch (wdev->iftype) {
-+ 	case NL80211_IFTYPE_ADHOC:
-+--- a/net/wireless/core.h
-++++ b/net/wireless/core.h
-+@@ -84,10 +84,10 @@ struct cfg80211_registered_device {
++ 		if (err < 0)
++ 			return err;
++@@ -3362,8 +3421,12 @@ static int ieee80211_set_csa_beacon(stru
++ 		if ((params->n_counter_offsets_beacon >
++ 		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM) ||
++ 		    (params->n_counter_offsets_presp >
++-		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM))
+++		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) {
+++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++			kfree(sdata->u.ap.next_beacon);
+++			sdata->u.ap.next_beacon = NULL;
++ 			return -EINVAL;
+++		}
++ 
++ 		csa.counter_offsets_beacon = params->counter_offsets_beacon;
++ 		csa.counter_offsets_presp = params->counter_offsets_presp;
++@@ -3373,7 +3436,9 @@ static int ieee80211_set_csa_beacon(stru
++ 
++ 		err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa, NULL);
++ 		if (err < 0) {
+++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
++ 			kfree(sdata->u.ap.next_beacon);
+++			sdata->u.ap.next_beacon = NULL;
++ 			return err;
++ 		}
++ 		*changed |= err;
++@@ -3463,8 +3528,11 @@ static int ieee80211_set_csa_beacon(stru
++ static void ieee80211_color_change_abort(struct ieee80211_sub_if_data  *sdata)
++ {
++ 	sdata->vif.color_change_active = false;
++-	kfree(sdata->u.ap.next_beacon);
++-	sdata->u.ap.next_beacon = NULL;
+++	if (sdata->u.ap.next_beacon) {
+++		kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++		kfree(sdata->u.ap.next_beacon);
+++		sdata->u.ap.next_beacon = NULL;
+++	}
++ 
++ 	cfg80211_color_change_aborted_notify(sdata->dev);
++ }
++@@ -4202,8 +4270,11 @@ ieee80211_set_after_color_change_beacon(
++ 
++ 		ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
++ 					      NULL, NULL);
++-		kfree(sdata->u.ap.next_beacon);
++-		sdata->u.ap.next_beacon = NULL;
+++		if (sdata->u.ap.next_beacon) {
+++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++			kfree(sdata->u.ap.next_beacon);
+++			sdata->u.ap.next_beacon = NULL;
+++		}
 + 
-+ 	struct delayed_work dfs_update_channels_wk;
++ 		if (ret < 0)
++ 			return ret;
++@@ -4246,7 +4317,11 @@ ieee80211_set_color_change_beacon(struct
++ 		err = ieee80211_assign_beacon(sdata, &params->beacon_color_change,
++ 					      NULL, &color_change);
++ 		if (err < 0) {
++-			kfree(sdata->u.ap.next_beacon);
+++			if (sdata->u.ap.next_beacon) {
+++				kfree(sdata->u.ap.next_beacon->mbssid_ies);
+++				kfree(sdata->u.ap.next_beacon);
+++				sdata->u.ap.next_beacon = NULL;
+++			}
++ 			return err;
++ 		}
++ 		*changed |= err;
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -261,6 +261,7 @@ struct beacon_data {
++ 	struct ieee80211_meshconf_ie *meshconf;
++ 	u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM];
++ 	u8 cntdwn_current_counter;
+++	struct cfg80211_mbssid_elems *mbssid_ies;
++ 	struct rcu_head rcu_head;
++ };
 + 
-+-	struct wireless_dev *offchan_radar_wdev;
-+-	struct cfg80211_chan_def offchan_radar_chandef;
-+-	struct delayed_work offchan_cac_done_wk;
-+-	struct work_struct offchan_cac_abort_wk;
-++	struct wireless_dev *background_radar_wdev;
-++	struct cfg80211_chan_def background_radar_chandef;
-++	struct delayed_work background_cac_done_wk;
-++	struct work_struct background_cac_abort_wk;
++@@ -1083,6 +1084,20 @@ ieee80211_vif_get_shift(struct ieee80211
++ 	return shift;
++ }
 + 
-+ 	/* netlink port which started critical protocol (0 means not started) */
-+ 	u32 crit_proto_nlportid;
-+@@ -497,15 +497,15 @@ cfg80211_chandef_dfs_cac_time(struct wip
-+ void cfg80211_sched_dfs_chan_update(struct cfg80211_registered_device *rdev);
+++static inline int
+++ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems)
+++{
+++	int i, len = 0;
+++
+++	if (!elems)
+++		return 0;
+++
+++	for (i = 0; i < elems->cnt; i++)
+++		len += elems->elem[i].len;
+++
+++	return len;
+++}
+++
++ enum {
++ 	IEEE80211_RX_MSG	= 1,
++ 	IEEE80211_TX_STATUS_MSG	= 2,
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -5041,6 +5041,19 @@ ieee80211_beacon_get_finish(struct ieee8
++ 		       IEEE80211_TX_CTL_FIRST_FRAGMENT;
++ }
 + 
-+ int
-+-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
-+-				       struct wireless_dev *wdev,
-+-				       struct cfg80211_chan_def *chandef);
-++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
-++					  struct wireless_dev *wdev,
-++					  struct cfg80211_chan_def *chandef);
+++static void
+++ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon)
+++{
+++	int i;
+++
+++	if (!beacon->mbssid_ies)
+++		return;
+++
+++	for (i = 0; i < beacon->mbssid_ies->cnt; i++)
+++		skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
+++			     beacon->mbssid_ies->elem[i].len);
+++}
+++
++ static struct sk_buff *
++ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
++ 			struct ieee80211_vif *vif,
++@@ -5054,6 +5067,7 @@ ieee80211_beacon_get_ap(struct ieee80211
++ 	struct ieee80211_if_ap *ap = &sdata->u.ap;
++ 	struct sk_buff *skb = NULL;
++ 	u16 csa_off_base = 0;
+++	int mbssid_len;
 + 
-+-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev);
-++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev);
++ 	if (beacon->cntdwn_counter_offsets[0]) {
++ 		if (!is_template)
++@@ -5063,11 +5077,12 @@ ieee80211_beacon_get_ap(struct ieee80211
++ 	}
 + 
-+-void cfg80211_offchan_cac_done_wk(struct work_struct *work);
-++void cfg80211_background_cac_done_wk(struct work_struct *work);
++ 	/* headroom, head length,
++-	 * tail length and maximum TIM length
+++	 * tail length, maximum TIM length and multiple BSSID length
++ 	 */
+++	mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
++ 	skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
++ 			    beacon->tail_len + 256 +
++-			    local->hw.extra_beacon_tailroom);
+++			    local->hw.extra_beacon_tailroom + mbssid_len);
++ 	if (!skb)
++ 		return NULL;
 + 
-+-void cfg80211_offchan_cac_abort_wk(struct work_struct *work);
-++void cfg80211_background_cac_abort_wk(struct work_struct *work);
++@@ -5081,6 +5096,11 @@ ieee80211_beacon_get_ap(struct ieee80211
++ 		offs->tim_length = skb->len - beacon->head_len;
++ 		offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
 + 
-+ bool cfg80211_any_wiphy_oper_chan(struct wiphy *wiphy,
-+ 				  struct ieee80211_channel *chan);
-+--- a/net/wireless/mlme.c
-++++ b/net/wireless/mlme.c
-+@@ -920,7 +920,7 @@ void __cfg80211_radar_event(struct wiphy
-+ 	cfg80211_set_dfs_state(wiphy, chandef, NL80211_DFS_UNAVAILABLE);
+++		if (mbssid_len) {
+++			ieee80211_beacon_add_mbssid(skb, beacon);
+++			offs->mbssid_off = skb->len - mbssid_len;
+++		}
+++
++ 		/* for AP the csa offsets are from tail */
++ 		csa_off_base = skb->len;
++ 	}
+diff --git a/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch
+new file mode 100644
+index 0000000000..38b0de180e
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch
+@@ -0,0 +1,52 @@
++From: John Crispin <john@phrozen.org>
++Date: Thu, 24 Feb 2022 12:54:59 +0100
++Subject: [PATCH] mac80211: MBSSID channel switch
++
++Trigger ieee80211_csa_finish() on the non-transmitting interfaces
++when channel switch concludes on the transmitting interface.
++
++Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
++Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
++Signed-off-by: John Crispin <john@phrozen.org>
++Link: https://lore.kernel.org/r/6fde4d7f9fa387494f46a7aa4a584478dcda06f1.1645702516.git.lorenzo@kernel.org
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/cfg.c
+++++ b/net/mac80211/cfg.c
++@@ -3247,9 +3247,31 @@ cfg80211_beacon_dup(struct cfg80211_beac
++ void ieee80211_csa_finish(struct ieee80211_vif *vif)
++ {
++ 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+++	struct ieee80211_local *local = sdata->local;
 + 
-+ 	if (offchan)
-+-		queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
-++		queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
++-	ieee80211_queue_work(&sdata->local->hw,
++-			     &sdata->csa_finalize_work);
+++	rcu_read_lock();
+++
+++	if (vif->mbssid_tx_vif == vif) {
+++		/* Trigger ieee80211_csa_finish() on the non-transmitting
+++		 * interfaces when channel switch is received on
+++		 * transmitting interface
+++		 */
+++		struct ieee80211_sub_if_data *iter;
+++
+++		list_for_each_entry_rcu(iter, &local->interfaces, list) {
+++			if (!ieee80211_sdata_running(iter))
+++				continue;
+++
+++			if (iter == sdata || iter->vif.mbssid_tx_vif != vif)
+++				continue;
+++
+++			ieee80211_queue_work(&iter->local->hw,
+++					     &iter->csa_finalize_work);
+++		}
+++	}
+++	ieee80211_queue_work(&local->hw, &sdata->csa_finalize_work);
+++
+++	rcu_read_unlock();
++ }
++ EXPORT_SYMBOL(ieee80211_csa_finish);
 + 
-+ 	cfg80211_sched_dfs_chan_update(rdev);
+diff --git a/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch
+new file mode 100644
+index 0000000000..1955568607
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch
+@@ -0,0 +1,25 @@
++From: Lorenzo Bianconi <lorenzo@kernel.org>
++Date: Thu, 24 Feb 2022 12:55:00 +0100
++Subject: [PATCH] mac80211: update bssid_indicator in
++ ieee80211_assign_beacon
++
++Update bssid_indicator in ieee80211_bss_conf according to the
++number of bssid in the set.
++
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Link: https://lore.kernel.org/r/f92317e002fca9933f05a445fcefb4f53291d601.1645702516.git.lorenzo@kernel.org
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++
++--- a/net/mac80211/cfg.c
+++++ b/net/mac80211/cfg.c
++@@ -1071,6 +1071,9 @@ static int ieee80211_assign_beacon(struc
++ 		new->mbssid_ies = (void *)pos;
++ 		pos += struct_size(new->mbssid_ies, elem, mbssid->cnt);
++ 		ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid);
+++		/* update bssid_indicator */
+++		sdata->vif.bss_conf.bssid_indicator =
+++			ilog2(__roundup_pow_of_two(mbssid->cnt + 1));
++ 	}
 + 
-+@@ -975,10 +975,10 @@ void cfg80211_cac_event(struct net_devic
-+ EXPORT_SYMBOL(cfg80211_cac_event);
++ 	if (csa) {
+diff --git a/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch b/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch
+new file mode 100644
+index 0000000000..f0150ddef0
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/328-mac80211-do-not-wake-queues-on-a-vif-that-is-being-s.patch
+@@ -0,0 +1,38 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Sat, 26 Mar 2022 23:58:35 +0100
++Subject: [PATCH] mac80211: do not wake queues on a vif that is being stopped
++
++When a vif is being removed and sdata->bss is cleared, __ieee80211_wake_txqs
++can still be called on it, which crashes as soon as sdata->bss is being
++dereferenced.
++To fix this properly, check for SDATA_STATE_RUNNING before waking queues,
++and take the fq lock when setting it (to ensure that __ieee80211_wake_txqs
++observes the change when running on a different CPU
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/iface.c
+++++ b/net/mac80211/iface.c
++@@ -377,7 +377,9 @@ static void ieee80211_do_stop(struct iee
++ 	bool cancel_scan;
++ 	struct cfg80211_nan_func *func;
++ 
+++	spin_lock_bh(&local->fq.lock);
++ 	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
+++	spin_unlock_bh(&local->fq.lock);
++ 
++ 	cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
++ 	if (cancel_scan)
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -301,6 +301,9 @@ static void __ieee80211_wake_txqs(struct
++ 	local_bh_disable();
++ 	spin_lock(&fq->lock);
++ 
+++	if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
+++		goto out;
+++
++ 	if (sdata->vif.type == NL80211_IFTYPE_AP)
++ 		ps = &sdata->bss->ps;
 + 
-+ static void
-+-__cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev,
-+-			     struct wireless_dev *wdev,
-+-			     const struct cfg80211_chan_def *chandef,
-+-			     enum nl80211_radar_event event)
-++__cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
-++				struct wireless_dev *wdev,
-++				const struct cfg80211_chan_def *chandef,
-++				enum nl80211_radar_event event)
-+ {
-+ 	struct wiphy *wiphy = &rdev->wiphy;
-+ 	struct net_device *netdev;
-+@@ -988,7 +988,7 @@ __cfg80211_offchan_cac_event(struct cfg8
-+ 	if (!cfg80211_chandef_valid(chandef))
-+ 		return;
+diff --git a/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch
+new file mode 100644
+index 0000000000..0ca53860a5
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/330-mac80211-switch-airtime-fairness-back-to-deficit-rou.patch
+@@ -0,0 +1,1249 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Sun, 19 Jun 2022 23:13:05 +0200
++Subject: [PATCH] mac80211: switch airtime fairness back to deficit round-robin
++ scheduling
++
++This reverts commits 6a789ba679d652587532cec2a0e0274fda172f3b and
++2433647bc8d983a543e7d31b41ca2de1c7e2c198.
++
++The virtual time scheduler code has a number of issues:
++- queues slowed down by hardware/firmware powersave handling were not properly
++  handled.
++- on ath10k in push-pull mode, tx queues that the driver tries to pull from
++  were starved, causing excessive latency
++- delay between tx enqueue and reported airtime use were causing excessively
++  bursty tx behavior
++
++The bursty behavior may also be present on the round-robin scheduler, but there
++it is much easier to fix without introducing additional regressions
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/include/net/mac80211.h
+++++ b/include/net/mac80211.h
++@@ -6666,6 +6666,9 @@ static inline void ieee80211_txq_schedul
++ {
++ }
 + 
-+-	if (!rdev->offchan_radar_wdev)
-++	if (!rdev->background_radar_wdev)
-+ 		return;
+++void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
+++			      struct ieee80211_txq *txq, bool force);
+++
++ /**
++  * ieee80211_schedule_txq - schedule a TXQ for transmission
++  *
++@@ -6678,7 +6681,11 @@ static inline void ieee80211_txq_schedul
++  * The driver may call this function if it has buffered packets for
++  * this TXQ internally.
++  */
++-void ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq);
+++static inline void
+++ieee80211_schedule_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq)
+++{
+++	__ieee80211_schedule_txq(hw, txq, true);
+++}
 + 
-+ 	switch (event) {
-+@@ -997,12 +997,12 @@ __cfg80211_offchan_cac_event(struct cfg8
-+ 		memcpy(&rdev->cac_done_chandef, chandef, sizeof(*chandef));
-+ 		queue_work(cfg80211_wq, &rdev->propagate_cac_done_wk);
-+ 		cfg80211_sched_dfs_chan_update(rdev);
-+-		wdev = rdev->offchan_radar_wdev;
-++		wdev = rdev->background_radar_wdev;
-+ 		break;
-+ 	case NL80211_RADAR_CAC_ABORTED:
-+-		if (!cancel_delayed_work(&rdev->offchan_cac_done_wk))
-++		if (!cancel_delayed_work(&rdev->background_cac_done_wk))
-+ 			return;
-+-		wdev = rdev->offchan_radar_wdev;
-++		wdev = rdev->background_radar_wdev;
-+ 		break;
-+ 	case NL80211_RADAR_CAC_STARTED:
-+ 		break;
-+@@ -1015,49 +1015,49 @@ __cfg80211_offchan_cac_event(struct cfg8
++ /**
++  * ieee80211_return_txq - return a TXQ previously acquired by ieee80211_next_txq()
++@@ -6690,8 +6697,12 @@ void ieee80211_schedule_txq(struct ieee8
++  * The driver may set force=true if it has buffered packets for this TXQ
++  * internally.
++  */
++-void ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
++-			  bool force);
+++static inline void
+++ieee80211_return_txq(struct ieee80211_hw *hw, struct ieee80211_txq *txq,
+++		     bool force)
+++{
+++	__ieee80211_schedule_txq(hw, txq, force);
+++}
++ 
++ /**
++  * ieee80211_txq_may_transmit - check whether TXQ is allowed to transmit
++--- a/net/mac80211/cfg.c
+++++ b/net/mac80211/cfg.c
++@@ -1554,38 +1554,6 @@ static void sta_apply_mesh_params(struct
++ #endif
 + }
 + 
-+ static void
-+-cfg80211_offchan_cac_event(struct cfg80211_registered_device *rdev,
-+-			   const struct cfg80211_chan_def *chandef,
-+-			   enum nl80211_radar_event event)
-++cfg80211_background_cac_event(struct cfg80211_registered_device *rdev,
-++			      const struct cfg80211_chan_def *chandef,
-++			      enum nl80211_radar_event event)
-+ {
-+ 	wiphy_lock(&rdev->wiphy);
-+-	__cfg80211_offchan_cac_event(rdev, rdev->offchan_radar_wdev,
-+-				     chandef, event);
-++	__cfg80211_background_cac_event(rdev, rdev->background_radar_wdev,
-++					chandef, event);
-+ 	wiphy_unlock(&rdev->wiphy);
++-static void sta_apply_airtime_params(struct ieee80211_local *local,
++-				     struct sta_info *sta,
++-				     struct station_parameters *params)
++-{
++-	u8 ac;
++-
++-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++-		struct airtime_sched_info *air_sched = &local->airtime[ac];
++-		struct airtime_info *air_info = &sta->airtime[ac];
++-		struct txq_info *txqi;
++-		u8 tid;
++-
++-		spin_lock_bh(&air_sched->lock);
++-		for (tid = 0; tid < IEEE80211_NUM_TIDS + 1; tid++) {
++-			if (air_info->weight == params->airtime_weight ||
++-			    !sta->sta.txq[tid] ||
++-			    ac != ieee80211_ac_from_tid(tid))
++-				continue;
++-
++-			airtime_weight_set(air_info, params->airtime_weight);
++-
++-			txqi = to_txq_info(sta->sta.txq[tid]);
++-			if (RB_EMPTY_NODE(&txqi->schedule_order))
++-				continue;
++-
++-			ieee80211_update_airtime_weight(local, air_sched,
++-							0, true);
++-		}
++-		spin_unlock_bh(&air_sched->lock);
++-	}
++-}
++-
++ static int sta_apply_parameters(struct ieee80211_local *local,
++ 				struct sta_info *sta,
++ 				struct station_parameters *params)
++@@ -1773,8 +1741,7 @@ static int sta_apply_parameters(struct i
++ 		sta_apply_mesh_params(local, sta, params);
++ 
++ 	if (params->airtime_weight)
++-		sta_apply_airtime_params(local, sta, params);
++-
+++		sta->airtime_weight = params->airtime_weight;
++ 
++ 	/* set the STA state after all sta info from usermode has been set */
++ 	if (test_sta_flag(sta, WLAN_STA_TDLS_PEER) ||
++--- a/net/mac80211/debugfs.c
+++++ b/net/mac80211/debugfs.c
++@@ -216,14 +216,14 @@ static ssize_t aql_txq_limit_read(struct
++ 			"VI	%u		%u\n"
++ 			"BE	%u		%u\n"
++ 			"BK	%u		%u\n",
++-			local->airtime[IEEE80211_AC_VO].aql_txq_limit_low,
++-			local->airtime[IEEE80211_AC_VO].aql_txq_limit_high,
++-			local->airtime[IEEE80211_AC_VI].aql_txq_limit_low,
++-			local->airtime[IEEE80211_AC_VI].aql_txq_limit_high,
++-			local->airtime[IEEE80211_AC_BE].aql_txq_limit_low,
++-			local->airtime[IEEE80211_AC_BE].aql_txq_limit_high,
++-			local->airtime[IEEE80211_AC_BK].aql_txq_limit_low,
++-			local->airtime[IEEE80211_AC_BK].aql_txq_limit_high);
+++			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);
 + }
++@@ -255,11 +255,11 @@ static ssize_t aql_txq_limit_write(struc
++ 	if (ac >= IEEE80211_NUM_ACS)
++ 		return -EINVAL;
 + 
-+-void cfg80211_offchan_cac_done_wk(struct work_struct *work)
-++void cfg80211_background_cac_done_wk(struct work_struct *work)
-+ {
-+ 	struct delayed_work *delayed_work = to_delayed_work(work);
-+ 	struct cfg80211_registered_device *rdev;
++-	q_limit_low_old = local->airtime[ac].aql_txq_limit_low;
++-	q_limit_high_old = local->airtime[ac].aql_txq_limit_high;
+++	q_limit_low_old = local->aql_txq_limit_low[ac];
+++	q_limit_high_old = local->aql_txq_limit_high[ac];
 + 
-+ 	rdev = container_of(delayed_work, struct cfg80211_registered_device,
-+-			    offchan_cac_done_wk);
-+-	cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef,
-+-				   NL80211_RADAR_CAC_FINISHED);
-++			    background_cac_done_wk);
-++	cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
-++				      NL80211_RADAR_CAC_FINISHED);
-+ }
++-	local->airtime[ac].aql_txq_limit_low = q_limit_low;
++-	local->airtime[ac].aql_txq_limit_high = q_limit_high;
+++	local->aql_txq_limit_low[ac] = q_limit_low;
+++	local->aql_txq_limit_high[ac] = q_limit_high;
 + 
-+-void cfg80211_offchan_cac_abort_wk(struct work_struct *work)
-++void cfg80211_background_cac_abort_wk(struct work_struct *work)
-+ {
-+ 	struct cfg80211_registered_device *rdev;
++ 	mutex_lock(&local->sta_mtx);
++ 	list_for_each_entry(sta, &local->sta_list, list) {
++@@ -382,46 +382,6 @@ static const struct file_operations forc
++ 	.llseek = default_llseek,
++ };
 + 
-+ 	rdev = container_of(work, struct cfg80211_registered_device,
-+-			    offchan_cac_abort_wk);
-+-	cfg80211_offchan_cac_event(rdev, &rdev->offchan_radar_chandef,
-+-				   NL80211_RADAR_CAC_ABORTED);
-++			    background_cac_abort_wk);
-++	cfg80211_background_cac_event(rdev, &rdev->background_radar_chandef,
-++				      NL80211_RADAR_CAC_ABORTED);
++-static ssize_t airtime_read(struct file *file,
++-			    char __user *user_buf,
++-			    size_t count,
++-			    loff_t *ppos)
++-{
++-	struct ieee80211_local *local = file->private_data;
++-	char buf[200];
++-	u64 v_t[IEEE80211_NUM_ACS];
++-	u64 wt[IEEE80211_NUM_ACS];
++-	int len = 0, ac;
++-
++-	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++-		spin_lock_bh(&local->airtime[ac].lock);
++-		v_t[ac] = local->airtime[ac].v_t;
++-		wt[ac] = local->airtime[ac].weight_sum;
++-		spin_unlock_bh(&local->airtime[ac].lock);
++-	}
++-	len = scnprintf(buf, sizeof(buf),
++-			"\tVO         VI         BE         BK\n"
++-			"Virt-t\t%-10llu %-10llu %-10llu %-10llu\n"
++-			"Weight\t%-10llu %-10llu %-10llu %-10llu\n",
++-			v_t[0],
++-			v_t[1],
++-			v_t[2],
++-			v_t[3],
++-			wt[0],
++-			wt[1],
++-			wt[2],
++-			wt[3]);
++-
++-	return simple_read_from_buffer(user_buf, count, ppos,
++-				       buf, len);
++-}
++-
++-static const struct file_operations airtime_ops = {
++-	.read = airtime_read,
++-	.open = simple_open,
++-	.llseek = default_llseek,
++-};
++-
++ #ifdef CONFIG_PM
++ static ssize_t reset_write(struct file *file, const char __user *user_buf,
++ 			   size_t count, loff_t *ppos)
++@@ -672,11 +632,7 @@ void debugfs_hw_add(struct ieee80211_loc
++ 	if (local->ops->wake_tx_queue)
++ 		DEBUGFS_ADD_MODE(aqm, 0600);
++ 
++-	if (wiphy_ext_feature_isset(local->hw.wiphy,
++-				    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
++-		DEBUGFS_ADD_MODE(airtime, 0600);
++-		DEBUGFS_ADD_MODE(airtime_flags, 0600);
++-	}
+++	DEBUGFS_ADD_MODE(airtime_flags, 0600);
++ 
++ 	DEBUGFS_ADD(aql_txq_limit);
++ 	debugfs_create_u32("aql_threshold", 0600,
++--- a/net/mac80211/debugfs_netdev.c
+++++ b/net/mac80211/debugfs_netdev.c
++@@ -512,34 +512,6 @@ static ssize_t ieee80211_if_fmt_aqm(
 + }
++ IEEE80211_IF_FILE_R(aqm);
 + 
-+-void cfg80211_offchan_cac_abort(struct wiphy *wiphy)
-++void cfg80211_background_cac_abort(struct wiphy *wiphy)
-+ {
-+ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
++-static ssize_t ieee80211_if_fmt_airtime(
++-	const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
++-{
++-	struct ieee80211_local *local = sdata->local;
++-	struct ieee80211_txq *txq = sdata->vif.txq;
++-	struct airtime_info *air_info;
++-	int len;
++-
++-	if (!txq)
++-		return 0;
++-
++-	spin_lock_bh(&local->airtime[txq->ac].lock);
++-	air_info = to_airtime_info(txq);
++-	len = scnprintf(buf,
++-			buflen,
++-			"RX: %llu us\nTX: %llu us\nWeight: %u\n"
++-			"Virt-T: %lld us\n",
++-			air_info->rx_airtime,
++-			air_info->tx_airtime,
++-			air_info->weight,
++-			air_info->v_t);
++-	spin_unlock_bh(&local->airtime[txq->ac].lock);
++-
++-	return len;
++-}
++-
++-IEEE80211_IF_FILE_R(airtime);
++-
++ IEEE80211_IF_FILE(multicast_to_unicast, u.ap.multicast_to_unicast, HEX);
 + 
-+-	queue_work(cfg80211_wq, &rdev->offchan_cac_abort_wk);
-++	queue_work(cfg80211_wq, &rdev->background_cac_abort_wk);
++ /* IBSS attributes */
++@@ -685,10 +657,8 @@ static void add_common_files(struct ieee
++ 
++ 	if (sdata->local->ops->wake_tx_queue &&
++ 	    sdata->vif.type != NL80211_IFTYPE_P2P_DEVICE &&
++-	    sdata->vif.type != NL80211_IFTYPE_NAN) {
+++	    sdata->vif.type != NL80211_IFTYPE_NAN)
++ 		DEBUGFS_ADD(aqm);
++-		DEBUGFS_ADD(airtime);
++-	}
 + }
-+-EXPORT_SYMBOL(cfg80211_offchan_cac_abort);
-++EXPORT_SYMBOL(cfg80211_background_cac_abort);
 + 
-+ int
-+-cfg80211_start_offchan_radar_detection(struct cfg80211_registered_device *rdev,
-+-				       struct wireless_dev *wdev,
-+-				       struct cfg80211_chan_def *chandef)
-++cfg80211_start_background_radar_detection(struct cfg80211_registered_device *rdev,
-++					  struct wireless_dev *wdev,
-++					  struct cfg80211_chan_def *chandef)
-+ {
-+ 	unsigned int cac_time_ms;
-+ 	int err;
-+@@ -1065,19 +1065,19 @@ cfg80211_start_offchan_radar_detection(s
-+ 	lockdep_assert_wiphy(&rdev->wiphy);
++ static void add_sta_files(struct ieee80211_sub_if_data *sdata)
++--- a/net/mac80211/debugfs_sta.c
+++++ b/net/mac80211/debugfs_sta.c
++@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f
++ 	size_t bufsz = 400;
++ 	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
++ 	u64 rx_airtime = 0, tx_airtime = 0;
++-	u64 v_t[IEEE80211_NUM_ACS];
+++	s64 deficit[IEEE80211_NUM_ACS];
++ 	ssize_t rv;
++ 	int ac;
++ 
++@@ -210,18 +210,18 @@ static ssize_t sta_airtime_read(struct f
++ 		return -ENOMEM;
 + 
-+ 	if (!wiphy_ext_feature_isset(&rdev->wiphy,
-+-				     NL80211_EXT_FEATURE_RADAR_OFFCHAN))
-++				     NL80211_EXT_FEATURE_RADAR_BACKGROUND))
-+ 		return -EOPNOTSUPP;
++ 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++-		spin_lock_bh(&local->airtime[ac].lock);
+++		spin_lock_bh(&local->active_txq_lock[ac]);
++ 		rx_airtime += sta->airtime[ac].rx_airtime;
++ 		tx_airtime += sta->airtime[ac].tx_airtime;
++-		v_t[ac] = sta->airtime[ac].v_t;
++-		spin_unlock_bh(&local->airtime[ac].lock);
+++		deficit[ac] = sta->airtime[ac].deficit;
+++		spin_unlock_bh(&local->active_txq_lock[ac]);
++ 	}
 + 
-+ 	/* Offchannel chain already locked by another wdev */
-+-	if (rdev->offchan_radar_wdev && rdev->offchan_radar_wdev != wdev)
-++	if (rdev->background_radar_wdev && rdev->background_radar_wdev != wdev)
-+ 		return -EBUSY;
++ 	p += scnprintf(p, bufsz + buf - p,
++ 		"RX: %llu us\nTX: %llu us\nWeight: %u\n"
++-		"Virt-T: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
++-		rx_airtime, tx_airtime, sta->airtime[0].weight,
++-		v_t[0], v_t[1], v_t[2], v_t[3]);
+++		"Deficit: VO: %lld us VI: %lld us BE: %lld us BK: %lld us\n",
+++		rx_airtime, tx_airtime, sta->airtime_weight,
+++		deficit[0], deficit[1], deficit[2], deficit[3]);
++ 
++ 	rv = simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
++ 	kfree(buf);
++@@ -236,11 +236,11 @@ static ssize_t sta_airtime_write(struct
++ 	int ac;
++ 
++ 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++-		spin_lock_bh(&local->airtime[ac].lock);
+++		spin_lock_bh(&local->active_txq_lock[ac]);
++ 		sta->airtime[ac].rx_airtime = 0;
++ 		sta->airtime[ac].tx_airtime = 0;
++-		sta->airtime[ac].v_t = 0;
++-		spin_unlock_bh(&local->airtime[ac].lock);
+++		sta->airtime[ac].deficit = sta->airtime_weight;
+++		spin_unlock_bh(&local->active_txq_lock[ac]);
++ 	}
 + 
-+ 	/* CAC already in progress on the offchannel chain */
-+-	if (rdev->offchan_radar_wdev == wdev &&
-+-	    delayed_work_pending(&rdev->offchan_cac_done_wk))
-++	if (rdev->background_radar_wdev == wdev &&
-++	    delayed_work_pending(&rdev->background_cac_done_wk))
-+ 		return -EBUSY;
++ 	return count;
++@@ -263,10 +263,10 @@ static ssize_t sta_aql_read(struct file
++ 		return -ENOMEM;
 + 
-+-	err = rdev_set_radar_offchan(rdev, chandef);
-++	err = rdev_set_radar_background(rdev, chandef);
-+ 	if (err)
-+ 		return err;
++ 	for (ac = 0; ac < IEEE80211_NUM_ACS; ac++) {
++-		spin_lock_bh(&local->airtime[ac].lock);
+++		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->airtime[ac].lock);
+++		spin_unlock_bh(&local->active_txq_lock[ac]);
++ 		q_depth[ac] = atomic_read(&sta->airtime[ac].aql_tx_pending);
++ 	}
 + 
-+@@ -1085,30 +1085,31 @@ cfg80211_start_offchan_radar_detection(s
-+ 	if (!cac_time_ms)
-+ 		cac_time_ms = IEEE80211_DFS_MIN_CAC_TIME_MS;
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -863,16 +863,20 @@ enum txq_info_flags {
++  * @def_flow: used as a fallback flow when a packet destined to @tin hashes to
++  *	a fq_flow which is already owned by a different tin
++  * @def_cvars: codel vars for @def_flow
++- * @schedule_order: used with ieee80211_local->active_txqs
++  * @frags: used to keep fragments created after dequeue
+++ * @schedule_order: used with ieee80211_local->active_txqs
+++ * @schedule_round: counter to prevent infinite loops on TXQ scheduling
++  */
++ struct txq_info {
++ 	struct fq_tin tin;
++ 	struct codel_vars def_cvars;
++ 	struct codel_stats cstats;
++-	struct rb_node schedule_order;
+++
+++	u16 schedule_round;
+++	struct list_head schedule_order;
 + 
-+-	rdev->offchan_radar_chandef = *chandef;
-+-	rdev->offchan_radar_wdev = wdev; /* Get offchain ownership */
-++	rdev->background_radar_chandef = *chandef;
-++	rdev->background_radar_wdev = wdev; /* Get offchain ownership */
++ 	struct sk_buff_head frags;
+++
++ 	unsigned long flags;
 + 
-+-	__cfg80211_offchan_cac_event(rdev, wdev, chandef,
-+-				     NL80211_RADAR_CAC_STARTED);
-+-	queue_delayed_work(cfg80211_wq, &rdev->offchan_cac_done_wk,
-++	__cfg80211_background_cac_event(rdev, wdev, chandef,
-++					NL80211_RADAR_CAC_STARTED);
-++	queue_delayed_work(cfg80211_wq, &rdev->background_cac_done_wk,
-+ 			   msecs_to_jiffies(cac_time_ms));
++ 	/* keep last! */
++@@ -949,8 +953,6 @@ struct ieee80211_sub_if_data {
++ 	struct ieee80211_tx_queue_params tx_conf[IEEE80211_NUM_ACS];
++ 	struct mac80211_qos_map __rcu *qos_map;
 + 
-+ 	return 0;
++-	struct airtime_info airtime[IEEE80211_NUM_ACS];
++-
++ 	struct work_struct csa_finalize_work;
++ 	bool csa_block_tx; /* write-protected by sdata_lock and local->mtx */
++ 	struct cfg80211_chan_def csa_chandef;
++@@ -1185,44 +1187,6 @@ enum mac80211_scan_state {
++ 	SCAN_ABORT,
++ };
++ 
++-/**
++- * struct airtime_sched_info - state used for airtime scheduling and AQL
++- *
++- * @lock: spinlock that protects all the fields in this struct
++- * @active_txqs: rbtree of currently backlogged queues, sorted by virtual time
++- * @schedule_pos: the current position maintained while a driver walks the tree
++- *                with ieee80211_next_txq()
++- * @active_list: list of struct airtime_info structs that were active within
++- *               the last AIRTIME_ACTIVE_DURATION (100 ms), used to compute
++- *               weight_sum
++- * @last_weight_update: used for rate limiting walking active_list
++- * @last_schedule_time: tracks the last time a transmission was scheduled; used
++- *                      for catching up v_t if no stations are eligible for
++- *                      transmission.
++- * @v_t: global virtual time; queues with v_t < this are eligible for
++- *       transmission
++- * @weight_sum: total sum of all active stations used for dividing airtime
++- * @weight_sum_reciprocal: reciprocal of weight_sum (to avoid divisions in fast
++- *                         path - see comment above
++- *                         IEEE80211_RECIPROCAL_DIVISOR_64)
++- * @aql_txq_limit_low: AQL limit when total outstanding airtime
++- *                     is < IEEE80211_AQL_THRESHOLD
++- * @aql_txq_limit_high: AQL limit when total outstanding airtime
++- *                      is > IEEE80211_AQL_THRESHOLD
++- */
++-struct airtime_sched_info {
++-	spinlock_t lock;
++-	struct rb_root_cached active_txqs;
++-	struct rb_node *schedule_pos;
++-	struct list_head active_list;
++-	u64 last_weight_update;
++-	u64 last_schedule_activity;
++-	u64 v_t;
++-	u64 weight_sum;
++-	u64 weight_sum_reciprocal;
++-	u32 aql_txq_limit_low;
++-	u32 aql_txq_limit_high;
++-};
++ DECLARE_STATIC_KEY_FALSE(aql_disable);
++ 
++ struct ieee80211_local {
++@@ -1236,8 +1200,13 @@ struct ieee80211_local {
++ 	struct codel_params cparams;
++ 
++ 	/* protects active_txqs and txqi->schedule_order */
++-	struct airtime_sched_info airtime[IEEE80211_NUM_ACS];
+++	spinlock_t active_txq_lock[IEEE80211_NUM_ACS];
+++	struct list_head active_txqs[IEEE80211_NUM_ACS];
+++	u16 schedule_round[IEEE80211_NUM_ACS];
+++
++ 	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;
++ 
++@@ -1654,125 +1623,6 @@ static inline bool txq_has_queue(struct
++ 	return !(skb_queue_empty(&txqi->frags) && !txqi->tin.backlog_packets);
 + }
 + 
-+-void cfg80211_stop_offchan_radar_detection(struct wireless_dev *wdev)
-++void cfg80211_stop_background_radar_detection(struct wireless_dev *wdev)
++-static inline struct airtime_info *to_airtime_info(struct ieee80211_txq *txq)
++-{
++-	struct ieee80211_sub_if_data *sdata;
++-	struct sta_info *sta;
++-
++-	if (txq->sta) {
++-		sta = container_of(txq->sta, struct sta_info, sta);
++-		return &sta->airtime[txq->ac];
++-	}
++-
++-	sdata = vif_to_sdata(txq->vif);
++-	return &sdata->airtime[txq->ac];
++-}
++-
++-/* To avoid divisions in the fast path, we keep pre-computed reciprocals for
++- * airtime weight calculations. There are two different weights to keep track
++- * of: The per-station weight and the sum of weights per phy.
++- *
++- * For the per-station weights (kept in airtime_info below), we use 32-bit
++- * reciprocals with a devisor of 2^19. This lets us keep the multiplications and
++- * divisions for the station weights as 32-bit operations at the cost of a bit
++- * of rounding error for high weights; but the choice of divisor keeps rounding
++- * errors <10% for weights <2^15, assuming no more than 8ms of airtime is
++- * reported at a time.
++- *
++- * For the per-phy sum of weights the values can get higher, so we use 64-bit
++- * operations for those with a 32-bit divisor, which should avoid any
++- * significant rounding errors.
++- */
++-#define IEEE80211_RECIPROCAL_DIVISOR_64 0x100000000ULL
++-#define IEEE80211_RECIPROCAL_SHIFT_64 32
++-#define IEEE80211_RECIPROCAL_DIVISOR_32 0x80000U
++-#define IEEE80211_RECIPROCAL_SHIFT_32 19
++-
++-static inline void airtime_weight_set(struct airtime_info *air_info, u16 weight)
++-{
++-	if (air_info->weight == weight)
++-		return;
++-
++-	air_info->weight = weight;
++-	if (weight) {
++-		air_info->weight_reciprocal =
++-			IEEE80211_RECIPROCAL_DIVISOR_32 / weight;
++-	} else {
++-		air_info->weight_reciprocal = 0;
++-	}
++-}
++-
++-static inline void airtime_weight_sum_set(struct airtime_sched_info *air_sched,
++-					  int weight_sum)
++-{
++-	if (air_sched->weight_sum == weight_sum)
++-		return;
++-
++-	air_sched->weight_sum = weight_sum;
++-	if (air_sched->weight_sum) {
++-		air_sched->weight_sum_reciprocal = IEEE80211_RECIPROCAL_DIVISOR_64;
++-		do_div(air_sched->weight_sum_reciprocal, air_sched->weight_sum);
++-	} else {
++-		air_sched->weight_sum_reciprocal = 0;
++-	}
++-}
++-
++-/* A problem when trying to enforce airtime fairness is that we want to divide
++- * the airtime between the currently *active* stations. However, basing this on
++- * the instantaneous queue state of stations doesn't work, as queues tend to
++- * oscillate very quickly between empty and occupied, leading to the scheduler
++- * thinking only a single station is active when deciding whether to allow
++- * transmission (and thus not throttling correctly).
++- *
++- * To fix this we use a timer-based notion of activity: a station is considered
++- * active if it has been scheduled within the last 100 ms; we keep a separate
++- * list of all the stations considered active in this manner, and lazily update
++- * the total weight of active stations from this list (filtering the stations in
++- * the list by their 'last active' time).
++- *
++- * We add one additional safeguard to guard against stations that manage to get
++- * scheduled every 100 ms but don't transmit a lot of data, and thus don't use
++- * up any airtime. Such stations would be able to get priority for an extended
++- * period of time if they do start transmitting at full capacity again, and so
++- * we add an explicit maximum for how far behind a station is allowed to fall in
++- * the virtual airtime domain. This limit is set to a relatively high value of
++- * 20 ms because the main mechanism for catching up idle stations is the active
++- * state as described above; i.e., the hard limit should only be hit in
++- * pathological cases.
++- */
++-#define AIRTIME_ACTIVE_DURATION (100 * NSEC_PER_MSEC)
++-#define AIRTIME_MAX_BEHIND 20000 /* 20 ms */
++-
++-static inline bool airtime_is_active(struct airtime_info *air_info, u64 now)
++-{
++-	return air_info->last_scheduled >= now - AIRTIME_ACTIVE_DURATION;
++-}
++-
++-static inline void airtime_set_active(struct airtime_sched_info *air_sched,
++-				      struct airtime_info *air_info, u64 now)
++-{
++-	air_info->last_scheduled = now;
++-	air_sched->last_schedule_activity = now;
++-	list_move_tail(&air_info->list, &air_sched->active_list);
++-}
++-
++-static inline bool airtime_catchup_v_t(struct airtime_sched_info *air_sched,
++-				       u64 v_t, u64 now)
++-{
++-	air_sched->v_t = v_t;
++-	return true;
++-}
++-
++-static inline void init_airtime_info(struct airtime_info *air_info,
++-				     struct airtime_sched_info *air_sched)
++-{
++-	atomic_set(&air_info->aql_tx_pending, 0);
++-	air_info->aql_limit_low = air_sched->aql_txq_limit_low;
++-	air_info->aql_limit_high = air_sched->aql_txq_limit_high;
++-	airtime_weight_set(air_info, IEEE80211_DEFAULT_AIRTIME_WEIGHT);
++-	INIT_LIST_HEAD(&air_info->list);
++-}
++-
++ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
 + {
-+ 	struct wiphy *wiphy = wdev->wiphy;
-+ 	struct cfg80211_registered_device *rdev = wiphy_to_rdev(wiphy);
-+ 
-+ 	lockdep_assert_wiphy(wiphy);
-+ 
-+-	if (wdev != rdev->offchan_radar_wdev)
-++	if (wdev != rdev->background_radar_wdev)
-+ 		return;
-+ 
-+-	rdev_set_radar_offchan(rdev, NULL);
-+-	rdev->offchan_radar_wdev = NULL; /* Release offchain ownership */
-++	rdev_set_radar_background(rdev, NULL);
-++	rdev->background_radar_wdev = NULL; /* Release offchain ownership */
++ 	return ether_addr_equal(raddr, addr) ||
++@@ -2018,14 +1868,6 @@ int ieee80211_tx_control_port(struct wip
++ 			      u64 *cookie);
++ int ieee80211_probe_mesh_link(struct wiphy *wiphy, struct net_device *dev,
++ 			      const u8 *buf, size_t len);
++-void ieee80211_resort_txq(struct ieee80211_hw *hw,
++-			  struct ieee80211_txq *txq);
++-void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
++-			      struct ieee80211_txq *txq,
++-			      bool purge);
++-void ieee80211_update_airtime_weight(struct ieee80211_local *local,
++-				     struct airtime_sched_info *air_sched,
++-				     u64 now, bool force);
++ 
++ /* HT */
++ void ieee80211_apply_htcap_overrides(struct ieee80211_sub_if_data *sdata,
++--- a/net/mac80211/iface.c
+++++ b/net/mac80211/iface.c
++@@ -2192,9 +2192,6 @@ int ieee80211_if_add(struct ieee80211_lo
++ 		}
++ 	}
 + 
-+-	__cfg80211_offchan_cac_event(rdev, wdev, &rdev->offchan_radar_chandef,
-+-				     NL80211_RADAR_CAC_ABORTED);
-++	__cfg80211_background_cac_event(rdev, wdev,
-++					&rdev->background_radar_chandef,
-++					NL80211_RADAR_CAC_ABORTED);
-+ }
-+--- a/net/wireless/nl80211.c
-++++ b/net/wireless/nl80211.c
-+@@ -796,7 +796,7 @@ static const struct nla_policy nl80211_p
-+ 	[NL80211_ATTR_MBSSID_CONFIG] =
-+ 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
-+ 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
-+-	[NL80211_ATTR_RADAR_OFFCHAN] = { .type = NLA_FLAG },
-++	[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
-+ };
++-	for (i = 0; i < IEEE80211_NUM_ACS; i++)
++-		init_airtime_info(&sdata->airtime[i], &local->airtime[i]);
++-
++ 	ieee80211_set_default_queues(sdata);
 + 
-+ /* policy for the key attributes */
-+@@ -9291,9 +9291,9 @@ static int nl80211_start_radar_detection
-+ 		goto unlock;
++ 	sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
++--- a/net/mac80211/main.c
+++++ b/net/mac80211/main.c
++@@ -707,13 +707,10 @@ struct ieee80211_hw *ieee80211_alloc_hw_
++ 	spin_lock_init(&local->queue_stop_reason_lock);
++ 
++ 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
++-		struct airtime_sched_info *air_sched = &local->airtime[i];
++-
++-		air_sched->active_txqs = RB_ROOT_CACHED;
++-		INIT_LIST_HEAD(&air_sched->active_list);
++-		spin_lock_init(&air_sched->lock);
++-		air_sched->aql_txq_limit_low = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
++-		air_sched->aql_txq_limit_high =
+++		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;
 + 	}
 + 
-+-	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_OFFCHAN])) {
-+-		err = cfg80211_start_offchan_radar_detection(rdev, wdev,
-+-							     &chandef);
-++	if (nla_get_flag(info->attrs[NL80211_ATTR_RADAR_BACKGROUND])) {
-++		err = cfg80211_start_background_radar_detection(rdev, wdev,
-++								&chandef);
-+ 		goto unlock;
++--- a/net/mac80211/rx.c
+++++ b/net/mac80211/rx.c
++@@ -1583,8 +1583,12 @@ static void sta_ps_start(struct sta_info
++ 
++ 	for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
++ 		struct ieee80211_txq *txq = sta->sta.txq[tid];
+++		struct txq_info *txqi = to_txq_info(txq);
++ 
++-		ieee80211_unschedule_txq(&local->hw, txq, false);
+++		spin_lock(&local->active_txq_lock[txq->ac]);
+++		if (!list_empty(&txqi->schedule_order))
+++			list_del_init(&txqi->schedule_order);
+++		spin_unlock(&local->active_txq_lock[txq->ac]);
++ 
++ 		if (txq_has_queue(txq))
++ 			set_bit(tid, &sta->txq_buffered_tids);
++--- a/net/mac80211/sta_info.c
+++++ b/net/mac80211/sta_info.c
++@@ -426,11 +426,15 @@ struct sta_info *sta_info_alloc(struct i
++ 	if (sta_prepare_rate_control(local, sta, gfp))
++ 		goto free_txq;
++ 
+++	sta->airtime_weight = IEEE80211_DEFAULT_AIRTIME_WEIGHT;
++ 
++ 	for (i = 0; i < IEEE80211_NUM_ACS; i++) {
++ 		skb_queue_head_init(&sta->ps_tx_buf[i]);
++ 		skb_queue_head_init(&sta->tx_filtered[i]);
++-		init_airtime_info(&sta->airtime[i], &local->airtime[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];
 + 	}
 + 
-+--- a/net/wireless/rdev-ops.h
-++++ b/net/wireless/rdev-ops.h
-+@@ -1382,17 +1382,17 @@ static inline int rdev_color_change(stru
++ 	for (i = 0; i < IEEE80211_NUM_TIDS; i++)
++@@ -1889,59 +1893,24 @@ void ieee80211_sta_set_buffered(struct i
 + }
++ EXPORT_SYMBOL(ieee80211_sta_set_buffered);
 + 
-+ static inline int
-+-rdev_set_radar_offchan(struct cfg80211_registered_device *rdev,
-+-		       struct cfg80211_chan_def *chandef)
-++rdev_set_radar_background(struct cfg80211_registered_device *rdev,
-++			  struct cfg80211_chan_def *chandef)
++-void ieee80211_register_airtime(struct ieee80211_txq *txq,
++-				u32 tx_airtime, u32 rx_airtime)
+++void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
+++				    u32 tx_airtime, u32 rx_airtime)
 + {
-+ 	struct wiphy *wiphy = &rdev->wiphy;
-+ 	int ret;
++-	struct ieee80211_sub_if_data *sdata = vif_to_sdata(txq->vif);
++-	struct ieee80211_local *local = sdata->local;
++-	u64 weight_sum, weight_sum_reciprocal;
++-	struct airtime_sched_info *air_sched;
++-	struct airtime_info *air_info;
+++	struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
+++	struct ieee80211_local *local = sta->sdata->local;
+++	u8 ac = ieee80211_ac_from_tid(tid);
++ 	u32 airtime = 0;
++ 
++-	air_sched = &local->airtime[txq->ac];
++-	air_info = to_airtime_info(txq);
++-
++-	if (local->airtime_flags & AIRTIME_USE_TX)
+++	if (sta->local->airtime_flags & AIRTIME_USE_TX)
++ 		airtime += tx_airtime;
++-	if (local->airtime_flags & AIRTIME_USE_RX)
+++	if (sta->local->airtime_flags & AIRTIME_USE_RX)
++ 		airtime += rx_airtime;
++ 
++-	/* Weights scale so the unit weight is 256 */
++-	airtime <<= 8;
++-
++-	spin_lock_bh(&air_sched->lock);
++-
++-	air_info->tx_airtime += tx_airtime;
++-	air_info->rx_airtime += rx_airtime;
++-
++-	if (air_sched->weight_sum) {
++-		weight_sum = air_sched->weight_sum;
++-		weight_sum_reciprocal = air_sched->weight_sum_reciprocal;
++-	} else {
++-		weight_sum = air_info->weight;
++-		weight_sum_reciprocal = air_info->weight_reciprocal;
++-	}
++-
++-	/* Round the calculation of global vt */
++-	air_sched->v_t += (u64)((airtime + (weight_sum >> 1)) *
++-				weight_sum_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_64;
++-	air_info->v_t += (u32)((airtime + (air_info->weight >> 1)) *
++-			       air_info->weight_reciprocal) >> IEEE80211_RECIPROCAL_SHIFT_32;
++-	ieee80211_resort_txq(&local->hw, txq);
++-
++-	spin_unlock_bh(&air_sched->lock);
++-}
++-
++-void ieee80211_sta_register_airtime(struct ieee80211_sta *pubsta, u8 tid,
++-				    u32 tx_airtime, u32 rx_airtime)
++-{
++-	struct ieee80211_txq *txq = pubsta->txq[tid];
++-
++-	if (!txq)
++-		return;
++-
++-	ieee80211_register_airtime(txq, tx_airtime, rx_airtime);
+++	spin_lock_bh(&local->active_txq_lock[ac]);
+++	sta->airtime[ac].tx_airtime += tx_airtime;
+++	sta->airtime[ac].rx_airtime += rx_airtime;
+++	sta->airtime[ac].deficit -= airtime;
+++	spin_unlock_bh(&local->active_txq_lock[ac]);
++ }
++ EXPORT_SYMBOL(ieee80211_sta_register_airtime);
 + 
-+-	if (!rdev->ops->set_radar_offchan)
-++	if (!rdev->ops->set_radar_background)
-+ 		return -EOPNOTSUPP;
++@@ -2385,7 +2354,7 @@ void sta_set_sinfo(struct sta_info *sta,
++ 	}
 + 
-+-	trace_rdev_set_radar_offchan(wiphy, chandef);
-+-	ret = rdev->ops->set_radar_offchan(wiphy, chandef);
-++	trace_rdev_set_radar_background(wiphy, chandef);
-++	ret = rdev->ops->set_radar_background(wiphy, chandef);
-+ 	trace_rdev_return_int(wiphy, ret);
++ 	if (!(sinfo->filled & BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT))) {
++-		sinfo->airtime_weight = sta->airtime[0].weight;
+++		sinfo->airtime_weight = sta->airtime_weight;
++ 		sinfo->filled |= BIT_ULL(NL80211_STA_INFO_AIRTIME_WEIGHT);
++ 	}
 + 
-+ 	return ret;
-+--- a/net/wireless/trace.h
-++++ b/net/wireless/trace.h
-+@@ -3646,7 +3646,7 @@ TRACE_EVENT(cfg80211_bss_color_notify,
-+ 		  __entry->color_bitmap)
-+ );
++--- a/net/mac80211/sta_info.h
+++++ b/net/mac80211/sta_info.h
++@@ -135,25 +135,18 @@ enum ieee80211_agg_stop_reason {
++ #define AIRTIME_USE_TX		BIT(0)
++ #define AIRTIME_USE_RX		BIT(1)
 + 
-+-TRACE_EVENT(rdev_set_radar_offchan,
-++TRACE_EVENT(rdev_set_radar_background,
-+ 	TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
++-
++ struct airtime_info {
++ 	u64 rx_airtime;
++ 	u64 tx_airtime;
++-	u64 v_t;
++-	u64 last_scheduled;
++-	struct list_head list;
+++	s64 deficit;
++ 	atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
++ 	u32 aql_limit_low;
++ 	u32 aql_limit_high;
++-	u32 weight_reciprocal;
++-	u16 weight;
++ };
 + 
-+ 	TP_ARGS(wiphy, chandef),
-diff --git a/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch
-new file mode 100644
-index 0000000000..a135e3d1b5
---- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/323-mac80211-MBSSID-support-in-interface-handling.patch
-@@ -0,0 +1,144 @@
-+From: John Crispin <john@phrozen.org>
-+Date: Wed, 15 Sep 2021 19:54:35 -0700
-+Subject: [PATCH] mac80211: MBSSID support in interface handling
-+
-+Configure multiple BSSID and enhanced multi-BSSID advertisement (EMA)
-+parameters in mac80211 for AP mode.
-+
-+For each interface, 'mbssid_tx_vif' points to the transmitting interface of
-+the MBSSID set. The pointer is set to NULL if MBSSID is disabled.
-+
-+Function ieee80211_stop() is modified to always bring down all the
-+non-transmitting interfaces first and the transmitting interface last.
-+
-+Signed-off-by: John Crispin <john@phrozen.org>
-+Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
-+Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
-+Link: https://lore.kernel.org/r/20210916025437.29138-3-alokad@codeaurora.org
-+[slightly change logic to be more obvious]
-+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-+---
-+
-+--- a/include/net/mac80211.h
-++++ b/include/net/mac80211.h
-+@@ -1719,6 +1719,7 @@ enum ieee80211_offload_flags {
-+  *	write-protected by sdata_lock and local->mtx so holding either is fine
-+  *	for read access.
-+  * @color_change_color: the bss color that will be used after the change.
-++ * @mbssid_tx_vif: Pointer to the transmitting interface if MBSSID is enabled.
-+  */
-+ struct ieee80211_vif {
-+ 	enum nl80211_iftype type;
-+@@ -1750,6 +1751,8 @@ struct ieee80211_vif {
-+ 	bool color_change_active;
-+ 	u8 color_change_color;
++ void ieee80211_sta_update_pending_airtime(struct ieee80211_local *local,
++ 					  struct sta_info *sta, u8 ac,
++ 					  u16 tx_airtime, bool tx_completed);
++-void ieee80211_register_airtime(struct ieee80211_txq *txq,
++-				u32 tx_airtime, u32 rx_airtime);
 + 
-++	struct ieee80211_vif *mbssid_tx_vif;
-++
-+ 	/* must be last */
-+ 	u8 drv_priv[] __aligned(sizeof(void *));
-+ };
-+--- a/net/mac80211/cfg.c
-++++ b/net/mac80211/cfg.c
-+@@ -112,6 +112,36 @@ static int ieee80211_set_mon_options(str
-+ 	return 0;
-+ }
++ struct sta_info;
 + 
-++static int ieee80211_set_ap_mbssid_options(struct ieee80211_sub_if_data *sdata,
-++					   struct cfg80211_mbssid_config params)
-++{
-++	struct ieee80211_sub_if_data *tx_sdata;
-++
-++	sdata->vif.mbssid_tx_vif = NULL;
-++	sdata->vif.bss_conf.bssid_index = 0;
-++	sdata->vif.bss_conf.nontransmitted = false;
-++	sdata->vif.bss_conf.ema_ap = false;
-++
-++	if (sdata->vif.type != NL80211_IFTYPE_AP || !params.tx_wdev)
-++		return -EINVAL;
-++
-++	tx_sdata = IEEE80211_WDEV_TO_SUB_IF(params.tx_wdev);
-++	if (!tx_sdata)
-++		return -EINVAL;
-++
-++	if (tx_sdata == sdata) {
-++		sdata->vif.mbssid_tx_vif = &sdata->vif;
-++	} else {
-++		sdata->vif.mbssid_tx_vif = &tx_sdata->vif;
-++		sdata->vif.bss_conf.nontransmitted = true;
-++		sdata->vif.bss_conf.bssid_index = params.index;
-++	}
-++	if (params.ema)
-++		sdata->vif.bss_conf.ema_ap = true;
-++
-++	return 0;
-++}
-++
-+ static struct wireless_dev *ieee80211_add_iface(struct wiphy *wiphy,
-+ 						const char *name,
-+ 						unsigned char name_assign_type,
-+@@ -1107,6 +1137,14 @@ static int ieee80211_start_ap(struct wip
-+ 			changed |= BSS_CHANGED_HE_BSS_COLOR;
++@@ -523,6 +516,7 @@ struct ieee80211_fragment_cache {
++  * @tid_seq: per-TID sequence numbers for sending to this STA
++  * @airtime: per-AC struct airtime_info describing airtime statistics for this
++  *	station
+++ * @airtime_weight: station weight for airtime fairness calculation purposes
++  * @ampdu_mlme: A-MPDU state machine state
++  * @mesh: mesh STA information
++  * @debugfs_dir: debug filesystem directory dentry
++@@ -653,6 +647,7 @@ struct sta_info {
++ 	u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
++ 
++ 	struct airtime_info airtime[IEEE80211_NUM_ACS];
+++	u16 airtime_weight;
++ 
++ 	/*
++ 	 * Aggregation information, locked with lock.
++--- a/net/mac80211/status.c
+++++ b/net/mac80211/status.c
++@@ -983,25 +983,6 @@ static void __ieee80211_tx_status(struct
++ 		if (!(info->flags & IEEE80211_TX_CTL_INJECTED) && acked)
++ 			ieee80211_frame_acked(sta, skb);
++ 
++-	} else if (wiphy_ext_feature_isset(local->hw.wiphy,
++-					   NL80211_EXT_FEATURE_AIRTIME_FAIRNESS)) {
++-		struct ieee80211_sub_if_data *sdata;
++-		struct ieee80211_txq *txq;
++-		u32 airtime;
++-
++-		/* Account airtime to multicast queue */
++-		sdata = ieee80211_sdata_from_skb(local, skb);
++-
++-		if (sdata && (txq = sdata->vif.txq)) {
++-			airtime = info->status.tx_time ?:
++-				ieee80211_calc_expected_tx_airtime(hw,
++-								   &sdata->vif,
++-								   NULL,
++-								   skb->len,
++-								   false);
++-
++-			ieee80211_register_airtime(txq, airtime, 0);
++-		}
 + 	}
 + 
-++	if (sdata->vif.type == NL80211_IFTYPE_AP &&
-++	    params->mbssid_config.tx_wdev) {
-++		err = ieee80211_set_ap_mbssid_options(sdata,
-++						      params->mbssid_config);
-++		if (err)
-++			return err;
-++	}
-++
-+ 	mutex_lock(&local->mtx);
-+ 	err = ieee80211_vif_use_channel(sdata, &params->chandef,
-+ 					IEEE80211_CHANCTX_SHARED);
-+--- a/net/mac80211/iface.c
-++++ b/net/mac80211/iface.c
-+@@ -632,17 +632,46 @@ static void ieee80211_do_stop(struct iee
-+ 		ieee80211_add_virtual_monitor(local);
++ 	/* SNMP counters
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -18,7 +18,6 @@
++ #include <linux/bitmap.h>
++ #include <linux/rcupdate.h>
++ #include <linux/export.h>
++-#include <linux/timekeeping.h>
++ #include <net/net_namespace.h>
++ #include <net/ieee80211_radiotap.h>
++ #include <net/cfg80211.h>
++@@ -1480,7 +1479,7 @@ void ieee80211_txq_init(struct ieee80211
++ 	codel_vars_init(&txqi->def_cvars);
++ 	codel_stats_init(&txqi->cstats);
++ 	__skb_queue_head_init(&txqi->frags);
++-	RB_CLEAR_NODE(&txqi->schedule_order);
+++	INIT_LIST_HEAD(&txqi->schedule_order);
++ 
++ 	txqi->txq.vif = &sdata->vif;
++ 
++@@ -1524,7 +1523,9 @@ void ieee80211_txq_purge(struct ieee8021
++ 	ieee80211_purge_tx_queue(&local->hw, &txqi->frags);
++ 	spin_unlock_bh(&fq->lock);
++ 
++-	ieee80211_unschedule_txq(&local->hw, &txqi->txq, true);
+++	spin_lock_bh(&local->active_txq_lock[txqi->txq.ac]);
+++	list_del_init(&txqi->schedule_order);
+++	spin_unlock_bh(&local->active_txq_lock[txqi->txq.ac]);
 + }
 + 
-++static void ieee80211_stop_mbssid(struct ieee80211_sub_if_data *sdata)
-++{
-++	struct ieee80211_sub_if_data *tx_sdata, *non_tx_sdata, *tmp_sdata;
-++	struct ieee80211_vif *tx_vif = sdata->vif.mbssid_tx_vif;
-++
-++	if (!tx_vif)
-++		return;
-++
-++	tx_sdata = vif_to_sdata(tx_vif);
-++	sdata->vif.mbssid_tx_vif = NULL;
-++
-++	list_for_each_entry_safe(non_tx_sdata, tmp_sdata,
-++				 &tx_sdata->local->interfaces, list) {
-++		if (non_tx_sdata != sdata && non_tx_sdata != tx_sdata &&
-++		    non_tx_sdata->vif.mbssid_tx_vif == tx_vif &&
-++		    ieee80211_sdata_running(non_tx_sdata)) {
-++			non_tx_sdata->vif.mbssid_tx_vif = NULL;
-++			dev_close(non_tx_sdata->wdev.netdev);
-++		}
-++	}
-++
-++	if (sdata != tx_sdata && ieee80211_sdata_running(tx_sdata)) {
-++		tx_sdata->vif.mbssid_tx_vif = NULL;
-++		dev_close(tx_sdata->wdev.netdev);
-++	}
-++}
-++
-+ static int ieee80211_stop(struct net_device *dev)
++ void ieee80211_txq_set_params(struct ieee80211_local *local)
++@@ -3819,259 +3820,102 @@ EXPORT_SYMBOL(ieee80211_tx_dequeue);
++ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
 + {
-+ 	struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-+ 
-+-	/* close all dependent VLAN interfaces before locking wiphy */
-++	/* close dependent VLAN and MBSSID interfaces before locking wiphy */
-+ 	if (sdata->vif.type == NL80211_IFTYPE_AP) {
-+ 		struct ieee80211_sub_if_data *vlan, *tmpsdata;
-+ 
-+ 		list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
-+ 					 u.vlan.list)
-+ 			dev_close(vlan->dev);
-++
-++		ieee80211_stop_mbssid(sdata);
-+ 	}
++ 	struct ieee80211_local *local = hw_to_local(hw);
++-	struct airtime_sched_info *air_sched;
++-	u64 now = ktime_get_coarse_boottime_ns();
++ 	struct ieee80211_txq *ret = NULL;
++-	struct airtime_info *air_info;
++-	struct txq_info *txqi = NULL;
++-	struct rb_node *node;
++-	bool first = false;
+++	struct txq_info *txqi = NULL, *head = NULL;
+++	bool found_eligible_txq = false;
++ 
++-	air_sched = &local->airtime[ac];
++-	spin_lock_bh(&air_sched->lock);
+++	spin_lock_bh(&local->active_txq_lock[ac]);
++ 
++-	node = air_sched->schedule_pos;
++-
++-begin:
++-	if (!node) {
++-		node = rb_first_cached(&air_sched->active_txqs);
++-		first = true;
++-	} else {
++-		node = rb_next(node);
++-	}
++-
++-	if (!node)
++-		goto out;
++-
++-	txqi = container_of(node, struct txq_info, schedule_order);
++-	air_info = to_airtime_info(&txqi->txq);
++-
++-	if (air_info->v_t > air_sched->v_t &&
++-	    (!first || !airtime_catchup_v_t(air_sched, air_info->v_t, now)))
+++ begin:
+++	txqi = list_first_entry_or_null(&local->active_txqs[ac],
+++					struct txq_info,
+++					schedule_order);
+++	if (!txqi)
++ 		goto out;
 + 
-+ 	wiphy_lock(sdata->local->hw.wiphy);
-diff --git a/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
-new file mode 100644
-index 0000000000..fdbcce9450
---- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/324-mac80211-MBSSID-beacon-handling-in-AP-mode.patch
-@@ -0,0 +1,326 @@
-+From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Thu, 24 Feb 2022 12:54:58 +0100
-+Subject: [PATCH] mac80211: MBSSID beacon handling in AP mode
-+
-+Add new fields in struct beacon_data to store all MBSSID elements.
-+Generate a beacon template which includes all MBSSID elements.
-+Move CSA offset to reflect the MBSSID element length.
-+
-+Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
-+Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
-+Co-developed-by: John Crispin <john@phrozen.org>
-+Signed-off-by: John Crispin <john@phrozen.org>
-+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Tested-by: Money Wang <money.wang@mediatek.com>
-+Link: https://lore.kernel.org/r/5322db3c303f431adaf191ab31c45e151dde5465.1645702516.git.lorenzo@kernel.org
-+[small cleanups]
-+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
-+---
-+
-+--- a/include/net/mac80211.h
-++++ b/include/net/mac80211.h
-+@@ -4938,12 +4938,14 @@ void ieee80211_report_low_ack(struct iee
-+  * @cntdwn_counter_offs: array of IEEE80211_MAX_CNTDWN_COUNTERS_NUM offsets
-+  *	to countdown counters.  This array can contain zero values which
-+  *	should be ignored.
-++ * @mbssid_off: position of the multiple bssid element
-+  */
-+ struct ieee80211_mutable_offsets {
-+ 	u16 tim_offset;
-+ 	u16 tim_length;
++-	if (!ieee80211_txq_airtime_check(hw, &txqi->txq)) {
++-		first = false;
++-		goto begin;
++-	}
++-
++-	air_sched->schedule_pos = node;
++-	air_sched->last_schedule_activity = now;
++-	ret = &txqi->txq;
++-out:
++-	spin_unlock_bh(&air_sched->lock);
++-	return ret;
++-}
++-EXPORT_SYMBOL(ieee80211_next_txq);
++-
++-static void __ieee80211_insert_txq(struct rb_root_cached *root,
++-				   struct txq_info *txqi)
++-{
++-	struct rb_node **new = &root->rb_root.rb_node;
++-	struct airtime_info *old_air, *new_air;
++-	struct rb_node *parent = NULL;
++-	struct txq_info *__txqi;
++-	bool leftmost = true;
++-
++-	while (*new) {
++-		parent = *new;
++-		__txqi = rb_entry(parent, struct txq_info, schedule_order);
++-		old_air = to_airtime_info(&__txqi->txq);
++-		new_air = to_airtime_info(&txqi->txq);
++-
++-		if (new_air->v_t <= old_air->v_t) {
++-			new = &parent->rb_left;
++-		} else {
++-			new = &parent->rb_right;
++-			leftmost = false;
++-		}
+++	if (txqi == head) {
+++		if (!found_eligible_txq)
+++			goto out;
+++		else
+++			found_eligible_txq = false;
++ 	}
 + 
-+ 	u16 cntdwn_counter_offs[IEEE80211_MAX_CNTDWN_COUNTERS_NUM];
-++	u16 mbssid_off;
-+ };
++-	rb_link_node(&txqi->schedule_order, parent, new);
++-	rb_insert_color_cached(&txqi->schedule_order, root, leftmost);
++-}
++-
++-void ieee80211_resort_txq(struct ieee80211_hw *hw,
++-			  struct ieee80211_txq *txq)
++-{
++-	struct airtime_info *air_info = to_airtime_info(txq);
++-	struct ieee80211_local *local = hw_to_local(hw);
++-	struct txq_info *txqi = to_txq_info(txq);
++-	struct airtime_sched_info *air_sched;
++-
++-	air_sched = &local->airtime[txq->ac];
+++	if (!head)
+++		head = txqi;
 + 
-+ /**
-+--- a/net/mac80211/cfg.c
-++++ b/net/mac80211/cfg.c
-+@@ -989,11 +989,29 @@ static int ieee80211_set_ftm_responder_p
-+ 	return 0;
++-	lockdep_assert_held(&air_sched->lock);
++-
++-	if (!RB_EMPTY_NODE(&txqi->schedule_order)) {
++-		struct airtime_info *a_prev = NULL, *a_next = NULL;
++-		struct txq_info *t_prev, *t_next;
++-		struct rb_node *n_prev, *n_next;
+++	if (txqi->txq.sta) {
+++		struct sta_info *sta = container_of(txqi->txq.sta,
+++						    struct sta_info, sta);
+++		bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
+++		s64 deficit = sta->airtime[txqi->txq.ac].deficit;
++ 
++-		/* Erasing a node can cause an expensive rebalancing operation,
++-		 * so we check the previous and next nodes first and only remove
++-		 * and re-insert if the current node is not already in the
++-		 * correct position.
++-		 */
++-		if ((n_prev = rb_prev(&txqi->schedule_order)) != NULL) {
++-			t_prev = container_of(n_prev, struct txq_info,
++-					      schedule_order);
++-			a_prev = to_airtime_info(&t_prev->txq);
++-		}
+++		if (aql_check)
+++			found_eligible_txq = true;
++ 
++-		if ((n_next = rb_next(&txqi->schedule_order)) != NULL) {
++-			t_next = container_of(n_next, struct txq_info,
++-					      schedule_order);
++-			a_next = to_airtime_info(&t_next->txq);
+++		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;
++ 		}
++-
++-		if ((!a_prev || a_prev->v_t <= air_info->v_t) &&
++-		    (!a_next || a_next->v_t > air_info->v_t))
++-			return;
++-
++-		if (air_sched->schedule_pos == &txqi->schedule_order)
++-			air_sched->schedule_pos = n_prev;
++-
++-		rb_erase_cached(&txqi->schedule_order,
++-				&air_sched->active_txqs);
++-		RB_CLEAR_NODE(&txqi->schedule_order);
++-		__ieee80211_insert_txq(&air_sched->active_txqs, txqi);
++ 	}
++-}
++-
++-void ieee80211_update_airtime_weight(struct ieee80211_local *local,
++-				     struct airtime_sched_info *air_sched,
++-				     u64 now, bool force)
++-{
++-	struct airtime_info *air_info, *tmp;
++-	u64 weight_sum = 0;
++-
++-	if (unlikely(!now))
++-		now = ktime_get_coarse_boottime_ns();
++-
++-	lockdep_assert_held(&air_sched->lock);
++-
++-	if (!force && (air_sched->last_weight_update <
++-		       now - AIRTIME_ACTIVE_DURATION))
++-		return;
++-
++-	list_for_each_entry_safe(air_info, tmp,
++-				 &air_sched->active_list, list) {
++-		if (airtime_is_active(air_info, now))
++-			weight_sum += air_info->weight;
++-		else
++-			list_del_init(&air_info->list);
++-	}
++-	airtime_weight_sum_set(air_sched, weight_sum);
++-	air_sched->last_weight_update = now;
++-}
++ 
++-void ieee80211_schedule_txq(struct ieee80211_hw *hw,
++-			    struct ieee80211_txq *txq)
++-	__acquires(txq_lock) __releases(txq_lock)
++-{
++-	struct ieee80211_local *local = hw_to_local(hw);
++-	struct txq_info *txqi = to_txq_info(txq);
++-	struct airtime_sched_info *air_sched;
++-	u64 now = ktime_get_coarse_boottime_ns();
++-	struct airtime_info *air_info;
++-	u8 ac = txq->ac;
++-	bool was_active;
++ 
++-	air_sched = &local->airtime[ac];
++-	air_info = to_airtime_info(txq);
++-
++-	spin_lock_bh(&air_sched->lock);
++-	was_active = airtime_is_active(air_info, now);
++-	airtime_set_active(air_sched, air_info, now);
++-
++-	if (!RB_EMPTY_NODE(&txqi->schedule_order))
+++	if (txqi->schedule_round == local->schedule_round[ac])
++ 		goto out;
++ 
++-	/* If the station has been inactive for a while, catch up its v_t so it
++-	 * doesn't get indefinite priority; see comment above the definition of
++-	 * AIRTIME_MAX_BEHIND.
++-	 */
++-	if ((!was_active && air_info->v_t < air_sched->v_t) ||
++-	    air_info->v_t < air_sched->v_t - AIRTIME_MAX_BEHIND)
++-		air_info->v_t = air_sched->v_t;
++-
++-	ieee80211_update_airtime_weight(local, air_sched, now, !was_active);
++-	__ieee80211_insert_txq(&air_sched->active_txqs, txqi);
+++	list_del_init(&txqi->schedule_order);
+++	txqi->schedule_round = local->schedule_round[ac];
+++	ret = &txqi->txq;
++ 
++ out:
++-	spin_unlock_bh(&air_sched->lock);
++-}
++-EXPORT_SYMBOL(ieee80211_schedule_txq);
++-
++-static void __ieee80211_unschedule_txq(struct ieee80211_hw *hw,
++-				       struct ieee80211_txq *txq,
++-				       bool purge)
++-{
++-	struct ieee80211_local *local = hw_to_local(hw);
++-	struct txq_info *txqi = to_txq_info(txq);
++-	struct airtime_sched_info *air_sched;
++-	struct airtime_info *air_info;
++-
++-	air_sched = &local->airtime[txq->ac];
++-	air_info = to_airtime_info(&txqi->txq);
++-
++-	lockdep_assert_held(&air_sched->lock);
++-
++-	if (purge) {
++-		list_del_init(&air_info->list);
++-		ieee80211_update_airtime_weight(local, air_sched, 0, true);
++-	}
++-
++-	if (RB_EMPTY_NODE(&txqi->schedule_order))
++-		return;
++-
++-	if (air_sched->schedule_pos == &txqi->schedule_order)
++-		air_sched->schedule_pos = rb_prev(&txqi->schedule_order);
++-
++-	if (!purge)
++-		airtime_set_active(air_sched, air_info,
++-				   ktime_get_coarse_boottime_ns());
++-
++-	rb_erase_cached(&txqi->schedule_order,
++-			&air_sched->active_txqs);
++-	RB_CLEAR_NODE(&txqi->schedule_order);
+++	spin_unlock_bh(&local->active_txq_lock[ac]);
+++	return ret;
 + }
+++EXPORT_SYMBOL(ieee80211_next_txq);
 + 
-++static int
-++ieee80211_copy_mbssid_beacon(u8 *pos, struct cfg80211_mbssid_elems *dst,
-++			     struct cfg80211_mbssid_elems *src)
-++{
-++	int i, offset = 0;
-++
-++	for (i = 0; i < src->cnt; i++) {
-++		memcpy(pos + offset, src->elem[i].data, src->elem[i].len);
-++		dst->elem[i].len = src->elem[i].len;
-++		dst->elem[i].data = pos + offset;
-++		offset += dst->elem[i].len;
-++	}
-++	dst->cnt = src->cnt;
-++
-++	return offset;
-++}
-++
-+ static int ieee80211_assign_beacon(struct ieee80211_sub_if_data *sdata,
-+ 				   struct cfg80211_beacon_data *params,
-+ 				   const struct ieee80211_csa_settings *csa,
-+ 				   const struct ieee80211_color_change_settings *cca)
++-void ieee80211_unschedule_txq(struct ieee80211_hw *hw,
+++void __ieee80211_schedule_txq(struct ieee80211_hw *hw,
++ 			      struct ieee80211_txq *txq,
++-			      bool purge)
++-	__acquires(txq_lock) __releases(txq_lock)
++-{
++-	struct ieee80211_local *local = hw_to_local(hw);
++-
++-	spin_lock_bh(&local->airtime[txq->ac].lock);
++-	__ieee80211_unschedule_txq(hw, txq, purge);
++-	spin_unlock_bh(&local->airtime[txq->ac].lock);
++-}
++-
++-void ieee80211_return_txq(struct ieee80211_hw *hw,
++-			  struct ieee80211_txq *txq, bool force)
+++			      bool force)
 + {
-++	struct cfg80211_mbssid_elems *mbssid = NULL;
-+ 	struct beacon_data *new, *old;
-+ 	int new_head_len, new_tail_len;
-+ 	int size, err;
-+@@ -1021,6 +1039,17 @@ static int ieee80211_assign_beacon(struc
++ 	struct ieee80211_local *local = hw_to_local(hw);
++ 	struct txq_info *txqi = to_txq_info(txq);
++ 
++-	spin_lock_bh(&local->airtime[txq->ac].lock);
+++	spin_lock_bh(&local->active_txq_lock[txq->ac]);
++ 
++-	if (!RB_EMPTY_NODE(&txqi->schedule_order) && !force &&
++-	    !txq_has_queue(txq))
++-		__ieee80211_unschedule_txq(hw, txq, false);
+++	if (list_empty(&txqi->schedule_order) &&
+++	    (force || !skb_queue_empty(&txqi->frags) ||
+++	     txqi->tin.backlog_packets)) {
+++		/* If airtime accounting is active, always enqueue STAs at the
+++		 * head of the list to ensure that they only get moved to the
+++		 * back by the airtime DRR scheduler once they have a negative
+++		 * deficit. A station that already has a negative deficit will
+++		 * get immediately moved to the back of the list on the next
+++		 * call to ieee80211_next_txq().
+++		 */
+++		if (txqi->txq.sta && local->airtime_flags &&
+++		    wiphy_ext_feature_isset(local->hw.wiphy,
+++					    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
+++			list_add(&txqi->schedule_order,
+++				 &local->active_txqs[txq->ac]);
+++		else
+++			list_add_tail(&txqi->schedule_order,
+++				      &local->active_txqs[txq->ac]);
+++	}
 + 
-+ 	size = sizeof(*new) + new_head_len + new_tail_len;
++-	spin_unlock_bh(&local->airtime[txq->ac].lock);
+++	spin_unlock_bh(&local->active_txq_lock[txq->ac]);
++ }
++-EXPORT_SYMBOL(ieee80211_return_txq);
+++EXPORT_SYMBOL(__ieee80211_schedule_txq);
 + 
-++	/* new or old multiple BSSID elements? */
-++	if (params->mbssid_ies) {
-++		mbssid = params->mbssid_ies;
-++		size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
-++		size += ieee80211_get_mbssid_beacon_len(mbssid);
-++	} else if (old && old->mbssid_ies) {
-++		mbssid = old->mbssid_ies;
-++		size += struct_size(new->mbssid_ies, elem, mbssid->cnt);
-++		size += ieee80211_get_mbssid_beacon_len(mbssid);
-++	}
-++
-+ 	new = kzalloc(size, GFP_KERNEL);
-+ 	if (!new)
-+ 		return -ENOMEM;
-+@@ -1029,12 +1058,20 @@ static int ieee80211_assign_beacon(struc
++ DEFINE_STATIC_KEY_FALSE(aql_disable);
 + 
-+ 	/*
-+ 	 * pointers go into the block we allocated,
-+-	 * memory is | beacon_data | head | tail |
-++	 * memory is | beacon_data | head | tail | mbssid_ies
-+ 	 */
-+ 	new->head = ((u8 *) new) + sizeof(*new);
-+ 	new->tail = new->head + new_head_len;
-+ 	new->head_len = new_head_len;
-+ 	new->tail_len = new_tail_len;
-++	/* copy in optional mbssid_ies */
-++	if (mbssid) {
-++		u8 *pos = new->tail + new->tail_len;
-++
-++		new->mbssid_ies = (void *)pos;
-++		pos += struct_size(new->mbssid_ies, elem, mbssid->cnt);
-++		ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid);
-++	}
++ bool ieee80211_txq_airtime_check(struct ieee80211_hw *hw,
++ 				 struct ieee80211_txq *txq)
++ {
++-	struct airtime_info *air_info = to_airtime_info(txq);
+++	struct sta_info *sta;
++ 	struct ieee80211_local *local = hw_to_local(hw);
 + 
-+ 	if (csa) {
-+ 		new->cntdwn_current_counter = csa->count;
-+@@ -1332,8 +1369,11 @@ static int ieee80211_stop_ap(struct wiph
++ 	if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
++@@ -4086,12 +3930,15 @@ bool ieee80211_txq_airtime_check(struct
++ 	if (unlikely(txq->tid == IEEE80211_NUM_TIDS))
++ 		return true;
 + 
-+ 	mutex_unlock(&local->mtx);
++-	if (atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_low)
+++	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;
 + 
-+-	kfree(sdata->u.ap.next_beacon);
-+-	sdata->u.ap.next_beacon = NULL;
-++	if (sdata->u.ap.next_beacon) {
-++		kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++		kfree(sdata->u.ap.next_beacon);
-++		sdata->u.ap.next_beacon = NULL;
-++	}
++ 	if (atomic_read(&local->aql_total_pending_airtime) <
++ 	    local->aql_threshold &&
++-	    atomic_read(&air_info->aql_tx_pending) < air_info->aql_limit_high)
+++	    atomic_read(&sta->airtime[txq->ac].aql_tx_pending) <
+++	    sta->airtime[txq->ac].aql_limit_high)
++ 		return true;
 + 
-+ 	/* turn off carrier for this interface and dependent VLANs */
-+ 	list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
-+@@ -3126,12 +3166,24 @@ cfg80211_beacon_dup(struct cfg80211_beac
++ 	return false;
++@@ -4101,59 +3948,60 @@ EXPORT_SYMBOL(ieee80211_txq_airtime_chec
++ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
++ 				struct ieee80211_txq *txq)
++ {
++-	struct txq_info *first_txqi = NULL, *txqi = to_txq_info(txq);
++ 	struct ieee80211_local *local = hw_to_local(hw);
++-	struct airtime_sched_info *air_sched;
++-	struct airtime_info *air_info;
++-	struct rb_node *node = NULL;
++-	bool ret = false;
++-	u64 now;
++-
+++	struct txq_info *iter, *tmp, *txqi = to_txq_info(txq);
+++	struct sta_info *sta;
+++	u8 ac = txq->ac;
 + 
-+ 	len = beacon->head_len + beacon->tail_len + beacon->beacon_ies_len +
-+ 	      beacon->proberesp_ies_len + beacon->assocresp_ies_len +
-+-	      beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len;
-++	      beacon->probe_resp_len + beacon->lci_len + beacon->civicloc_len +
-++	      ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
++-	if (!ieee80211_txq_airtime_check(hw, txq))
++-		return false;
+++	spin_lock_bh(&local->active_txq_lock[ac]);
 + 
-+ 	new_beacon = kzalloc(sizeof(*new_beacon) + len, GFP_KERNEL);
-+ 	if (!new_beacon)
-+ 		return NULL;
++-	air_sched = &local->airtime[txq->ac];
++-	spin_lock_bh(&air_sched->lock);
+++	if (!txqi->txq.sta)
+++		goto out;
 + 
-++	if (beacon->mbssid_ies && beacon->mbssid_ies->cnt) {
-++		new_beacon->mbssid_ies =
-++			kzalloc(struct_size(new_beacon->mbssid_ies,
-++					    elem, beacon->mbssid_ies->cnt),
-++				GFP_KERNEL);
-++		if (!new_beacon->mbssid_ies) {
-++			kfree(new_beacon);
-++			return NULL;
-++		}
-++	}
-++
-+ 	pos = (u8 *)(new_beacon + 1);
-+ 	if (beacon->head_len) {
-+ 		new_beacon->head_len = beacon->head_len;
-+@@ -3169,6 +3221,10 @@ cfg80211_beacon_dup(struct cfg80211_beac
-+ 		memcpy(pos, beacon->probe_resp, beacon->probe_resp_len);
-+ 		pos += beacon->probe_resp_len;
-+ 	}
-++	if (beacon->mbssid_ies && beacon->mbssid_ies->cnt)
-++		pos += ieee80211_copy_mbssid_beacon(pos,
-++						    new_beacon->mbssid_ies,
-++						    beacon->mbssid_ies);
++-	if (RB_EMPTY_NODE(&txqi->schedule_order))
+++	if (list_empty(&txqi->schedule_order))
++ 		goto out;
 + 
-+ 	/* might copy -1, meaning no changes requested */
-+ 	new_beacon->ftm_responder = beacon->ftm_responder;
-+@@ -3206,8 +3262,11 @@ static int ieee80211_set_after_csa_beaco
-+ 	case NL80211_IFTYPE_AP:
-+ 		err = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
-+ 					      NULL, NULL);
-+-		kfree(sdata->u.ap.next_beacon);
-+-		sdata->u.ap.next_beacon = NULL;
-++		if (sdata->u.ap.next_beacon) {
-++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++			kfree(sdata->u.ap.next_beacon);
-++			sdata->u.ap.next_beacon = NULL;
-++		}
++-	now = ktime_get_coarse_boottime_ns();
+++	list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
+++				 schedule_order) {
+++		if (iter == txqi)
+++			break;
 + 
-+ 		if (err < 0)
-+ 			return err;
-+@@ -3362,8 +3421,12 @@ static int ieee80211_set_csa_beacon(stru
-+ 		if ((params->n_counter_offsets_beacon >
-+ 		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM) ||
-+ 		    (params->n_counter_offsets_presp >
-+-		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM))
-++		     IEEE80211_MAX_CNTDWN_COUNTERS_NUM)) {
-++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++			kfree(sdata->u.ap.next_beacon);
-++			sdata->u.ap.next_beacon = NULL;
-+ 			return -EINVAL;
++-	/* Like in ieee80211_next_txq(), make sure the first station in the
++-	 * scheduling order is eligible for transmission to avoid starvation.
++-	 */
++-	node = rb_first_cached(&air_sched->active_txqs);
++-	if (node) {
++-		first_txqi = container_of(node, struct txq_info,
++-					  schedule_order);
++-		air_info = to_airtime_info(&first_txqi->txq);
++-
++-		if (air_sched->v_t < air_info->v_t)
++-			airtime_catchup_v_t(air_sched, air_info->v_t, now);
+++		if (!iter->txq.sta) {
+++			list_move_tail(&iter->schedule_order,
+++				       &local->active_txqs[ac]);
+++			continue;
 ++		}
+++		sta = container_of(iter->txq.sta, struct sta_info, sta);
+++		if (sta->airtime[ac].deficit < 0)
+++			sta->airtime[ac].deficit += sta->airtime_weight;
+++		list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
++ 	}
 + 
-+ 		csa.counter_offsets_beacon = params->counter_offsets_beacon;
-+ 		csa.counter_offsets_presp = params->counter_offsets_presp;
-+@@ -3373,7 +3436,9 @@ static int ieee80211_set_csa_beacon(stru
++-	air_info = to_airtime_info(&txqi->txq);
++-	if (air_info->v_t <= air_sched->v_t) {
++-		air_sched->last_schedule_activity = now;
++-		ret = true;
++-	}
+++	sta = container_of(txqi->txq.sta, struct sta_info, sta);
+++	if (sta->airtime[ac].deficit >= 0)
+++		goto out;
+++
+++	sta->airtime[ac].deficit += sta->airtime_weight;
+++	list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
+++	spin_unlock_bh(&local->active_txq_lock[ac]);
 + 
-+ 		err = ieee80211_assign_beacon(sdata, &params->beacon_csa, &csa, NULL);
-+ 		if (err < 0) {
-++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
-+ 			kfree(sdata->u.ap.next_beacon);
-++			sdata->u.ap.next_beacon = NULL;
-+ 			return err;
-+ 		}
-+ 		*changed |= err;
-+@@ -3463,8 +3528,11 @@ static int ieee80211_set_csa_beacon(stru
-+ static void ieee80211_color_change_abort(struct ieee80211_sub_if_data  *sdata)
+++	return false;
++ out:
++-	spin_unlock_bh(&air_sched->lock);
++-	return ret;
+++	if (!list_empty(&txqi->schedule_order))
+++		list_del_init(&txqi->schedule_order);
+++	spin_unlock_bh(&local->active_txq_lock[ac]);
+++
+++	return true;
++ }
++ EXPORT_SYMBOL(ieee80211_txq_may_transmit);
++ 
++ void ieee80211_txq_schedule_start(struct ieee80211_hw *hw, u8 ac)
 + {
-+ 	sdata->vif.color_change_active = false;
-+-	kfree(sdata->u.ap.next_beacon);
-+-	sdata->u.ap.next_beacon = NULL;
-++	if (sdata->u.ap.next_beacon) {
-++		kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++		kfree(sdata->u.ap.next_beacon);
-++		sdata->u.ap.next_beacon = NULL;
-++	}
++ 	struct ieee80211_local *local = hw_to_local(hw);
++-	struct airtime_sched_info *air_sched = &local->airtime[ac];
++ 
++-	spin_lock_bh(&air_sched->lock);
++-	air_sched->schedule_pos = NULL;
++-	spin_unlock_bh(&air_sched->lock);
+++	spin_lock_bh(&local->active_txq_lock[ac]);
+++	local->schedule_round[ac]++;
+++	spin_unlock_bh(&local->active_txq_lock[ac]);
++ }
++ EXPORT_SYMBOL(ieee80211_txq_schedule_start);
 + 
-+ 	cfg80211_color_change_aborted_notify(sdata->dev);
+diff --git a/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch b/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch
+new file mode 100644
+index 0000000000..c006d3762a
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/331-mac80211-make-sta-airtime-deficit-field-s32-instead-.patch
+@@ -0,0 +1,52 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Mon, 20 Jun 2022 14:53:04 +0200
++Subject: [PATCH] mac80211: make sta airtime deficit field s32 instead of
++ s64
++
++32 bit is more than enough range for the airtime deficit
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/debugfs_sta.c
+++++ b/net/mac80211/debugfs_sta.c
++@@ -202,7 +202,7 @@ static ssize_t sta_airtime_read(struct f
++ 	size_t bufsz = 400;
++ 	char *buf = kzalloc(bufsz, GFP_KERNEL), *p = buf;
++ 	u64 rx_airtime = 0, tx_airtime = 0;
++-	s64 deficit[IEEE80211_NUM_ACS];
+++	s32 deficit[IEEE80211_NUM_ACS];
++ 	ssize_t rv;
++ 	int ac;
++ 
++@@ -219,7 +219,7 @@ static ssize_t sta_airtime_read(struct f
++ 
++ 	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",
+++		"Deficit: VO: %d us VI: %d us BE: %d us BK: %d us\n",
++ 		rx_airtime, tx_airtime, sta->airtime_weight,
++ 		deficit[0], deficit[1], deficit[2], deficit[3]);
++ 
++--- a/net/mac80211/sta_info.h
+++++ b/net/mac80211/sta_info.h
++@@ -138,7 +138,7 @@ enum ieee80211_agg_stop_reason {
++ struct airtime_info {
++ 	u64 rx_airtime;
++ 	u64 tx_airtime;
++-	s64 deficit;
+++	s32 deficit;
++ 	atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
++ 	u32 aql_limit_low;
++ 	u32 aql_limit_high;
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -3847,7 +3847,7 @@ struct ieee80211_txq *ieee80211_next_txq
++ 		struct sta_info *sta = container_of(txqi->txq.sta,
++ 						    struct sta_info, sta);
++ 		bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
++-		s64 deficit = sta->airtime[txqi->txq.ac].deficit;
+++		s32 deficit = sta->airtime[txqi->txq.ac].deficit;
++ 
++ 		if (aql_check)
++ 			found_eligible_txq = true;
+diff --git a/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch b/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch
+new file mode 100644
+index 0000000000..c214294603
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/332-mac80211-consider-aql_tx_pending-when-checking-airti.patch
+@@ -0,0 +1,48 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Mon, 20 Jun 2022 14:59:09 +0200
++Subject: [PATCH] mac80211: consider aql_tx_pending when checking airtime
++ deficit
++
++When queueing packets for a station, deficit only gets added once the packets
++have been transmitted, which could be much later. During that time, a lot of
++temporary unfairness could happen, which could lead to bursty behavior.
++Fix this by subtracting the aql_tx_pending when checking the deficit in tx
++scheduling.
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -3817,6 +3817,13 @@ out:
 + }
-+@@ -4202,8 +4270,11 @@ ieee80211_set_after_color_change_beacon(
-+ 
-+ 		ret = ieee80211_assign_beacon(sdata, sdata->u.ap.next_beacon,
-+ 					      NULL, NULL);
-+-		kfree(sdata->u.ap.next_beacon);
-+-		sdata->u.ap.next_beacon = NULL;
-++		if (sdata->u.ap.next_beacon) {
-++			kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++			kfree(sdata->u.ap.next_beacon);
-++			sdata->u.ap.next_beacon = NULL;
-++		}
++ EXPORT_SYMBOL(ieee80211_tx_dequeue);
 + 
-+ 		if (ret < 0)
-+ 			return ret;
-+@@ -4246,7 +4317,11 @@ ieee80211_set_color_change_beacon(struct
-+ 		err = ieee80211_assign_beacon(sdata, &params->beacon_color_change,
-+ 					      NULL, &color_change);
-+ 		if (err < 0) {
-+-			kfree(sdata->u.ap.next_beacon);
-++			if (sdata->u.ap.next_beacon) {
-++				kfree(sdata->u.ap.next_beacon->mbssid_ies);
-++				kfree(sdata->u.ap.next_beacon);
-++				sdata->u.ap.next_beacon = NULL;
-++			}
-+ 			return err;
+++static inline s32 ieee80211_sta_deficit(struct sta_info *sta, u8 ac)
+++{
+++	struct airtime_info *air_info = &sta->airtime[ac];
+++
+++	return air_info->deficit - atomic_read(&air_info->aql_tx_pending);
+++}
+++
++ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
++ {
++ 	struct ieee80211_local *local = hw_to_local(hw);
++@@ -3847,7 +3854,7 @@ struct ieee80211_txq *ieee80211_next_txq
++ 		struct sta_info *sta = container_of(txqi->txq.sta,
++ 						    struct sta_info, sta);
++ 		bool aql_check = ieee80211_txq_airtime_check(hw, &txqi->txq);
++-		s32 deficit = sta->airtime[txqi->txq.ac].deficit;
+++		s32 deficit = ieee80211_sta_deficit(sta, txqi->txq.ac);
++ 
++ 		if (aql_check)
++ 			found_eligible_txq = true;
++@@ -3972,7 +3979,7 @@ bool ieee80211_txq_may_transmit(struct i
++ 			continue;
 + 		}
-+ 		*changed |= err;
++ 		sta = container_of(iter->txq.sta, struct sta_info, sta);
++-		if (sta->airtime[ac].deficit < 0)
+++		if (ieee80211_sta_deficit(sta, ac) < 0)
++ 			sta->airtime[ac].deficit += sta->airtime_weight;
++ 		list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
++ 	}
+diff --git a/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch b/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch
+new file mode 100644
+index 0000000000..317e4f0653
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/333-mac80211-keep-recently-active-tx-queues-in-schedulin.patch
+@@ -0,0 +1,118 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Mon, 20 Jun 2022 20:52:50 +0200
++Subject: [PATCH] mac80211: keep recently active tx queues in scheduling
++ list
++
++This allows proper deficit accounting to ensure that they don't carry their
++deficit until the next time they become active
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
 +--- a/net/mac80211/ieee80211_i.h
 ++++ b/net/mac80211/ieee80211_i.h
-+@@ -261,6 +261,7 @@ struct beacon_data {
-+ 	struct ieee80211_meshconf_ie *meshconf;
-+ 	u16 cntdwn_counter_offsets[IEEE80211_MAX_CNTDWN_COUNTERS_NUM];
-+ 	u8 cntdwn_current_counter;
-++	struct cfg80211_mbssid_elems *mbssid_ies;
-+ 	struct rcu_head rcu_head;
-+ };
++@@ -83,6 +83,13 @@ extern const u8 ieee80211_ac_to_qos_mask
 + 
-+@@ -1083,6 +1084,20 @@ ieee80211_vif_get_shift(struct ieee80211
-+ 	return shift;
-+ }
++ #define IEEE80211_MAX_NAN_INSTANCE_ID 255
 + 
-++static inline int
-++ieee80211_get_mbssid_beacon_len(struct cfg80211_mbssid_elems *elems)
-++{
-++	int i, len = 0;
-++
-++	if (!elems)
-++		return 0;
-++
-++	for (i = 0; i < elems->cnt; i++)
-++		len += elems->elem[i].len;
 ++
-++	return len;
-++}
+++/*
+++ * Keep a station's queues on the active list for deficit accounting purposes
+++ * if it was active or queued during the last 100ms
+++ */
+++#define AIRTIME_ACTIVE_DURATION (HZ / 10)
 ++
-+ enum {
-+ 	IEEE80211_RX_MSG	= 1,
-+ 	IEEE80211_TX_STATUS_MSG	= 2,
++ struct ieee80211_bss {
++ 	u32 device_ts_beacon, device_ts_presp;
++ 
++--- a/net/mac80211/sta_info.h
+++++ b/net/mac80211/sta_info.h
++@@ -138,6 +138,7 @@ enum ieee80211_agg_stop_reason {
++ struct airtime_info {
++ 	u64 rx_airtime;
++ 	u64 tx_airtime;
+++	u32 last_active;
++ 	s32 deficit;
++ 	atomic_t aql_tx_pending; /* Estimated airtime for frames pending */
++ 	u32 aql_limit_low;
 +--- a/net/mac80211/tx.c
 ++++ b/net/mac80211/tx.c
-+@@ -5041,6 +5041,19 @@ ieee80211_beacon_get_finish(struct ieee8
-+ 		       IEEE80211_TX_CTL_FIRST_FRAGMENT;
++@@ -3824,6 +3824,36 @@ static inline s32 ieee80211_sta_deficit(
++ 	return air_info->deficit - atomic_read(&air_info->aql_tx_pending);
 + }
 + 
 ++static void
-++ieee80211_beacon_add_mbssid(struct sk_buff *skb, struct beacon_data *beacon)
+++ieee80211_txq_set_active(struct txq_info *txqi)
 ++{
-++	int i;
+++	struct sta_info *sta;
 ++
-++	if (!beacon->mbssid_ies)
+++	if (!txqi->txq.sta)
 ++		return;
 ++
-++	for (i = 0; i < beacon->mbssid_ies->cnt; i++)
-++		skb_put_data(skb, beacon->mbssid_ies->elem[i].data,
-++			     beacon->mbssid_ies->elem[i].len);
+++	sta = container_of(txqi->txq.sta, struct sta_info, sta);
+++	sta->airtime[txqi->txq.ac].last_active = (u32)jiffies;
 ++}
 ++
-+ static struct sk_buff *
-+ ieee80211_beacon_get_ap(struct ieee80211_hw *hw,
-+ 			struct ieee80211_vif *vif,
-+@@ -5054,6 +5067,7 @@ ieee80211_beacon_get_ap(struct ieee80211
-+ 	struct ieee80211_if_ap *ap = &sdata->u.ap;
-+ 	struct sk_buff *skb = NULL;
-+ 	u16 csa_off_base = 0;
-++	int mbssid_len;
-+ 
-+ 	if (beacon->cntdwn_counter_offsets[0]) {
-+ 		if (!is_template)
-+@@ -5063,11 +5077,12 @@ ieee80211_beacon_get_ap(struct ieee80211
+++static bool
+++ieee80211_txq_keep_active(struct txq_info *txqi)
+++{
+++	struct sta_info *sta;
+++	u32 diff;
+++
+++	if (!txqi->txq.sta)
+++		return false;
+++
+++	sta = container_of(txqi->txq.sta, struct sta_info, sta);
+++	if (ieee80211_sta_deficit(sta, txqi->txq.ac) >= 0)
+++		return false;
+++
+++	diff = (u32)jiffies - sta->airtime[txqi->txq.ac].last_active;
+++
+++	return diff <= AIRTIME_ACTIVE_DURATION;
+++}
+++
++ struct ieee80211_txq *ieee80211_next_txq(struct ieee80211_hw *hw, u8 ac)
++ {
++ 	struct ieee80211_local *local = hw_to_local(hw);
++@@ -3870,7 +3900,6 @@ struct ieee80211_txq *ieee80211_next_txq
++ 		}
 + 	}
 + 
-+ 	/* headroom, head length,
-+-	 * tail length and maximum TIM length
-++	 * tail length, maximum TIM length and multiple BSSID length
-+ 	 */
-++	mbssid_len = ieee80211_get_mbssid_beacon_len(beacon->mbssid_ies);
-+ 	skb = dev_alloc_skb(local->tx_headroom + beacon->head_len +
-+ 			    beacon->tail_len + 256 +
-+-			    local->hw.extra_beacon_tailroom);
-++			    local->hw.extra_beacon_tailroom + mbssid_len);
-+ 	if (!skb)
-+ 		return NULL;
-+ 
-+@@ -5081,6 +5096,11 @@ ieee80211_beacon_get_ap(struct ieee80211
-+ 		offs->tim_length = skb->len - beacon->head_len;
-+ 		offs->cntdwn_counter_offs[0] = beacon->cntdwn_counter_offsets[0];
++-
++ 	if (txqi->schedule_round == local->schedule_round[ac])
++ 		goto out;
 + 
-++		if (mbssid_len) {
-++			ieee80211_beacon_add_mbssid(skb, beacon);
-++			offs->mbssid_off = skb->len - mbssid_len;
-++		}
-++
-+ 		/* for AP the csa offsets are from tail */
-+ 		csa_off_base = skb->len;
++@@ -3890,12 +3919,13 @@ void __ieee80211_schedule_txq(struct iee
++ {
++ 	struct ieee80211_local *local = hw_to_local(hw);
++ 	struct txq_info *txqi = to_txq_info(txq);
+++	bool has_queue;
++ 
++ 	spin_lock_bh(&local->active_txq_lock[txq->ac]);
++ 
+++	has_queue = force || txq_has_queue(txq);
++ 	if (list_empty(&txqi->schedule_order) &&
++-	    (force || !skb_queue_empty(&txqi->frags) ||
++-	     txqi->tin.backlog_packets)) {
+++	    (has_queue || ieee80211_txq_keep_active(txqi))) {
++ 		/* If airtime accounting is active, always enqueue STAs at the
++ 		 * head of the list to ensure that they only get moved to the
++ 		 * back by the airtime DRR scheduler once they have a negative
++@@ -3903,7 +3933,7 @@ void __ieee80211_schedule_txq(struct iee
++ 		 * get immediately moved to the back of the list on the next
++ 		 * call to ieee80211_next_txq().
++ 		 */
++-		if (txqi->txq.sta && local->airtime_flags &&
+++		if (txqi->txq.sta && local->airtime_flags && has_queue &&
++ 		    wiphy_ext_feature_isset(local->hw.wiphy,
++ 					    NL80211_EXT_FEATURE_AIRTIME_FAIRNESS))
++ 			list_add(&txqi->schedule_order,
++@@ -3911,6 +3941,8 @@ void __ieee80211_schedule_txq(struct iee
++ 		else
++ 			list_add_tail(&txqi->schedule_order,
++ 				      &local->active_txqs[txq->ac]);
+++		if (has_queue)
+++			ieee80211_txq_set_active(txqi);
 + 	}
-diff --git a/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch
++ 
++ 	spin_unlock_bh(&local->active_txq_lock[txq->ac]);
+diff --git a/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch
 new file mode 100644
-index 0000000000..38b0de180e
+index 0000000000..42e1671ed6
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/325-mac80211-MBSSID-channel-switch.patch
-@@ -0,0 +1,52 @@
-+From: John Crispin <john@phrozen.org>
-+Date: Thu, 24 Feb 2022 12:54:59 +0100
-+Subject: [PATCH] mac80211: MBSSID channel switch
++++ b/package/kernel/mac80211/patches/subsys/334-mac80211-add-a-per-PHY-AQL-limit-to-improve-fairness.patch
+@@ -0,0 +1,131 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Mon, 20 Jun 2022 21:26:34 +0200
++Subject: [PATCH] mac80211: add a per-PHY AQL limit to improve fairness
 +
-+Trigger ieee80211_csa_finish() on the non-transmitting interfaces
-+when channel switch concludes on the transmitting interface.
++In order to maintain fairness, the amount of queueing needs to be limited
++beyond the simple per-station AQL budget, otherwise the driver can simply
++repeatedly do scheduling rounds until all queues that have not used their
++AQL budget become eligble.
 +
-+Co-developed-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Co-developed-by: Aloka Dixit <alokad@codeaurora.org>
-+Signed-off-by: Aloka Dixit <alokad@codeaurora.org>
-+Signed-off-by: John Crispin <john@phrozen.org>
-+Link: https://lore.kernel.org/r/6fde4d7f9fa387494f46a7aa4a584478dcda06f1.1645702516.git.lorenzo@kernel.org
-+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++To be conservative, use the high AQL limit for the first txq and add half
++of the low AQL for each subsequent queue.
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +---
 +
-+--- a/net/mac80211/cfg.c
-++++ b/net/mac80211/cfg.c
-+@@ -3247,9 +3247,31 @@ cfg80211_beacon_dup(struct cfg80211_beac
-+ void ieee80211_csa_finish(struct ieee80211_vif *vif)
-+ {
-+ 	struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
-++	struct ieee80211_local *local = sdata->local;
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -1216,6 +1216,7 @@ struct ieee80211_local {
++ 	u32 aql_txq_limit_high[IEEE80211_NUM_ACS];
++ 	u32 aql_threshold;
++ 	atomic_t aql_total_pending_airtime;
+++	atomic_t aql_ac_pending_airtime[IEEE80211_NUM_ACS];
++ 
++ 	const struct ieee80211_ops *ops;
++ 
++--- a/net/mac80211/main.c
+++++ b/net/mac80211/main.c
++@@ -712,6 +712,7 @@ struct ieee80211_hw *ieee80211_alloc_hw_
++ 		local->aql_txq_limit_low[i] = IEEE80211_DEFAULT_AQL_TXQ_LIMIT_L;
++ 		local->aql_txq_limit_high[i] =
++ 			IEEE80211_DEFAULT_AQL_TXQ_LIMIT_H;
+++		atomic_set(&local->aql_ac_pending_airtime[i], 0);
++ 	}
 + 
-+-	ieee80211_queue_work(&sdata->local->hw,
-+-			     &sdata->csa_finalize_work);
-++	rcu_read_lock();
++ 	local->airtime_flags = AIRTIME_USE_TX | AIRTIME_USE_RX;
++--- a/net/mac80211/sta_info.c
+++++ b/net/mac80211/sta_info.c
++@@ -1929,6 +1929,7 @@ void ieee80211_sta_update_pending_airtim
++ 				   &sta->airtime[ac].aql_tx_pending);
++ 
++ 		atomic_add(tx_airtime, &local->aql_total_pending_airtime);
+++		atomic_add(tx_airtime, &local->aql_ac_pending_airtime[ac]);
++ 		return;
++ 	}
++ 
++@@ -1940,14 +1941,17 @@ void ieee80211_sta_update_pending_airtim
++ 				       tx_pending, 0);
++ 	}
++ 
+++	atomic_sub(tx_airtime, &local->aql_total_pending_airtime);
++ 	tx_pending = atomic_sub_return(tx_airtime,
++-				       &local->aql_total_pending_airtime);
+++				       &local->aql_ac_pending_airtime[ac]);
++ 	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_airtime)) {
+++		atomic_cmpxchg(&local->aql_ac_pending_airtime[ac],
++ 			       tx_pending, 0);
+++		atomic_sub(tx_pending, &local->aql_total_pending_airtime);
+++	}
++ }
++ 
++ int sta_info_move_state(struct sta_info *sta,
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -3863,6 +3863,9 @@ struct ieee80211_txq *ieee80211_next_txq
++ 
++ 	spin_lock_bh(&local->active_txq_lock[ac]);
++ 
+++	if (!local->schedule_round[ac])
+++		goto out;
 ++
-++	if (vif->mbssid_tx_vif == vif) {
-++		/* Trigger ieee80211_csa_finish() on the non-transmitting
-++		 * interfaces when channel switch is received on
-++		 * transmitting interface
-++		 */
-++		struct ieee80211_sub_if_data *iter;
++  begin:
++ 	txqi = list_first_entry_or_null(&local->active_txqs[ac],
++ 					struct txq_info,
++@@ -3984,6 +3987,25 @@ bool ieee80211_txq_airtime_check(struct
++ }
++ EXPORT_SYMBOL(ieee80211_txq_airtime_check);
++ 
+++static bool
+++ieee80211_txq_schedule_airtime_check(struct ieee80211_local *local, u8 ac)
+++{
+++	unsigned int num_txq = 0;
+++	struct txq_info *txq;
+++	u32 aql_limit;
 ++
-++		list_for_each_entry_rcu(iter, &local->interfaces, list) {
-++			if (!ieee80211_sdata_running(iter))
-++				continue;
+++	if (!wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL))
+++		return true;
 ++
-++			if (iter == sdata || iter->vif.mbssid_tx_vif != vif)
-++				continue;
+++	list_for_each_entry(txq, &local->active_txqs[ac], schedule_order)
+++		num_txq++;
 ++
-++			ieee80211_queue_work(&iter->local->hw,
-++					     &iter->csa_finalize_work);
-++		}
+++	aql_limit = (num_txq - 1) * local->aql_txq_limit_low[ac] / 2 +
+++		    local->aql_txq_limit_high[ac];
+++
+++	return atomic_read(&local->aql_ac_pending_airtime[ac]) < aql_limit;
+++}
+++
++ bool ieee80211_txq_may_transmit(struct ieee80211_hw *hw,
++ 				struct ieee80211_txq *txq)
++ {
++@@ -4000,6 +4022,9 @@ bool ieee80211_txq_may_transmit(struct i
++ 	if (list_empty(&txqi->schedule_order))
++ 		goto out;
++ 
+++	if (!ieee80211_txq_schedule_airtime_check(local, ac))
+++		goto out;
+++
++ 	list_for_each_entry_safe(iter, tmp, &local->active_txqs[ac],
++ 				 schedule_order) {
++ 		if (iter == txqi)
++@@ -4039,7 +4064,15 @@ void ieee80211_txq_schedule_start(struct
++ 	struct ieee80211_local *local = hw_to_local(hw);
++ 
++ 	spin_lock_bh(&local->active_txq_lock[ac]);
++-	local->schedule_round[ac]++;
+++
+++	if (ieee80211_txq_schedule_airtime_check(local, ac)) {
+++		local->schedule_round[ac]++;
+++		if (!local->schedule_round[ac])
+++			local->schedule_round[ac]++;
+++	} else {
+++		local->schedule_round[ac] = 0;
 ++	}
-++	ieee80211_queue_work(&local->hw, &sdata->csa_finalize_work);
 ++
-++	rcu_read_unlock();
++ 	spin_unlock_bh(&local->active_txq_lock[ac]);
 + }
-+ EXPORT_SYMBOL(ieee80211_csa_finish);
-+ 
-diff --git a/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch
++ EXPORT_SYMBOL(ieee80211_txq_schedule_start);
+diff --git a/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch b/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch
 new file mode 100644
-index 0000000000..1955568607
+index 0000000000..df45a520fa
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/326-mac80211-update-bssid_indicator-in-ieee80211_assign_.patch
-@@ -0,0 +1,25 @@
-+From: Lorenzo Bianconi <lorenzo@kernel.org>
-+Date: Thu, 24 Feb 2022 12:55:00 +0100
-+Subject: [PATCH] mac80211: update bssid_indicator in
-+ ieee80211_assign_beacon
++++ b/package/kernel/mac80211/patches/subsys/335-mac80211-add-debugfs-file-to-display-per-phy-AQL-pen.patch
+@@ -0,0 +1,58 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Sat, 25 Jun 2022 21:25:40 +0200
++Subject: [PATCH] mac80211: add debugfs file to display per-phy AQL pending
++ airtime
 +
-+Update bssid_indicator in ieee80211_bss_conf according to the
-+number of bssid in the set.
++Now that the global pending airtime is more relevant for airtime fairness,
++it makes sense to make it accessible via debugfs for debugging
 +
-+Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
-+Link: https://lore.kernel.org/r/f92317e002fca9933f05a445fcefb4f53291d601.1645702516.git.lorenzo@kernel.org
-+Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +---
 +
-+--- a/net/mac80211/cfg.c
-++++ b/net/mac80211/cfg.c
-+@@ -1071,6 +1071,9 @@ static int ieee80211_assign_beacon(struc
-+ 		new->mbssid_ies = (void *)pos;
-+ 		pos += struct_size(new->mbssid_ies, elem, mbssid->cnt);
-+ 		ieee80211_copy_mbssid_beacon(pos, new->mbssid_ies, mbssid);
-++		/* update bssid_indicator */
-++		sdata->vif.bss_conf.bssid_indicator =
-++			ilog2(__roundup_pow_of_two(mbssid->cnt + 1));
-+ 	}
++--- a/net/mac80211/debugfs.c
+++++ b/net/mac80211/debugfs.c
++@@ -201,6 +201,36 @@ static const struct file_operations airt
++ 	.llseek = default_llseek,
++ };
 + 
-+ 	if (csa) {
-diff --git a/package/kernel/mac80211/patches/subsys/329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch b/package/kernel/mac80211/patches/subsys/329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch
+++static ssize_t aql_pending_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 pending\n"
+++			"VO     %u us\n"
+++			"VI     %u us\n"
+++			"BE     %u us\n"
+++			"BK     %u us\n"
+++			"total  %u us\n",
+++			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VO]),
+++			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_VI]),
+++			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BE]),
+++			atomic_read(&local->aql_ac_pending_airtime[IEEE80211_AC_BK]),
+++			atomic_read(&local->aql_total_pending_airtime));
+++	return simple_read_from_buffer(user_buf, count, ppos,
+++				       buf, len);
+++}
+++
+++static const struct file_operations aql_pending_ops = {
+++	.read = aql_pending_read,
+++	.open = simple_open,
+++	.llseek = default_llseek,
+++};
+++
++ static ssize_t aql_txq_limit_read(struct file *file,
++ 				  char __user *user_buf,
++ 				  size_t count,
++@@ -628,6 +658,7 @@ void debugfs_hw_add(struct ieee80211_loc
++ 	DEBUGFS_ADD(hw_conf);
++ 	DEBUGFS_ADD_MODE(force_tx_status, 0600);
++ 	DEBUGFS_ADD_MODE(aql_enable, 0600);
+++	DEBUGFS_ADD(aql_pending);
++ 
++ 	if (local->ops->wake_tx_queue)
++ 		DEBUGFS_ADD_MODE(aqm, 0600);
+diff --git a/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch b/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch
+new file mode 100644
+index 0000000000..35f07c1a97
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/336-mac80211-only-accumulate-airtime-deficit-for-active-.patch
+@@ -0,0 +1,36 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Sat, 25 Jun 2022 23:10:19 +0200
++Subject: [PATCH] mac80211: only accumulate airtime deficit for active
++ clients
++
++When a client does not generate any local tx activity, accumulating airtime
++deficit for the round-robin scheduler can be harmful. If this goes on for too
++long, the deficit could grow quite large, which might cause unreasonable
++initial latency once the client becomes active
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/sta_info.c
+++++ b/net/mac80211/sta_info.c
++@@ -1900,6 +1900,7 @@ void ieee80211_sta_register_airtime(stru
++ 	struct ieee80211_local *local = sta->sdata->local;
++ 	u8 ac = ieee80211_ac_from_tid(tid);
++ 	u32 airtime = 0;
+++	u32 diff;
++ 
++ 	if (sta->local->airtime_flags & AIRTIME_USE_TX)
++ 		airtime += tx_airtime;
++@@ -1909,7 +1910,11 @@ void ieee80211_sta_register_airtime(stru
++ 	spin_lock_bh(&local->active_txq_lock[ac]);
++ 	sta->airtime[ac].tx_airtime += tx_airtime;
++ 	sta->airtime[ac].rx_airtime += rx_airtime;
++-	sta->airtime[ac].deficit -= airtime;
+++
+++	diff = (u32)jiffies - sta->airtime[ac].last_active;
+++	if (diff <= AIRTIME_ACTIVE_DURATION)
+++		sta->airtime[ac].deficit -= airtime;
+++
++ 	spin_unlock_bh(&local->active_txq_lock[ac]);
++ }
++ EXPORT_SYMBOL(ieee80211_sta_register_airtime);
+diff --git a/package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch b/package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch
 new file mode 100644
-index 0000000000..d7832acce5
+index 0000000000..74e857679e
 --- /dev/null
-+++ b/package/kernel/mac80211/patches/subsys/329-mac80211-minstrel_ht-fix-where-rate-stats-are-stored.patch
-@@ -0,0 +1,61 @@
-+From: Peter Seiderer <ps.report@gmx.net>
-+Date: Mon, 4 Apr 2022 18:54:14 +0200
-+Subject: [PATCH] mac80211: minstrel_ht: fix where rate stats are stored (fixes
-+ debugfs output)
-+
-+Using an ath9k card the debugfs output of minstrel_ht looks like the following
-+(note the zero values for the first four rates sum-of success/attempts):
-+
-+             best    ____________rate__________    ____statistics___    _____last____    ______sum-of________
-+mode guard #  rate   [name   idx airtime  max_tp]  [avg(tp) avg(prob)]  [retry|suc|att]  [#success | #attempts]
-+OFDM       1    DP     6.0M  272    1640     5.2       3.1      53.8       3     0 0             0   0
-+OFDM       1   C       9.0M  273    1104     7.7       4.6      53.8       4     0 0             0   0
-+OFDM       1  B       12.0M  274     836    10.0       6.0      53.8       4     0 0             0   0
-+OFDM       1 A    S   18.0M  275     568    14.3       8.5      53.8       5     0 0             0   0
-+OFDM       1      S   24.0M  276     436    18.1       0.0       0.0       5     0 1            80   1778
-+OFDM       1          36.0M  277     300    24.9       0.0       0.0       0     0 1             0   107
-+OFDM       1      S   48.0M  278     236    30.4       0.0       0.0       0     0 0             0   75
-+OFDM       1          54.0M  279     212    33.0       0.0       0.0       0     0 0             0   72
-+
-+Total packet count::    ideal 16582      lookaround 885
-+Average # of aggregated frames per A-MPDU: 1.0
-+
-+Debugging showed that the rate statistics for the first four rates where
-+stored in the MINSTREL_CCK_GROUP instead of the MINSTREL_OFDM_GROUP because
-+in minstrel_ht_get_stats() the supported check was not honoured as done in
-+various other places, e.g net/mac80211/rc80211_minstrel_ht_debugfs.c:
-+
-+ 74                 if (!(mi->supported[i] & BIT(j)))
-+ 75                         continue;
-+
-+With the patch applied the output looks good:
-+
-+              best    ____________rate__________    ____statistics___    _____last____    ______sum-of________
-+mode guard #  rate   [name   idx airtime  max_tp]  [avg(tp) avg(prob)]  [retry|suc|att]  [#success | #attempts]
-+OFDM       1    D      6.0M  272    1640     5.2       5.2     100.0       3     0 0             1   1
-+OFDM       1   C       9.0M  273    1104     7.7       7.7     100.0       4     0 0            38   38
-+OFDM       1  B       12.0M  274     836    10.0       9.9      89.5       4     2 2           372   395
-+OFDM       1 A   P    18.0M  275     568    14.3      14.3      97.2       5    52 53         6956   7181
-+OFDM       1      S   24.0M  276     436    18.1       0.0       0.0       0     0 1             6   163
-+OFDM       1          36.0M  277     300    24.9       0.0       0.0       0     0 1             0   35
-+OFDM       1      S   48.0M  278     236    30.4       0.0       0.0       0     0 0             0   38
-+OFDM       1      S   54.0M  279     212    33.0       0.0       0.0       0     0 0             0   38
-+
-+Total packet count::    ideal 7097      lookaround 287
-+Average # of aggregated frames per A-MPDU: 1.0
-+
-+Signed-off-by: Peter Seiderer <ps.report@gmx.net>
++++ b/package/kernel/mac80211/patches/subsys/337-mac80211-increase-quantum-for-airtime-scheduler.patch
+@@ -0,0 +1,53 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Sun, 26 Jun 2022 11:43:25 +0200
++Subject: [PATCH] mac80211: increase quantum for airtime scheduler
++
++Given the typical AQL budget and queue length, a quantum of 256 with the
++default station weight often requires iterating over all queues frequently,
++until one of them becomes eligible.
++Improve performance by using 8 times station weight as scheduler quantum
++
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
 +---
 +
-+--- a/net/mac80211/rc80211_minstrel_ht.c
-++++ b/net/mac80211/rc80211_minstrel_ht.c
-+@@ -364,6 +364,9 @@ minstrel_ht_get_stats(struct minstrel_pr
++--- a/net/mac80211/ieee80211_i.h
+++++ b/net/mac80211/ieee80211_i.h
++@@ -90,6 +90,8 @@ extern const u8 ieee80211_ac_to_qos_mask
++  */
++ #define AIRTIME_ACTIVE_DURATION (HZ / 10)
 + 
-+ 	group = MINSTREL_CCK_GROUP;
-+ 	for (idx = 0; idx < ARRAY_SIZE(mp->cck_rates); idx++) {
-++		if (!(mi->supported[group] & BIT(idx)))
-++			continue;
+++#define AIRTIME_QUANTUM_SHIFT	3
 ++
-+ 		if (rate->idx != mp->cck_rates[idx])
-+ 			continue;
++ struct ieee80211_bss {
++ 	u32 device_ts_beacon, device_ts_presp;
++ 
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -3894,7 +3894,7 @@ struct ieee80211_txq *ieee80211_next_txq
++ 
++ 		if (deficit < 0)
++ 			sta->airtime[txqi->txq.ac].deficit +=
++-				sta->airtime_weight;
+++				sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
++ 
++ 		if (deficit < 0 || !aql_check) {
++ 			list_move_tail(&txqi->schedule_order,
++@@ -4037,7 +4037,8 @@ bool ieee80211_txq_may_transmit(struct i
++ 		}
++ 		sta = container_of(iter->txq.sta, struct sta_info, sta);
++ 		if (ieee80211_sta_deficit(sta, ac) < 0)
++-			sta->airtime[ac].deficit += sta->airtime_weight;
+++			sta->airtime[ac].deficit += sta->airtime_weight <<
+++						    AIRTIME_QUANTUM_SHIFT;
++ 		list_move_tail(&iter->schedule_order, &local->active_txqs[ac]);
++ 	}
++ 
++@@ -4045,7 +4046,7 @@ bool ieee80211_txq_may_transmit(struct i
++ 	if (sta->airtime[ac].deficit >= 0)
++ 		goto out;
++ 
++-	sta->airtime[ac].deficit += sta->airtime_weight;
+++	sta->airtime[ac].deficit += sta->airtime_weight << AIRTIME_QUANTUM_SHIFT;
++ 	list_move_tail(&txqi->schedule_order, &local->active_txqs[ac]);
++ 	spin_unlock_bh(&local->active_txq_lock[ac]);
 + 
 diff --git a/package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch b/package/kernel/mac80211/patches/subsys/337-mac80211-minstrel_ht-clean-up-CCK-code.patch
 deleted file mode 100644
@@ -10954,6 +16794,42 @@ index abefde7109..0000000000
 - 	if (!ms)
 - 		return -ENOMEM;
 - 
+diff --git a/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch b/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch
+new file mode 100644
+index 0000000000..43c3e75d65
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/339-mac80211-exclude-multicast-packets-from-AQL-pending-.patch
+@@ -0,0 +1,30 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Wed, 13 Jul 2022 07:32:26 +0200
++Subject: [PATCH] mac80211: exclude multicast packets from AQL pending airtime
++
++In AP mode, multicast traffic is handled very differently from normal traffic,
++especially if at least one client is in powersave mode.
++This means that multicast packets can be buffered a lot longer than normal
++unicast packets, and can eat up the AQL budget very quickly because of the low
++data rate.
++Along with the recent change to maintain a global PHY AQL limit, this can lead
++to significant latency spikes for unicast traffic.
++
++Since queueing multicast to hardware is currently not constrained by AQL limits
++anyway, let's just exclude it from the AQL pending airtime calculation entirely.
++
++Fixes: 8e4bac067105 ("wifi: mac80211: add a per-PHY AQL limit to improve fairness")
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/tx.c
+++++ b/net/mac80211/tx.c
++@@ -3792,7 +3792,7 @@ begin:
++ encap_out:
++ 	IEEE80211_SKB_CB(skb)->control.vif = vif;
++ 
++-	if (vif &&
+++	if (tx.sta &&
++ 	    wiphy_ext_feature_isset(local->hw.wiphy, NL80211_EXT_FEATURE_AQL)) {
++ 		bool ampdu = txq->ac != IEEE80211_AC_VO;
++ 		u32 airtime;
 diff --git a/package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch b/package/kernel/mac80211/patches/subsys/339-mac80211-remove-legacy-minstrel-rate-control.patch
 deleted file mode 100644
 index 96ee595ac1..0000000000
@@ -12390,6 +18266,104 @@ index 9b6a614aa8..0000000000
 - 	u32 sample_switch;
 - 	unsigned int cw_min;
 - 	unsigned int cw_max;
+diff --git a/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch b/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch
+new file mode 100644
+index 0000000000..82243f1d98
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/340-wifi-mac80211-do-not-abuse-fq.lock-in-ieee80211_do_s.patch
+@@ -0,0 +1,46 @@
++From aa40d5a43526cca9439a2b45fcfdcd016594dece Mon Sep 17 00:00:00 2001
++From: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
++Date: Sun, 17 Jul 2022 21:21:52 +0900
++Subject: [PATCH] wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop()
++MIME-Version: 1.0
++Content-Type: text/plain; charset=UTF-8
++Content-Transfer-Encoding: 8bit
++
++lockdep complains use of uninitialized spinlock at ieee80211_do_stop() [1],
++for commit f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif
++that is being stopped") guards clear_bit() using fq.lock even before
++fq_init() from ieee80211_txq_setup_flows() initializes this spinlock.
++
++According to discussion [2], Toke was not happy with expanding usage of
++fq.lock. Since __ieee80211_wake_txqs() is called under RCU read lock, we
++can instead use synchronize_rcu() for flushing ieee80211_wake_txqs().
++
++Link: https://syzkaller.appspot.com/bug?extid=eceab52db7c4b961e9d6 [1]
++Link: https://lkml.kernel.org/r/874k0zowh2.fsf@toke.dk [2]
++Reported-by: syzbot <syzbot+eceab52db7c4b961e9d6@syzkaller.appspotmail.com>
++Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
++Fixes: f856373e2f31ffd3 ("wifi: mac80211: do not wake queues on a vif that is being stopped")
++Tested-by: syzbot <syzbot+eceab52db7c4b961e9d6@syzkaller.appspotmail.com>
++Acked-by: Toke Høiland-Jørgensen <toke@kernel.org>
++Signed-off-by: Kalle Valo <kvalo@kernel.org>
++Link: https://lore.kernel.org/r/9cc9b81d-75a3-3925-b612-9d0ad3cab82b@I-love.SAKURA.ne.jp
++[ pick up commit 3598cb6e1862 ("wifi: mac80211: do not abuse fq.lock in ieee80211_do_stop()") from -next]
++Link: https://lore.kernel.org/all/87o7xcq6qt.fsf@kernel.org/
++Signed-off-by: Jakub Kicinski <kuba@kernel.org>
++---
++ net/mac80211/iface.c | 3 +--
++ 1 file changed, 1 insertion(+), 2 deletions(-)
++
++--- a/net/mac80211/iface.c
+++++ b/net/mac80211/iface.c
++@@ -377,9 +377,8 @@ static void ieee80211_do_stop(struct iee
++ 	bool cancel_scan;
++ 	struct cfg80211_nan_func *func;
++ 
++-	spin_lock_bh(&local->fq.lock);
++ 	clear_bit(SDATA_STATE_RUNNING, &sdata->state);
++-	spin_unlock_bh(&local->fq.lock);
+++	synchronize_rcu(); /* flush _ieee80211_wake_txqs() */
++ 
++ 	cancel_scan = rcu_access_pointer(local->scan_sdata) == sdata;
++ 	if (cancel_scan)
+diff --git a/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch b/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch
+new file mode 100644
+index 0000000000..8c56acbf88
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/341-mac80211-Fix-deadlock-Don-t-start-TX-while-holding-f.patch
+@@ -0,0 +1,40 @@
++From: Alexander Wetzel <alexander@wetzel-home.de>
++Date: Thu, 15 Sep 2022 14:41:20 +0200
++Subject: [PATCH] mac80211: Fix deadlock: Don't start TX while holding
++ fq->lock
++
++ieee80211_txq_purge() calls fq_tin_reset() and
++ieee80211_purge_tx_queue(); Both are then calling
++ieee80211_free_txskb(). Which can decide to TX the skb again.
++
++There are at least two ways to get a deadlock:
++
++1) When we have a TDLS teardown packet queued in either tin or frags
++   ieee80211_tdls_td_tx_handle() will call ieee80211_subif_start_xmit()
++   while we still hold fq->lock. ieee80211_txq_enqueue() will thus
++   deadlock.
++
++2) A variant of the above happens if aggregation is up and running:
++   In that case ieee80211_iface_work() will deadlock with the original
++   task: The original tasks already holds fq->lock and tries to get
++   sta->lock after kicking off ieee80211_iface_work(). But the worker
++   can get sta->lock prior to the original task and will then spin for
++   fq->lock.
++
++Avoid these deadlocks by not sending out any skbs when called via
++ieee80211_free_txskb().
++
++Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
++---
++
++--- a/net/mac80211/status.c
+++++ b/net/mac80211/status.c
++@@ -698,7 +698,7 @@ static void ieee80211_report_used_skb(st
++ 
++ 		if (!sdata) {
++ 			skb->dev = NULL;
++-		} else {
+++		} else if (!dropped) {
++ 			unsigned int hdr_size =
++ 				ieee80211_hdrlen(hdr->frame_control);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch b/package/kernel/mac80211/patches/subsys/341-mac80211-minstrel_ht-improve-ampdu-length-estimation.patch
 deleted file mode 100644
 index a8e6e89954..0000000000
@@ -12463,6 +18437,59 @@ index a8e6e89954..0000000000
 - 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)
+diff --git a/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch b/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch
+new file mode 100644
+index 0000000000..4310329319
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/342-mac80211-Ensure-vif-queues-are-operational-after-sta.patch
+@@ -0,0 +1,47 @@
++From: Alexander Wetzel <alexander@wetzel-home.de>
++Date: Thu, 15 Sep 2022 15:09:46 +0200
++Subject: [PATCH] mac80211: Ensure vif queues are operational after start
++
++Make sure local->queue_stop_reasons and vif.txqs_stopped stay in sync.
++
++When a new vif is created the queues may end up in an inconsistent state
++and be inoperable:
++Communication not using iTXQ will work, allowing to e.g. complete the
++association. But the 4-way handshake will time out. The sta will not
++send out any skbs queued in iTXQs.
++
++All normal attempts to start the queues will fail when reaching this
++state.
++local->queue_stop_reasons will have marked all queues as operational but
++vif.txqs_stopped will still be set, creating an inconsistent internal
++state.
++
++In reality this seems to be race between the mac80211 function
++ieee80211_do_open() setting SDATA_STATE_RUNNING and the wake_txqs_tasklet:
++Depending on the driver and the timing the queues may end up to be
++operational or not.
++
++Cc: stable@vger.kernel.org
++Fixes: f856373e2f31 ("wifi: mac80211: do not wake queues on a vif that is being stopped")
++Signed-off-by: Alexander Wetzel <alexander@wetzel-home.de>
++---
++
++--- a/net/mac80211/util.c
+++++ b/net/mac80211/util.c
++@@ -301,14 +301,14 @@ static void __ieee80211_wake_txqs(struct
++ 	local_bh_disable();
++ 	spin_lock(&fq->lock);
++ 
+++	sdata->vif.txqs_stopped[ac] = false;
+++
++ 	if (!test_bit(SDATA_STATE_RUNNING, &sdata->state))
++ 		goto out;
++ 
++ 	if (sdata->vif.type == NL80211_IFTYPE_AP)
++ 		ps = &sdata->bss->ps;
++ 
++-	sdata->vif.txqs_stopped[ac] = false;
++-
++ 	list_for_each_entry_rcu(sta, &local->sta_list, list) {
++ 		if (sdata != sta->sdata)
++ 			continue;
 diff --git a/package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch b/package/kernel/mac80211/patches/subsys/342-mac80211-minstrel_ht-improve-sample-rate-selection.patch
 deleted file mode 100644
 index e084525235..0000000000
@@ -12630,6 +18657,49 @@ index 0dbfa9d4fb..0000000000
 - 	/* Try to increase robustness of max_prob_rate*/
 - 	minstrel_ht_prob_rate_reduce_streams(mi);
 - 
+diff --git a/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch b/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch
+new file mode 100644
+index 0000000000..0feb408d21
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/343-wifi-mac80211-fix-decap-offload-for-stations-on-AP_V.patch
+@@ -0,0 +1,37 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Wed, 28 Sep 2022 13:50:34 +0200
++Subject: [PATCH] wifi: mac80211: fix decap offload for stations on AP_VLAN
++ interfaces
++
++Since AP_VLAN interfaces are not passed to the driver, check offload_flags
++on the bss vif instead.
++
++Reported-by: Howard Hsu <howard-yh.hsu@mediatek.com>
++Fixes: 80a915ec4427 ("mac80211: add rx decapsulation offload support")
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/rx.c
+++++ b/net/mac80211/rx.c
++@@ -4265,6 +4265,7 @@ void ieee80211_check_fast_rx(struct sta_
++ 		.vif_type = sdata->vif.type,
++ 		.control_port_protocol = sdata->control_port_protocol,
++ 	}, *old, *new = NULL;
+++	u32 offload_flags;
++ 	bool set_offload = false;
++ 	bool assign = false;
++ 	bool offload;
++@@ -4380,10 +4381,10 @@ void ieee80211_check_fast_rx(struct sta_
++ 	if (assign)
++ 		new = kmemdup(&fastrx, sizeof(fastrx), GFP_KERNEL);
++ 
++-	offload = assign &&
++-		  (sdata->vif.offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED);
+++	offload_flags = get_bss_sdata(sdata)->vif.offload_flags;
+++	offload = offload_flags & IEEE80211_OFFLOAD_DECAP_ENABLED;
++ 
++-	if (offload)
+++	if (assign && 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);
 diff --git a/package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch b/package/kernel/mac80211/patches/subsys/344-mac80211-minstrel_ht-increase-stats-update-interval.patch
 deleted file mode 100644
 index 9972a9414e..0000000000
@@ -12656,6 +18726,111 @@ index 9972a9414e..0000000000
 - 
 - 	minstrel_ht_init_cck_rates(mp);
 - 	for (i = 0; i < ARRAY_SIZE(mp->hw->wiphy->bands); i++)
+diff --git a/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch b/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch
+new file mode 100644
+index 0000000000..161c7d6c8f
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/344-wifi-cfg80211-fix-ieee80211_data_to_8023_exthdr-hand.patch
+@@ -0,0 +1,99 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Fri, 7 Oct 2022 10:54:47 +0200
++Subject: [PATCH] wifi: cfg80211: fix ieee80211_data_to_8023_exthdr
++ handling of small packets
++
++STP topology change notification packets only have a payload of 7 bytes,
++so they get dropped due to the skb->len < hdrlen + 8 check.
++Fix this by removing skb->len based checks and instead check the return code
++on the skb_copy_bits calls.
++
++Fixes: 2d1c304cb2d5 ("cfg80211: add function for 802.3 conversion with separate output buffer")
++Reported-by: Chad Monroe <chad.monroe@smartrg.com>
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/wireless/util.c
+++++ b/net/wireless/util.c
++@@ -557,7 +557,7 @@ int ieee80211_data_to_8023_exthdr(struct
++ 		return -1;
++ 
++ 	hdrlen = ieee80211_hdrlen(hdr->frame_control) + data_offset;
++-	if (skb->len < hdrlen + 8)
+++	if (skb->len < hdrlen)
++ 		return -1;
++ 
++ 	/* convert IEEE 802.11 header + possible LLC headers into Ethernet
++@@ -572,8 +572,9 @@ int ieee80211_data_to_8023_exthdr(struct
++ 	memcpy(tmp.h_dest, ieee80211_get_DA(hdr), ETH_ALEN);
++ 	memcpy(tmp.h_source, ieee80211_get_SA(hdr), ETH_ALEN);
++ 
++-	if (iftype == NL80211_IFTYPE_MESH_POINT)
++-		skb_copy_bits(skb, hdrlen, &mesh_flags, 1);
+++	if (iftype == NL80211_IFTYPE_MESH_POINT &&
+++	    skb_copy_bits(skb, hdrlen, &mesh_flags, 1) < 0)
+++		return -1;
++ 
++ 	mesh_flags &= MESH_FLAGS_AE;
++ 
++@@ -593,11 +594,12 @@ int ieee80211_data_to_8023_exthdr(struct
++ 		if (iftype == NL80211_IFTYPE_MESH_POINT) {
++ 			if (mesh_flags == MESH_FLAGS_AE_A4)
++ 				return -1;
++-			if (mesh_flags == MESH_FLAGS_AE_A5_A6) {
++-				skb_copy_bits(skb, hdrlen +
++-					offsetof(struct ieee80211s_hdr, eaddr1),
++-					tmp.h_dest, 2 * ETH_ALEN);
++-			}
+++			if (mesh_flags == MESH_FLAGS_AE_A5_A6 &&
+++			    skb_copy_bits(skb, hdrlen +
+++					  offsetof(struct ieee80211s_hdr, eaddr1),
+++					  tmp.h_dest, 2 * ETH_ALEN) < 0)
+++				return -1;
+++
++ 			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
++ 		}
++ 		break;
++@@ -611,10 +613,11 @@ int ieee80211_data_to_8023_exthdr(struct
++ 		if (iftype == NL80211_IFTYPE_MESH_POINT) {
++ 			if (mesh_flags == MESH_FLAGS_AE_A5_A6)
++ 				return -1;
++-			if (mesh_flags == MESH_FLAGS_AE_A4)
++-				skb_copy_bits(skb, hdrlen +
++-					offsetof(struct ieee80211s_hdr, eaddr1),
++-					tmp.h_source, ETH_ALEN);
+++			if (mesh_flags == MESH_FLAGS_AE_A4 &&
+++			    skb_copy_bits(skb, hdrlen +
+++					  offsetof(struct ieee80211s_hdr, eaddr1),
+++					  tmp.h_source, ETH_ALEN) < 0)
+++				return -1;
++ 			hdrlen += __ieee80211_get_mesh_hdrlen(mesh_flags);
++ 		}
++ 		break;
++@@ -626,18 +629,18 @@ int ieee80211_data_to_8023_exthdr(struct
++ 		break;
++ 	}
++ 
++-	skb_copy_bits(skb, hdrlen, &payload, sizeof(payload));
++-	tmp.h_proto = payload.proto;
++-
++-	if (likely((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
++-		    tmp.h_proto != htons(ETH_P_AARP) &&
++-		    tmp.h_proto != htons(ETH_P_IPX)) ||
++-		   ether_addr_equal(payload.hdr, bridge_tunnel_header)))
+++	if (likely(skb_copy_bits(skb, hdrlen, &payload, sizeof(payload)) == 0 &&
+++	           ((!is_amsdu && ether_addr_equal(payload.hdr, rfc1042_header) &&
+++		     payload.proto != htons(ETH_P_AARP) &&
+++		     payload.proto != htons(ETH_P_IPX)) ||
+++		    ether_addr_equal(payload.hdr, bridge_tunnel_header)))) {
++ 		/* remove RFC1042 or Bridge-Tunnel encapsulation and
++ 		 * replace EtherType */
++ 		hdrlen += ETH_ALEN + 2;
++-	else
+++		tmp.h_proto = payload.proto;
+++	} else {
++ 		tmp.h_proto = htons(skb->len - hdrlen);
+++	}
++ 
++ 	pskb_pull(skb, hdrlen);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch b/package/kernel/mac80211/patches/subsys/345-mac80211-minstrel_ht-fix-rounding-error-in-throughpu.patch
 deleted file mode 100644
 index 1df5dec039..0000000000
@@ -12696,6 +18871,37 @@ index 1df5dec039..0000000000
 - }
 - 
 - /*
+diff --git a/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch b/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch
+new file mode 100644
+index 0000000000..16cafc447c
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/345-wifi-mac80211-do-not-drop-packets-smaller-than-the-L.patch
+@@ -0,0 +1,25 @@
++From: Felix Fietkau <nbd@nbd.name>
++Date: Fri, 7 Oct 2022 10:58:26 +0200
++Subject: [PATCH] wifi: mac80211: do not drop packets smaller than the
++ LLC-SNAP header on fast-rx
++
++Since STP TCN frames are only 7 bytes, the pskb_may_pull call returns an error.
++Instead of dropping those packets, bump them back to the slow path for proper
++processing.
++
++Fixes: 49ddf8e6e234 ("mac80211: add fast-rx path")
++Reported-by: Chad Monroe <chad.monroe@smartrg.com>
++Signed-off-by: Felix Fietkau <nbd@nbd.name>
++---
++
++--- a/net/mac80211/rx.c
+++++ b/net/mac80211/rx.c
++@@ -4601,7 +4601,7 @@ static bool ieee80211_invoke_fast_rx(str
++ 
++ 	if (!(status->rx_flags & IEEE80211_RX_AMSDU)) {
++ 		if (!pskb_may_pull(skb, snap_offs + sizeof(*payload)))
++-			goto drop;
+++			return false;
++ 
++ 		payload = (void *)(skb->data + snap_offs);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch b/package/kernel/mac80211/patches/subsys/346-mac80211-minstrel_ht-use-bitfields-to-encode-rate-in.patch
 deleted file mode 100644
 index 6aa6f0ed93..0000000000
@@ -14055,6 +20261,130 @@ index 09f6fd2214..0000000000
 - 	u8 band;
 - 
 - 	/* Bitfield of supported MCS rates of all groups */
+diff --git a/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch b/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch
+new file mode 100644
+index 0000000000..1e3486accd
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/350-bss-color-collision.patch
+@@ -0,0 +1,118 @@
++From 6d945a33f2b0aa24fc210dadaa0af3e8218e7002 Mon Sep 17 00:00:00 2001
++From: Lorenzo Bianconi <lorenzo@kernel.org>
++Date: Fri, 25 Mar 2022 11:42:41 +0100
++Subject: [PATCH] mac80211: introduce BSS color collision detection
++
++Add ieee80211_rx_check_bss_color_collision routine in order to introduce
++BSS color collision detection in mac80211 if it is not supported in HW/FW
++(e.g. for mt7915 chipset).
++Add IEEE80211_HW_DETECTS_COLOR_COLLISION flag to let the driver notify
++BSS color collision detection is supported in HW/FW. Set this for ath11k
++which apparently didn't need this code.
++
++Tested-by: Peter Chiu <Chui-Hao.Chiu@mediatek.com>
++Co-developed-by: Ryder Lee <ryder.lee@mediatek.com>
++Signed-off-by: Ryder Lee <ryder.lee@mediatek.com>
++Signed-off-by: Lorenzo Bianconi <lorenzo@kernel.org>
++Link: https://lore.kernel.org/r/a05eeeb1841a84560dc5aaec77894fcb69a54f27.1648204871.git.lorenzo@kernel.org
++[clarify commit message a bit, move flag to mac80211]
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++---
++ drivers/net/wireless/ath/ath11k/mac.c |  5 ++-
++ include/net/mac80211.h                |  4 +++
++ net/mac80211/debugfs.c                |  1 +
++ net/mac80211/rx.c                     | 46 +++++++++++++++++++++++++++
++ 4 files changed, 55 insertions(+), 1 deletion(-)
++
++--- a/include/net/mac80211.h
+++++ b/include/net/mac80211.h
++@@ -2418,6 +2418,9 @@ struct ieee80211_txq {
++  *	usage and 802.11 frames with %RX_FLAG_ONLY_MONITOR set for monitor to
++  *	the stack.
++  *
+++ * @IEEE80211_HW_DETECTS_COLOR_COLLISION: HW/driver has support for BSS color
+++ *	collision detection and doesn't need it in software.
+++ *
++  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
++  */
++ enum ieee80211_hw_flags {
++@@ -2473,6 +2476,7 @@ enum ieee80211_hw_flags {
++ 	IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
++ 	IEEE80211_HW_SUPPORTS_RX_DECAP_OFFLOAD,
++ 	IEEE80211_HW_SUPPORTS_CONC_MON_RX_DECAP,
+++	IEEE80211_HW_DETECTS_COLOR_COLLISION,
++ 
++ 	/* keep last, obviously */
++ 	NUM_IEEE80211_HW_FLAGS
++--- a/net/mac80211/debugfs.c
+++++ b/net/mac80211/debugfs.c
++@@ -494,6 +494,7 @@ static const char *hw_flag_names[] = {
++ 	FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
++ 	FLAG(SUPPORTS_RX_DECAP_OFFLOAD),
++ 	FLAG(SUPPORTS_CONC_MON_RX_DECAP),
+++	FLAG(DETECTS_COLOR_COLLISION),
++ #undef FLAG
++ };
++ 
++--- a/net/mac80211/rx.c
+++++ b/net/mac80211/rx.c
++@@ -3180,6 +3180,49 @@ static void ieee80211_process_sa_query_r
++ 	ieee80211_tx_skb(sdata, skb);
++ }
++ 
+++static void
+++ieee80211_rx_check_bss_color_collision(struct ieee80211_rx_data *rx)
+++{
+++	struct ieee80211_mgmt *mgmt = (void *)rx->skb->data;
+++	const struct element *ie;
+++	size_t baselen;
+++
+++	if (!wiphy_ext_feature_isset(rx->local->hw.wiphy,
+++				     NL80211_EXT_FEATURE_BSS_COLOR))
+++		return;
+++
+++	if (ieee80211_hw_check(&rx->local->hw, DETECTS_COLOR_COLLISION))
+++		return;
+++
+++	if (rx->sdata->vif.csa_active)
+++		return;
+++
+++	baselen = mgmt->u.beacon.variable - rx->skb->data;
+++	if (baselen > rx->skb->len)
+++		return;
+++
+++	ie = cfg80211_find_ext_elem(WLAN_EID_EXT_HE_OPERATION,
+++				    mgmt->u.beacon.variable,
+++				    rx->skb->len - baselen);
+++	if (ie && ie->datalen >= sizeof(struct ieee80211_he_operation) &&
+++	    ie->datalen >= ieee80211_he_oper_size(ie->data + 1)) {
+++		struct ieee80211_bss_conf *bss_conf = &rx->sdata->vif.bss_conf;
+++		const struct ieee80211_he_operation *he_oper;
+++		u8 color;
+++
+++		he_oper = (void *)(ie->data + 1);
+++		if (le32_get_bits(he_oper->he_oper_params,
+++				  IEEE80211_HE_OPERATION_BSS_COLOR_DISABLED))
+++			return;
+++
+++		color = le32_get_bits(he_oper->he_oper_params,
+++				      IEEE80211_HE_OPERATION_BSS_COLOR_MASK);
+++		if (color == bss_conf->he_bss_color.color)
+++			ieeee80211_obss_color_collision_notify(&rx->sdata->vif,
+++							       BIT_ULL(color));
+++	}
+++}
+++
++ static ieee80211_rx_result debug_noinline
++ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
++ {
++@@ -3205,6 +3248,9 @@ ieee80211_rx_h_mgmt_check(struct ieee802
++ 	    !(rx->flags & IEEE80211_RX_BEACON_REPORTED)) {
++ 		int sig = 0;
++ 
+++		/* sw bss color collision detection */
+++		ieee80211_rx_check_bss_color_collision(rx);
+++
++ 		if (ieee80211_hw_check(&rx->local->hw, SIGNAL_DBM) &&
++ 		    !(status->flag & RX_FLAG_NO_SIGNAL_VAL))
++ 			sig = status->signal;
 diff --git a/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch b/package/kernel/mac80211/patches/subsys/350-mac80211-minstrel_ht-show-sampling-rates-in-debugfs.patch
 deleted file mode 100644
 index 041ba31a37..0000000000
@@ -14433,6 +20763,203 @@ index a366a921d4..0000000000
 - 
 - 		max_gpr_tp_avg = minstrel_ht_get_tp_avg(mi, max_gpr_group,
 - 							max_gpr_idx,
+diff --git a/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch b/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+new file mode 100644
+index 0000000000..ff3cb7be53
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/360-mac80211-fix-a-memory-leak-where-sta_info-is-not-fre.patch
+@@ -0,0 +1,77 @@
++From 4db561ae4a90c2d0e15996634567559e292dc9e5 Mon Sep 17 00:00:00 2001
++From: Ahmed Zaki <anzaki@gmail.com>
++Date: Sat, 2 Oct 2021 08:53:29 -0600
++Subject: [PATCH] mac80211: fix a memory leak where sta_info is not freed
++
++commit 8f9dcc29566626f683843ccac6113a12208315ca upstream.
++
++The following is from a system that went OOM due to a memory leak:
++
++wlan0: Allocated STA 74:83:c2:64:0b:87
++wlan0: Allocated STA 74:83:c2:64:0b:87
++wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_add_sta)
++wlan0: Adding new IBSS station 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 3
++wlan0: Inserted STA 74:83:c2:64:0b:87
++wlan0: IBSS finish 74:83:c2:64:0b:87 (---from ieee80211_ibss_work)
++wlan0: Adding new IBSS station 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 3
++.
++.
++wlan0: expiring inactive not authorized STA 74:83:c2:64:0b:87
++wlan0: moving STA 74:83:c2:64:0b:87 to state 2
++wlan0: moving STA 74:83:c2:64:0b:87 to state 1
++wlan0: Removed STA 74:83:c2:64:0b:87
++wlan0: Destroyed STA 74:83:c2:64:0b:87
++
++The ieee80211_ibss_finish_sta() is called twice on the same STA from 2
++different locations. On the second attempt, the allocated STA is not
++destroyed creating a kernel memory leak.
++
++This is happening because sta_info_insert_finish() does not call
++sta_info_free() the second time when the STA already exists (returns
++-EEXIST). Note that the caller sta_info_insert_rcu() assumes STA is
++destroyed upon errors.
++
++Same fix is applied to -ENOMEM.
++
++Signed-off-by: Ahmed Zaki <anzaki@gmail.com>
++Link: https://lore.kernel.org/r/20211002145329.3125293-1-anzaki@gmail.com
++[change the error path label to use the existing code]
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Viacheslav Sablin <sablin@ispras.ru>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/sta_info.c | 6 +++---
++ 1 file changed, 3 insertions(+), 3 deletions(-)
++
++--- a/net/mac80211/sta_info.c
+++++ b/net/mac80211/sta_info.c
++@@ -646,13 +646,13 @@ static int sta_info_insert_finish(struct
++ 	/* check if STA exists already */
++ 	if (sta_info_get_bss(sdata, sta->sta.addr)) {
++ 		err = -EEXIST;
++-		goto out_err;
+++		goto out_cleanup;
++ 	}
++ 
++ 	sinfo = kzalloc(sizeof(struct station_info), GFP_KERNEL);
++ 	if (!sinfo) {
++ 		err = -ENOMEM;
++-		goto out_err;
+++		goto out_cleanup;
++ 	}
++ 
++ 	local->num_sta++;
++@@ -708,8 +708,8 @@ static int sta_info_insert_finish(struct
++  out_drop_sta:
++ 	local->num_sta--;
++ 	synchronize_net();
+++ out_cleanup:
++ 	cleanup_single_sta(sta);
++- out_err:
++ 	mutex_unlock(&local->sta_mtx);
++ 	kfree(sinfo);
++ 	rcu_read_lock();
+diff --git a/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch b/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+new file mode 100644
+index 0000000000..dd3e934c00
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/361-wifi-mac80211-Don-t-finalize-CSA-in-IBSS-mode-if-sta.patch
+@@ -0,0 +1,47 @@
++From 552ba102a6898630a7d16887f29e606d6fabe508 Mon Sep 17 00:00:00 2001
++From: Siddh Raman Pant <code@siddh.me>
++Date: Sun, 14 Aug 2022 20:45:12 +0530
++Subject: [PATCH] wifi: mac80211: Don't finalize CSA in IBSS mode if state is
++ disconnected
++
++commit 15bc8966b6d3a5b9bfe4c9facfa02f2b69b1e5f0 upstream.
++
++When we are not connected to a channel, sending channel "switch"
++announcement doesn't make any sense.
++
++The BSS list is empty in that case. This causes the for loop in
++cfg80211_get_bss() to be bypassed, so the function returns NULL
++(check line 1424 of net/wireless/scan.c), causing the WARN_ON()
++in ieee80211_ibss_csa_beacon() to get triggered (check line 500
++of net/mac80211/ibss.c), which was consequently reported on the
++syzkaller dashboard.
++
++Thus, check if we have an existing connection before generating
++the CSA beacon in ieee80211_ibss_finish_csa().
++
++Cc: stable@vger.kernel.org
++Fixes: cd7760e62c2a ("mac80211: add support for CSA in IBSS mode")
++Link: https://syzkaller.appspot.com/bug?id=05603ef4ae8926761b678d2939a3b2ad28ab9ca6
++Reported-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
++Signed-off-by: Siddh Raman Pant <code@siddh.me>
++Tested-by: syzbot+b6c9fe29aefe68e4ad34@syzkaller.appspotmail.com
++Link: https://lore.kernel.org/r/20220814151512.9985-1-code@siddh.me
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/ibss.c | 4 ++++
++ 1 file changed, 4 insertions(+)
++
++--- a/net/mac80211/ibss.c
+++++ b/net/mac80211/ibss.c
++@@ -534,6 +534,10 @@ int ieee80211_ibss_finish_csa(struct iee
++ 
++ 	sdata_assert_lock(sdata);
++ 
+++	/* When not connected/joined, sending CSA doesn't make sense. */
+++	if (ifibss->state != IEEE80211_IBSS_MLME_JOINED)
+++		return -ENOLINK;
+++
++ 	/* update cfg80211 bss information with the new channel */
++ 	if (!is_zero_ether_addr(ifibss->bssid)) {
++ 		cbss = cfg80211_get_bss(sdata->local->hw.wiphy,
+diff --git a/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch b/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+new file mode 100644
+index 0000000000..0e58b61602
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/362-wifi-mac80211-Fix-UAF-in-ieee80211_scan_rx.patch
+@@ -0,0 +1,55 @@
++From 5d20c6f932f2758078d0454729129c894fe353e7 Mon Sep 17 00:00:00 2001
++From: Siddh Raman Pant <code@siddh.me>
++Date: Sat, 20 Aug 2022 01:33:40 +0530
++Subject: [PATCH] wifi: mac80211: Fix UAF in ieee80211_scan_rx()
++
++commit 60deb9f10eec5c6a20252ed36238b55d8b614a2c upstream.
++
++ieee80211_scan_rx() tries to access scan_req->flags after a
++null check, but a UAF is observed when the scan is completed
++and __ieee80211_scan_completed() executes, which then calls
++cfg80211_scan_done() leading to the freeing of scan_req.
++
++Since scan_req is rcu_dereference()'d, prevent the racing in
++__ieee80211_scan_completed() by ensuring that from mac80211's
++POV it is no longer accessed from an RCU read critical section
++before we call cfg80211_scan_done().
++
++Cc: stable@vger.kernel.org
++Link: https://syzkaller.appspot.com/bug?extid=f9acff9bf08a845f225d
++Reported-by: syzbot+f9acff9bf08a845f225d@syzkaller.appspotmail.com
++Suggested-by: Johannes Berg <johannes@sipsolutions.net>
++Signed-off-by: Siddh Raman Pant <code@siddh.me>
++Link: https://lore.kernel.org/r/20220819200340.34826-1-code@siddh.me
++Signed-off-by: Johannes Berg <johannes.berg@intel.com>
++Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
++---
++ net/mac80211/scan.c | 11 +++++++----
++ 1 file changed, 7 insertions(+), 4 deletions(-)
++
++--- a/net/mac80211/scan.c
+++++ b/net/mac80211/scan.c
++@@ -461,16 +461,19 @@ static void __ieee80211_scan_completed(s
++ 	scan_req = rcu_dereference_protected(local->scan_req,
++ 					     lockdep_is_held(&local->mtx));
++ 
++-	if (scan_req != local->int_scan_req) {
++-		local->scan_info.aborted = aborted;
++-		cfg80211_scan_done(scan_req, &local->scan_info);
++-	}
++ 	RCU_INIT_POINTER(local->scan_req, NULL);
++ 	RCU_INIT_POINTER(local->scan_sdata, NULL);
++ 
++ 	local->scanning = 0;
++ 	local->scan_chandef.chan = NULL;
++ 
+++	synchronize_rcu();
+++
+++	if (scan_req != local->int_scan_req) {
+++		local->scan_info.aborted = aborted;
+++		cfg80211_scan_done(scan_req, &local->scan_info);
+++	}
+++
++ 	/* Set power back to normal operating levels. */
++ 	ieee80211_hw_config(local, 0);
++ 
 diff --git a/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch b/package/kernel/mac80211/patches/subsys/371-mac80211-don-t-apply-flow-control-on-management-fram.patch
 deleted file mode 100644
 index 0d3b42f3b9..0000000000
@@ -19372,6 +25899,114 @@ index cd91a925f3..0000000000
 - 	CALL_TXH(ieee80211_tx_h_michael_mic_add);
 - 	CALL_TXH(ieee80211_tx_h_sequence);
 - 	CALL_TXH(ieee80211_tx_h_fragment);
+diff --git a/package/kernel/mac80211/patches/subsys/396-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch b/package/kernel/mac80211/patches/subsys/396-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
+deleted file mode 100644
+index 0fecd36382..0000000000
+--- a/package/kernel/mac80211/patches/subsys/396-wifi-mac80211-fix-crash-in-beacon-protection-for-P2P.patch
++++ /dev/null
+@@ -1,52 +0,0 @@
+-From: Johannes Berg <johannes.berg@intel.com>
+-Date: Wed, 5 Oct 2022 21:24:10 +0200
+-Subject: [PATCH] wifi: mac80211: fix crash in beacon protection for
+- P2P-device
+-MIME-Version: 1.0
+-Content-Type: text/plain; charset=UTF-8
+-Content-Transfer-Encoding: 8bit
+-
+-commit b2d03cabe2b2e150ff5a381731ea0355459be09f upstream.
+-
+-If beacon protection is active but the beacon cannot be
+-decrypted or is otherwise malformed, we call the cfg80211
+-API to report this to userspace, but that uses a netdev
+-pointer, which isn't present for P2P-Device. Fix this to
+-call it only conditionally to ensure cfg80211 won't crash
+-in the case of P2P-Device.
+-
+-This fixes CVE-2022-42722.
+-
+-Reported-by: Sönke Huster <shuster@seemoo.tu-darmstadt.de>
+-Fixes: 9eaf183af741 ("mac80211: Report beacon protection failures to user space")
+-Signed-off-by: Johannes Berg <johannes.berg@intel.com>
+----
+-
+---- a/net/mac80211/rx.c
+-+++ b/net/mac80211/rx.c
+-@@ -1972,10 +1972,11 @@ ieee80211_rx_h_decrypt(struct ieee80211_
+- 
+- 		if (mmie_keyidx < NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS ||
+- 		    mmie_keyidx >= NUM_DEFAULT_KEYS + NUM_DEFAULT_MGMT_KEYS +
+--		    NUM_DEFAULT_BEACON_KEYS) {
+--			cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+--						     skb->data,
+--						     skb->len);
+-+				   NUM_DEFAULT_BEACON_KEYS) {
+-+			if (rx->sdata->dev)
+-+				cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+-+							     skb->data,
+-+							     skb->len);
+- 			return RX_DROP_MONITOR; /* unexpected BIP keyidx */
+- 		}
+- 
+-@@ -2123,7 +2124,8 @@ ieee80211_rx_h_decrypt(struct ieee80211_
+- 	/* either the frame has been decrypted or will be dropped */
+- 	status->flag |= RX_FLAG_DECRYPTED;
+- 
+--	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE))
+-+	if (unlikely(ieee80211_is_beacon(fc) && result == RX_DROP_UNUSABLE &&
+-+		     rx->sdata->dev))
+- 		cfg80211_rx_unprot_mlme_mgmt(rx->sdata->dev,
+- 					     skb->data, skb->len);
+- 
+diff --git a/package/kernel/mac80211/patches/subsys/397-disable-mbssid.patch b/package/kernel/mac80211/patches/subsys/397-disable-mbssid.patch
+deleted file mode 100644
+index 5bd33c4588..0000000000
+--- a/package/kernel/mac80211/patches/subsys/397-disable-mbssid.patch
++++ /dev/null
+@@ -1,44 +0,0 @@
+---- a/net/mac80211/util.c
+-+++ b/net/mac80211/util.c
+-@@ -1406,6 +1406,7 @@ static size_t ieee802_11_find_bssid_prof
+- 	if (!bss_bssid || !transmitter_bssid)
+- 		return profile_len;
+- 
+-+	return 0;
+- 	for_each_element_id(elem, WLAN_EID_MULTIPLE_BSSID, start, len) {
+- 		if (elem->datalen < 2)
+- 			continue;
+---- a/net/wireless/scan.c
+-+++ b/net/wireless/scan.c
+-@@ -1982,6 +1982,7 @@ static const struct element
+- 	const struct element *next_mbssid;
+- 	const struct element *next_sub;
+- 
+-+	return NULL;
+- 	next_mbssid = cfg80211_find_elem(WLAN_EID_MULTIPLE_BSSID,
+- 					 mbssid_end,
+- 					 ielen - (mbssid_end - ie));
+-@@ -2063,6 +2064,7 @@ static void cfg80211_parse_mbssid_data(s
+- 	u16 capability;
+- 	struct cfg80211_bss *bss;
+- 
+-+	return;
+- 	if (!non_tx_data)
+- 		return;
+- 	if (!cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
+-@@ -2221,6 +2223,7 @@ cfg80211_update_notlisted_nontrans(struc
+- 	const struct cfg80211_bss_ies *old;
+- 	u8 cpy_len;
+- 
+-+	return;
+- 	lockdep_assert_held(&wiphy_to_rdev(wiphy)->bss_lock);
+- 
+- 	ie = mgmt->u.probe_resp.variable;
+-@@ -2436,6 +2439,7 @@ cfg80211_inform_bss_frame_data(struct wi
+- 
+- 	res = cfg80211_inform_single_bss_frame_data(wiphy, data, mgmt,
+- 						    len, gfp);
+-+	return res;
+- 	if (!res || !wiphy->support_mbssid ||
+- 	    !cfg80211_find_ie(WLAN_EID_MULTIPLE_BSSID, ie, ielen))
+- 		return res;
 diff --git a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch b/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch
 index 974595e11a..f2ed528d23 100644
 --- a/package/kernel/mac80211/patches/subsys/400-allow-ibss-mixed.patch
@@ -19386,7 +26021,7 @@ index 974595e11a..f2ed528d23 100644
   				return -EINVAL;
   
 diff --git a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
-index 6f13f64208..612b9d66ee 100644
+index 6f13f64208..50c24a7746 100644
 --- a/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
 +++ b/package/kernel/mac80211/patches/subsys/500-mac80211_configure_antenna_gain.patch
 @@ -1,24 +1,24 @@
@@ -19461,7 +26096,7 @@ index 6f13f64208..612b9d66ee 100644
  --- a/net/mac80211/cfg.c
  +++ b/net/mac80211/cfg.c
 -@@ -2769,6 +2769,19 @@ static int ieee80211_get_tx_power(struct
-+@@ -2845,6 +2845,19 @@ static int ieee80211_get_tx_power(struct
++@@ -2812,6 +2812,19 @@ static int ieee80211_get_tx_power(struct
   	return 0;
   }
   
@@ -19475,7 +26110,7 @@ index 6f13f64208..612b9d66ee 100644
   {
 -@@ -4413,6 +4426,7 @@ const struct cfg80211_ops mac80211_confi
 + 	struct ieee80211_local *local = wiphy_priv(wiphy);
-+@@ -4549,6 +4562,7 @@ const struct cfg80211_ops mac80211_confi
++@@ -4516,6 +4529,7 @@ const struct cfg80211_ops mac80211_confi
   	.set_wiphy_params = ieee80211_set_wiphy_params,
   	.set_tx_power = ieee80211_set_tx_power,
   	.get_tx_power = ieee80211_get_tx_power,
@@ -19487,7 +26122,7 @@ index 6f13f64208..612b9d66ee 100644
  --- a/net/mac80211/ieee80211_i.h
  +++ b/net/mac80211/ieee80211_i.h
 -@@ -1435,6 +1435,7 @@ struct ieee80211_local {
-+@@ -1464,6 +1464,7 @@ struct ieee80211_local {
++@@ -1448,6 +1448,7 @@ struct ieee80211_local {
   	int dynamic_ps_forced_timeout;
   
   	int user_power_level; /* in dBm, for all interfaces */
@@ -19508,7 +26143,7 @@ index 6f13f64208..612b9d66ee 100644
 - 	[NL80211_ATTR_COLOR_CHANGE_COUNT] = { .type = NLA_U8 },
 - 	[NL80211_ATTR_COLOR_CHANGE_COLOR] = { .type = NLA_U8 },
 - 	[NL80211_ATTR_COLOR_CHANGE_ELEMS] = NLA_POLICY_NESTED(nl80211_policy),
-+@@ -797,6 +797,7 @@ static const struct nla_policy nl80211_p
++@@ -802,6 +802,7 @@ static const struct nla_policy nl80211_p
 + 			NLA_POLICY_NESTED(nl80211_mbssid_config_policy),
 + 	[NL80211_ATTR_MBSSID_ELEMS] = { .type = NLA_NESTED },
 + 	[NL80211_ATTR_RADAR_BACKGROUND] = { .type = NLA_FLAG },
@@ -19517,7 +26152,7 @@ index 6f13f64208..612b9d66ee 100644
   
   /* policy for the key attributes */
 -@@ -3322,6 +3323,20 @@ static int nl80211_set_wiphy(struct sk_b
-+@@ -3377,6 +3378,22 @@ static int nl80211_set_wiphy(struct sk_b
++@@ -3391,6 +3392,22 @@ static int nl80211_set_wiphy(struct sk_b
   		if (result)
 - 			return result;
 + 			goto out;
@@ -19581,6 +26216,73 @@ index 0000000000..26af6a2fb9
 +-#endif /* < 5.2 */
 +-
 +-#endif /* _BP_OF_NET_H */
+diff --git a/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch b/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch
+new file mode 100644
+index 0000000000..dc2b05b1a3
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/783-sync-nl80211.patch
+@@ -0,0 +1,22 @@
++--- a/include/uapi/linux/nl80211.h
+++++ b/include/uapi/linux/nl80211.h
++@@ -6027,6 +6027,11 @@ enum nl80211_feature_flags {
++  * @NL80211_EXT_FEATURE_BSS_COLOR: The driver supports BSS color collision
++  *	detection and change announcemnts.
++  *
+++ * @NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD: Driver running in AP mode supports
+++ *	FILS encryption and decryption for (Re)Association Request and Response
+++ *	frames. Userspace has to share FILS AAD details to the driver by using
+++ *	@NL80211_CMD_SET_FILS_AAD.
+++ *
++  * @NL80211_EXT_FEATURE_RADAR_BACKGROUND: Device supports background radar/CAC
++  *	detection.
++  *
++@@ -6095,6 +6100,7 @@ enum nl80211_ext_feature_index {
++ 	NL80211_EXT_FEATURE_SECURE_RTT,
++ 	NL80211_EXT_FEATURE_PROT_RANGE_NEGO_AND_MEASURE,
++ 	NL80211_EXT_FEATURE_BSS_COLOR,
+++	NL80211_EXT_FEATURE_FILS_CRYPTO_OFFLOAD,
++ 	NL80211_EXT_FEATURE_RADAR_BACKGROUND,
++ 
++ 	/* add new features before the definition below */
+diff --git a/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch b/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch
+new file mode 100644
+index 0000000000..e7da94c9cd
+--- /dev/null
++++ b/package/kernel/mac80211/patches/subsys/800-mac80211-mask-nested-A-MSDU-support-for-mesh.patch
+@@ -0,0 +1,33 @@
++From 313d8c18385f10957402b475f9b0c209ceab6c5a Mon Sep 17 00:00:00 2001
++From: David Bauer <mail@david-bauer.net>
++Date: Fri, 8 Oct 2021 00:25:19 +0200
++Subject: [PATCH] mac80211: mask nested A-MSDU support for mesh
++
++mac80211 incorrectly processes A-MSDUs contained in A-MPDU frames. This
++results in dropped packets and severely impacted throughput.
++
++As a workaround, don't indicate support for A-MSDUs contained in
++A-MPDUs. This improves throughput over mesh links by factor 10.
++
++Ref: https://github.com/openwrt/mt76/issues/450
++
++Signed-off-by: David Bauer <mail@david-bauer.net>
++---
++ net/mac80211/agg-rx.c | 4 +++-
++ 1 file changed, 3 insertions(+), 1 deletion(-)
++
++--- a/net/mac80211/agg-rx.c
+++++ b/net/mac80211/agg-rx.c
++@@ -251,7 +251,11 @@ static void ieee80211_send_addba_resp(st
++ 	mgmt->u.action.u.addba_resp.action_code = WLAN_ACTION_ADDBA_RESP;
++ 	mgmt->u.action.u.addba_resp.dialog_token = dialog_token;
++ 
++-	capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
+++	capab = 0;
+++#ifdef CONFIG_MAC80211_MESH
+++	if (!sta->mesh)
+++#endif
+++		capab = u16_encode_bits(amsdu, IEEE80211_ADDBA_PARAM_AMSDU_MASK);
++ 	capab |= u16_encode_bits(policy, IEEE80211_ADDBA_PARAM_POLICY_MASK);
++ 	capab |= u16_encode_bits(tid, IEEE80211_ADDBA_PARAM_TID_MASK);
++ 	capab |= u16_encode_bits(buf_size, IEEE80211_ADDBA_PARAM_BUF_SIZE_MASK);
 diff --git a/package/kernel/mac80211/realtek.mk b/package/kernel/mac80211/realtek.mk
 index 75cb94d7b6..44c6c25b08 100644
 --- a/package/kernel/mac80211/realtek.mk
-- 
GitLab