mac80211: update encap offload patches to the latest version
[openwrt/openwrt.git] / package / kernel / mac80211 / patches / subsys / 314-mac80211-rework-tx-encapsulation-offload-API.patch
diff --git a/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch b/package/kernel/mac80211/patches/subsys/314-mac80211-rework-tx-encapsulation-offload-API.patch
deleted file mode 100644 (file)
index 4f0d264..0000000
+++ /dev/null
@@ -1,651 +0,0 @@
-From: Felix Fietkau <nbd@nbd.name>
-Date: Thu, 13 Aug 2020 15:37:11 +0200
-Subject: [PATCH] mac80211: rework tx encapsulation offload API
-
-The current API (which lets the driver turn on/off per vif directly) has a
-number of limitations:
-- it does not deal with AP_VLAN
-- conditions for enabling (no tkip, no monitor) are only checked at
-  add_interface time
-- no way to indicate 4-addr support
-
-In order to address this, store offload flags in struct ieee80211_vif
-(easy to extend for decap offload later). mac80211 initially sets the enable
-flag, but gives the driver a chance to modify it before its settings are
-applied. In addition to the .add_interface op, a .update_vif_offload op is
-introduced, which can be used for runtime changes.
-
-If a driver can't disable encap offload at runtime, or if it has some extra
-limitations, it can simply override the flags within those ops.
-
-Support for encap offload with 4-address mode interfaces can be enabled
-by setting a flag from .add_interface or .update_vif_offload.
-
-Signed-off-by: Felix Fietkau <nbd@nbd.name>
----
-
---- a/drivers/net/wireless/ath/ath11k/mac.c
-+++ b/drivers/net/wireless/ath/ath11k/mac.c
-@@ -4150,6 +4150,35 @@ static int ath11k_set_he_mu_sounding_mod
-       return ret;
- }
-+static void ath11k_mac_op_update_vif_offload(struct ieee80211_hw *hw,
-+                                          struct ieee80211_vif *vif)
-+{
-+      struct ath11k *ar = hw->priv;
-+      struct ath11k_base *ab = ar->ab;
-+      struct ath11k_vif *arvif = ath11k_vif_to_arvif(vif);
-+      u32 param_id, param_value;
-+      int ret;
-+
-+      param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
-+      if (ath11k_frame_mode != ATH11K_HW_TXRX_ETHERNET ||
-+          (vif->type != NL80211_IFTYPE_STATION &&
-+           vif->type != NL80211_IFTYPE_AP))
-+              vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+
-+      if (vif->offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED)
-+              param_value = ATH11K_HW_TXRX_ETHERNET;
-+      else
-+              param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
-+
-+      ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
-+                                          param_id, param_value);
-+      if (ret) {
-+              ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
-+                          arvif->vdev_id, ret);
-+              vif->offload_flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+      }
-+}
-+
- static int ath11k_mac_op_add_interface(struct ieee80211_hw *hw,
-                                      struct ieee80211_vif *vif)
- {
-@@ -4159,7 +4188,6 @@ static int ath11k_mac_op_add_interface(s
-       struct vdev_create_params vdev_param = {0};
-       struct peer_create_params peer_param;
-       u32 param_id, param_value;
--      int hw_encap = 0;
-       u16 nss;
-       int i;
-       int ret;
-@@ -4253,30 +4281,7 @@ static int ath11k_mac_op_add_interface(s
-       list_add(&arvif->list, &ar->arvifs);
-       spin_unlock_bh(&ar->data_lock);
--      param_id = WMI_VDEV_PARAM_TX_ENCAP_TYPE;
--      if (ath11k_frame_mode == ATH11K_HW_TXRX_ETHERNET)
--              switch (vif->type) {
--              case NL80211_IFTYPE_STATION:
--              case NL80211_IFTYPE_AP_VLAN:
--              case NL80211_IFTYPE_AP:
--                      hw_encap = 1;
--                      break;
--              default:
--                      break;
--              }
--
--      if (ieee80211_set_hw_80211_encap(vif, hw_encap))
--              param_value = ATH11K_HW_TXRX_ETHERNET;
--      else
--              param_value = ATH11K_HW_TXRX_NATIVE_WIFI;
--
--      ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
--                                          param_id, param_value);
--      if (ret) {
--              ath11k_warn(ab, "failed to set vdev %d tx encap mode: %d\n",
--                          arvif->vdev_id, ret);
--              goto err_vdev_del;
--      }
-+      ath11k_mac_op_update_vif_offload(hw, vif);
-       nss = get_num_chains(ar->cfg_tx_chainmask) ? : 1;
-       ret = ath11k_wmi_vdev_set_param_cmd(ar, arvif->vdev_id,
-@@ -5599,6 +5604,7 @@ static const struct ieee80211_ops ath11k
-       .reconfig_complete              = ath11k_mac_op_reconfig_complete,
-       .add_interface                  = ath11k_mac_op_add_interface,
-       .remove_interface               = ath11k_mac_op_remove_interface,
-+      .update_vif_offload             = ath11k_mac_op_update_vif_offload,
-       .config                         = ath11k_mac_op_config,
-       .bss_info_changed               = ath11k_mac_op_bss_info_changed,
-       .configure_filter               = ath11k_mac_op_configure_filter,
-@@ -5852,6 +5858,7 @@ static int __ath11k_mac_register(struct
-       ieee80211_hw_set(ar->hw, QUEUE_CONTROL);
-       ieee80211_hw_set(ar->hw, SUPPORTS_TX_FRAG);
-       ieee80211_hw_set(ar->hw, REPORTS_LOW_ACK);
-+      ieee80211_hw_set(ar->hw, SUPPORTS_TX_ENCAP_OFFLOAD);
-       if (ht_cap & WMI_HT_CAP_ENABLED) {
-               ieee80211_hw_set(ar->hw, AMPDU_AGGREGATION);
-               ieee80211_hw_set(ar->hw, TX_AMPDU_SETUP_IN_HW);
---- a/include/net/mac80211.h
-+++ b/include/net/mac80211.h
-@@ -1603,6 +1603,21 @@ enum ieee80211_vif_flags {
-       IEEE80211_VIF_GET_NOA_UPDATE            = BIT(3),
- };
-+
-+/**
-+ * enum ieee80211_offload_flags - virtual interface offload flags
-+ *
-+ * @IEEE80211_OFFLOAD_ENCAP_ENABLED: tx encapsulation offload is enabled
-+ *    The driver supports sending frames passed as 802.3 frames by mac80211.
-+ *    It must also support sending 802.11 packets for the same interface.
-+ * @IEEE80211_OFFLOAD_ENCAP_4ADDR: support 4-address mode encapsulation offload
-+ */
-+
-+enum ieee80211_offload_flags {
-+      IEEE80211_OFFLOAD_ENCAP_ENABLED         = BIT(0),
-+      IEEE80211_OFFLOAD_ENCAP_4ADDR           = BIT(1),
-+};
-+
- /**
-  * struct ieee80211_vif - per-interface data
-  *
-@@ -1623,6 +1638,11 @@ enum ieee80211_vif_flags {
-  *    these need to be set (or cleared) when the interface is added
-  *    or, if supported by the driver, the interface type is changed
-  *    at runtime, mac80211 will never touch this field
-+ * @offloaad_flags: hardware offload capabilities/flags for this interface.
-+ *    These are initialized by mac80211 before calling .add_interface,
-+ *    .change_interface or .update_vif_offload and updated by the driver
-+ *    within these ops, based on supported features or runtime change
-+ *    restrictions.
-  * @hw_queue: hardware queue for each AC
-  * @cab_queue: content-after-beacon (DTIM beacon really) queue, AP mode only
-  * @chanctx_conf: The channel context this interface is assigned to, or %NULL
-@@ -1659,6 +1679,7 @@ struct ieee80211_vif {
-       struct ieee80211_chanctx_conf __rcu *chanctx_conf;
-       u32 driver_flags;
-+      u32 offload_flags;
- #ifdef CPTCFG_MAC80211_DEBUGFS
-       struct dentry *debugfs_dir;
-@@ -2325,6 +2346,9 @@ struct ieee80211_txq {
-  *    aggregating MPDUs with the same keyid, allowing mac80211 to keep Tx
-  *    A-MPDU sessions active while rekeying with Extended Key ID.
-  *
-+ * @IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD: Hardware supports tx encapsulation
-+ *    offload
-+ *
-  * @NUM_IEEE80211_HW_FLAGS: number of hardware flags, used for sizing arrays
-  */
- enum ieee80211_hw_flags {
-@@ -2377,6 +2401,7 @@ enum ieee80211_hw_flags {
-       IEEE80211_HW_SUPPORTS_MULTI_BSSID,
-       IEEE80211_HW_SUPPORTS_ONLY_HE_MULTI_BSSID,
-       IEEE80211_HW_AMPDU_KEYBORDER_SUPPORT,
-+      IEEE80211_HW_SUPPORTS_TX_ENCAP_OFFLOAD,
-       /* keep last, obviously */
-       NUM_IEEE80211_HW_FLAGS
-@@ -3811,6 +3836,8 @@ enum ieee80211_reconfig_type {
-  * @set_tid_config: Apply TID specific configurations. This callback may sleep.
-  * @reset_tid_config: Reset TID specific configuration for the peer.
-  *    This callback may sleep.
-+ * @update_vif_config: Update virtual interface offload flags
-+ *    This callback may sleep.
-  */
- struct ieee80211_ops {
-       void (*tx)(struct ieee80211_hw *hw,
-@@ -4122,6 +4149,8 @@ struct ieee80211_ops {
-       int (*reset_tid_config)(struct ieee80211_hw *hw,
-                               struct ieee80211_vif *vif,
-                               struct ieee80211_sta *sta, u8 tids);
-+      void (*update_vif_offload)(struct ieee80211_hw *hw,
-+                                 struct ieee80211_vif *vif);
- };
- /**
---- a/net/mac80211/cfg.c
-+++ b/net/mac80211/cfg.c
-@@ -504,6 +504,7 @@ static int ieee80211_del_key(struct wiph
-       struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       struct ieee80211_key *key = NULL;
-+      bool recalc_offload = false;
-       int ret;
-       mutex_lock(&local->sta_mtx);
-@@ -528,6 +529,7 @@ static int ieee80211_del_key(struct wiph
-               goto out_unlock;
-       }
-+      recalc_offload = key->conf.cipher == WLAN_CIPHER_SUITE_TKIP;
-       ieee80211_key_free(key, sdata->vif.type == NL80211_IFTYPE_STATION);
-       ret = 0;
-@@ -535,6 +537,9 @@ static int ieee80211_del_key(struct wiph
-       mutex_unlock(&local->key_mtx);
-       mutex_unlock(&local->sta_mtx);
-+      if (recalc_offload)
-+              ieee80211_recalc_offload(local);
-+
-       return ret;
- }
---- a/net/mac80211/debugfs.c
-+++ b/net/mac80211/debugfs.c
-@@ -408,6 +408,7 @@ static const char *hw_flag_names[] = {
-       FLAG(SUPPORTS_MULTI_BSSID),
-       FLAG(SUPPORTS_ONLY_HE_MULTI_BSSID),
-       FLAG(AMPDU_KEYBORDER_SUPPORT),
-+      FLAG(SUPPORTS_TX_ENCAP_OFFLOAD),
- #undef FLAG
- };
---- a/net/mac80211/driver-ops.h
-+++ b/net/mac80211/driver-ops.h
-@@ -1385,4 +1385,19 @@ static inline int drv_reset_tid_config(s
-       return ret;
- }
-+
-+static inline void drv_update_vif_offload(struct ieee80211_local *local,
-+                                        struct ieee80211_sub_if_data *sdata)
-+{
-+      might_sleep();
-+      check_sdata_in_driver(sdata);
-+
-+      if (!local->ops->update_vif_offload)
-+              return;
-+
-+      trace_drv_update_vif_offload(local, sdata);
-+      local->ops->update_vif_offload(&local->hw, &sdata->vif);
-+      trace_drv_return_void(local);
-+}
-+
- #endif /* __MAC80211_DRIVER_OPS */
---- a/net/mac80211/ieee80211_i.h
-+++ b/net/mac80211/ieee80211_i.h
-@@ -990,8 +990,6 @@ struct ieee80211_sub_if_data {
-       } debugfs;
- #endif
--      bool hw_80211_encap;
--
-       /* must be last, dynamically sized area in this! */
-       struct ieee80211_vif vif;
- };
-@@ -1769,6 +1767,7 @@ void ieee80211_del_virtual_monitor(struc
- bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
- void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata,
-                             bool update_bss);
-+void ieee80211_recalc_offload(struct ieee80211_local *local);
- static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
- {
---- a/net/mac80211/iface.c
-+++ b/net/mac80211/iface.c
-@@ -43,6 +43,7 @@
-  */
- static void ieee80211_iface_work(struct work_struct *work);
-+static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata);
- bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
- {
-@@ -348,6 +349,99 @@ static int ieee80211_check_queues(struct
-       return 0;
- }
-+static bool ieee80211_iftype_supports_encap_offload(enum nl80211_iftype iftype)
-+{
-+      switch (iftype) {
-+      case NL80211_IFTYPE_AP:
-+      case NL80211_IFTYPE_P2P_GO:
-+      case NL80211_IFTYPE_P2P_CLIENT:
-+      case NL80211_IFTYPE_STATION:
-+              return true;
-+      default:
-+              return false;
-+      }
-+}
-+
-+static bool ieee80211_set_sdata_offload_flags(struct ieee80211_sub_if_data *sdata)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      struct ieee80211_key *key;
-+      u32 flags;
-+
-+      flags = sdata->vif.offload_flags;
-+
-+      if (ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) &&
-+          ieee80211_iftype_supports_encap_offload(sdata->vif.type)) {
-+              flags |= IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+              mutex_lock(&local->key_mtx);
-+              list_for_each_entry(key, &sdata->key_list, list) {
-+                      if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
-+                              continue;
-+                      if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP ||
-+                          !(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-+                              flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+              }
-+              mutex_unlock(&local->key_mtx);
-+
-+              if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
-+                  local->hw.wiphy->frag_threshold != (u32)-1)
-+                      flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+
-+              if (local->monitors)
-+                      flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+      } else {
-+              flags &= ~IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+      }
-+
-+      if (sdata->vif.offload_flags == flags)
-+              return false;
-+
-+      sdata->vif.offload_flags = flags;
-+      return true;
-+}
-+
-+
-+static void ieee80211_recalc_sdata_offload(struct ieee80211_sub_if_data *sdata)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      struct ieee80211_sub_if_data *vsdata;
-+
-+      if (ieee80211_set_sdata_offload_flags(sdata)) {
-+              drv_update_vif_offload(local, sdata);
-+              ieee80211_set_vif_encap_ops(sdata);
-+      }
-+
-+      list_for_each_entry(vsdata, &local->interfaces, list) {
-+              if (vsdata->vif.type != NL80211_IFTYPE_AP_VLAN ||
-+                  vsdata->bss != &sdata->u.ap)
-+                      continue;
-+
-+              ieee80211_set_vif_encap_ops(vsdata);
-+      }
-+}
-+
-+void ieee80211_recalc_offload(struct ieee80211_local *local)
-+{
-+      struct ieee80211_sub_if_data *sdata;
-+
-+      if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD))
-+              return;
-+
-+      mutex_lock(&local->iflist_mtx);
-+
-+      list_for_each_entry(sdata, &local->interfaces, list) {
-+              if (!ieee80211_sdata_running(sdata))
-+                      continue;
-+
-+              ieee80211_recalc_sdata_offload(sdata);
-+      }
-+
-+      mutex_unlock(&local->iflist_mtx);
-+}
-+
- void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
-                                   const int offset)
- {
-@@ -587,6 +681,7 @@ int ieee80211_do_open(struct wireless_de
-               if (rtnl_dereference(sdata->bss->beacon)) {
-                       ieee80211_vif_vlan_copy_chanctx(sdata);
-                       netif_carrier_on(dev);
-+                      ieee80211_set_vif_encap_ops(sdata);
-               } else {
-                       netif_carrier_off(dev);
-               }
-@@ -616,6 +711,7 @@ int ieee80211_do_open(struct wireless_de
-               ieee80211_adjust_monitor_flags(sdata, 1);
-               ieee80211_configure_filter(local);
-+              ieee80211_recalc_offload(local);
-               mutex_lock(&local->mtx);
-               ieee80211_recalc_idle(local);
-               mutex_unlock(&local->mtx);
-@@ -625,10 +721,13 @@ int ieee80211_do_open(struct wireless_de
-       default:
-               if (coming_up) {
-                       ieee80211_del_virtual_monitor(local);
-+                      ieee80211_set_sdata_offload_flags(sdata);
-                       res = drv_add_interface(local, sdata);
-                       if (res)
-                               goto err_stop;
-+
-+                      ieee80211_set_vif_encap_ops(sdata);
-                       res = ieee80211_check_queues(sdata,
-                               ieee80211_vif_type_p2p(&sdata->vif));
-                       if (res)
-@@ -1286,61 +1385,6 @@ static const struct net_device_ops ieee8
- };
--static void __ieee80211_set_hw_80211_encap(struct ieee80211_sub_if_data *sdata,
--                                         bool enable)
--{
--      sdata->dev->netdev_ops = enable ? &ieee80211_dataif_8023_ops :
--                                        &ieee80211_dataif_ops;
--      sdata->hw_80211_encap = enable;
--}
--
--bool ieee80211_set_hw_80211_encap(struct ieee80211_vif *vif, bool enable)
--{
--      struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
--      struct ieee80211_local *local = sdata->local;
--      struct ieee80211_sub_if_data *iter;
--      struct ieee80211_key *key;
--
--      mutex_lock(&local->iflist_mtx);
--      list_for_each_entry(iter, &local->interfaces, list) {
--              struct ieee80211_sub_if_data *disable = NULL;
--
--              if (vif->type == NL80211_IFTYPE_MONITOR) {
--                      disable = iter;
--                      __ieee80211_set_hw_80211_encap(iter, false);
--              } else if (iter->vif.type == NL80211_IFTYPE_MONITOR) {
--                      disable = sdata;
--                      enable = false;
--              }
--              if (disable)
--                      sdata_dbg(disable,
--                                "disable hw 80211 encap due to mon co-exist\n");
--      }
--      mutex_unlock(&local->iflist_mtx);
--
--      if (enable == sdata->hw_80211_encap)
--              return enable;
--
--      if (!sdata->dev)
--              return false;
--
--      if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_FRAG) &&
--          (local->hw.wiphy->frag_threshold != (u32)-1))
--              enable = false;
--
--      mutex_lock(&sdata->local->key_mtx);
--      list_for_each_entry(key, &sdata->key_list, list) {
--              if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP)
--                      enable = false;
--      }
--      mutex_unlock(&sdata->local->key_mtx);
--
--      __ieee80211_set_hw_80211_encap(sdata, enable);
--
--      return enable;
--}
--EXPORT_SYMBOL(ieee80211_set_hw_80211_encap);
--
- static void ieee80211_if_free(struct net_device *dev)
- {
-       free_percpu(netdev_tstats(dev));
-@@ -1371,6 +1415,51 @@ static void ieee80211_if_setup_no_queue(
- #endif
- }
-+static void ieee80211_set_vif_encap_ops(struct ieee80211_sub_if_data *sdata)
-+{
-+      struct ieee80211_local *local = sdata->local;
-+      struct ieee80211_sub_if_data *bss = sdata;
-+      struct ieee80211_key *key;
-+      bool enabled;
-+
-+      if (sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
-+              if (!sdata->bss)
-+                      return;
-+
-+              bss = container_of(sdata->bss, struct ieee80211_sub_if_data, u.ap);
-+      }
-+
-+      if (!ieee80211_hw_check(&local->hw, SUPPORTS_TX_ENCAP_OFFLOAD) ||
-+          !ieee80211_iftype_supports_encap_offload(bss->vif.type))
-+              return;
-+
-+      enabled = bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_ENABLED;
-+      if (sdata->wdev.use_4addr &&
-+          !(bss->vif.offload_flags & IEEE80211_OFFLOAD_ENCAP_4ADDR))
-+              enabled = false;
-+
-+      /*
-+       * Encapsulation offload cannot be used with software crypto, and a per-VLAN
-+       * key may have been set
-+       */
-+      if (enabled && sdata->vif.type == NL80211_IFTYPE_AP_VLAN) {
-+              mutex_lock(&local->key_mtx);
-+              list_for_each_entry(key, &sdata->key_list, list) {
-+                      if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_128 ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_GMAC_256 ||
-+                          key->conf.cipher == WLAN_CIPHER_SUITE_BIP_CMAC_256)
-+                              continue;
-+                      if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-+                              enabled = false;
-+              }
-+              mutex_unlock(&local->key_mtx);
-+      }
-+
-+      sdata->dev->netdev_ops = enabled ? &ieee80211_dataif_8023_ops :
-+                                         &ieee80211_dataif_ops;
-+}
-+
- static void ieee80211_iface_work(struct work_struct *work)
- {
-       struct ieee80211_sub_if_data *sdata =
-@@ -1553,7 +1642,6 @@ static void ieee80211_setup_sdata(struct
-       sdata->vif.bss_conf.txpower = INT_MIN; /* unset */
-       sdata->noack_map = 0;
--      sdata->hw_80211_encap = false;
-       /* only monitor/p2p-device differ */
-       if (sdata->dev) {
-@@ -1688,6 +1776,7 @@ static int ieee80211_runtime_change_ifty
-       ieee80211_teardown_sdata(sdata);
-+      ieee80211_set_sdata_offload_flags(sdata);
-       ret = drv_change_interface(local, sdata, internal_type, p2p);
-       if (ret)
-               type = ieee80211_vif_type_p2p(&sdata->vif);
-@@ -1700,6 +1789,7 @@ static int ieee80211_runtime_change_ifty
-       ieee80211_check_queues(sdata, type);
-       ieee80211_setup_sdata(sdata, type);
-+      ieee80211_set_vif_encap_ops(sdata);
-       err = ieee80211_do_open(&sdata->wdev, false);
-       WARN(err, "type change: do_open returned %d", err);
---- a/net/mac80211/key.c
-+++ b/net/mac80211/key.c
-@@ -177,13 +177,6 @@ static int ieee80211_key_enable_hw_accel
-               }
-       }
--      /* TKIP countermeasures don't work in encap offload mode */
--      if (key->conf.cipher == WLAN_CIPHER_SUITE_TKIP &&
--          sdata->hw_80211_encap) {
--              sdata_dbg(sdata, "TKIP is not allowed in hw 80211 encap mode\n");
--              return -EINVAL;
--      }
--
-       ret = drv_set_key(key->local, SET_KEY, sdata,
-                         sta ? &sta->sta : NULL, &key->conf);
-@@ -219,14 +212,6 @@ static int ieee80211_key_enable_hw_accel
-       case WLAN_CIPHER_SUITE_CCMP_256:
-       case WLAN_CIPHER_SUITE_GCMP:
-       case WLAN_CIPHER_SUITE_GCMP_256:
--              /* We cannot do software crypto of data frames with
--               * encapsulation offload enabled. However for 802.11w to
--               * function properly we need cmac/gmac keys.
--               */
--              if (sdata->hw_80211_encap)
--                      return -EINVAL;
--              /* Fall through */
--
-       case WLAN_CIPHER_SUITE_AES_CMAC:
-       case WLAN_CIPHER_SUITE_BIP_CMAC_256:
-       case WLAN_CIPHER_SUITE_BIP_GMAC_128:
-@@ -824,6 +809,7 @@ int ieee80211_key_link(struct ieee80211_
-        */
-       bool delay_tailroom = sdata->vif.type == NL80211_IFTYPE_STATION;
-       int ret = -EOPNOTSUPP;
-+      bool recalc_offload = false;
-       mutex_lock(&sdata->local->key_mtx);
-@@ -864,11 +850,15 @@ int ieee80211_key_link(struct ieee80211_
-       key->local = sdata->local;
-       key->sdata = sdata;
-       key->sta = sta;
-+      recalc_offload = !old_key && key->conf.cipher == WLAN_CIPHER_SUITE_TKIP;
-       increment_tailroom_need_count(sdata);
-       ret = ieee80211_key_replace(sdata, sta, pairwise, old_key, key);
-+      if (!(key->flags & KEY_FLAG_UPLOADED_TO_HARDWARE))
-+              recalc_offload = true;
-+
-       if (!ret) {
-               ieee80211_debugfs_key_add(key);
-               ieee80211_key_destroy(old_key, delay_tailroom);
-@@ -879,6 +869,9 @@ int ieee80211_key_link(struct ieee80211_
-  out:
-       mutex_unlock(&sdata->local->key_mtx);
-+      if (recalc_offload)
-+              ieee80211_recalc_offload(sdata->local);
-+
-       return ret;
- }
---- a/net/mac80211/trace.h
-+++ b/net/mac80211/trace.h
-@@ -2733,6 +2733,12 @@ TRACE_EVENT(drv_get_ftm_responder_stats,
-       )
- );
-+DEFINE_EVENT(local_sdata_addr_evt, drv_update_vif_offload,
-+      TP_PROTO(struct ieee80211_local *local,
-+               struct ieee80211_sub_if_data *sdata),
-+      TP_ARGS(local, sdata)
-+);
-+
- #endif /* !__MAC80211_DRIVER_TRACE || TRACE_HEADER_MULTI_READ */
- #undef TRACE_INCLUDE_PATH
---- a/net/mac80211/tx.c
-+++ b/net/mac80211/tx.c
-@@ -4264,11 +4264,6 @@ netdev_tx_t ieee80211_subif_start_xmit_8
-       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       struct sta_info *sta;
--      if (WARN_ON(!sdata->hw_80211_encap)) {
--              kfree_skb(skb);
--              return NETDEV_TX_OK;
--      }
--
-       if (unlikely(skb->len < ETH_HLEN)) {
-               kfree_skb(skb);
-               return NETDEV_TX_OK;