wifi: iwlwifi: mvm: add cancel/remain_on_channel for MLD mode
authorMiri Korenblit <miriam.rachel.korenblit@intel.com>
Tue, 28 Mar 2023 07:58:47 +0000 (10:58 +0300)
committerJohannes Berg <johannes.berg@intel.com>
Thu, 30 Mar 2023 10:07:53 +0000 (12:07 +0200)
Add an MLD version of the remain_on_channel and
cancel_remain_on_channel callbacks.

Signed-off-by: Miri Korenblit <miriam.rachel.korenblit@intel.com>
Signed-off-by: Gregory Greenman <gregory.greenman@intel.com>
Link: https://lore.kernel.org/r/20230328104948.b51813dbebd4.Ia25bbd63d3138e4759237ce2be0cd0436fe01c0a@changeid
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/intel/iwlwifi/fw/api/mac-cfg.h
drivers/net/wireless/intel/iwlwifi/mvm/mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mld-mac80211.c
drivers/net/wireless/intel/iwlwifi/mvm/mld-sta.c
drivers/net/wireless/intel/iwlwifi/mvm/mvm.h
drivers/net/wireless/intel/iwlwifi/mvm/sta.h
drivers/net/wireless/intel/iwlwifi/mvm/time-event.c

index a111e7366d49da3999bee1d0baedeccfa5bf6738..3c540aa9c0c86dc7946b906390e9296776dba1aa 100644 (file)
@@ -491,11 +491,14 @@ struct iwl_link_config_cmd {
  * @STATION_TYPE_MCAST: the station used for BCAST / MCAST in GO. Will be
  *     suspended / resumed at the right timing depending on the clients'
  *     power save state and the DTIM timing
+ * @STATION_TYPE_AUX: aux sta. In the FW there is no need for a special type
+ *     for the aux sta, so this type is only for driver - internal use.
  */
 enum iwl_fw_sta_type {
        STATION_TYPE_PEER,
        STATION_TYPE_BCAST_MGMT,
        STATION_TYPE_MCAST,
+       STATION_TYPE_AUX,
 }; /* STATION_TYPE_E_VER_1 */
 
 /**
index bb7e4e26d99f3536231dd1d518266a241c42b12e..d36319bd9247feeeeccc8934519fab251d614380 100644 (file)
@@ -4309,6 +4309,20 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
                       struct ieee80211_channel *channel,
                       int duration,
                       enum ieee80211_roc_type type)
+{
+       struct iwl_mvm_roc_ops ops = {
+               .add_aux_sta_for_hs20 = iwl_mvm_add_aux_sta_for_hs20,
+               .switch_phy_ctxt = iwl_mvm_roc_switch_binding,
+       };
+
+       return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
+}
+
+/* Execute the common part for MLD and non-MLD modes */
+int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_channel *channel, int duration,
+                      enum ieee80211_roc_type type,
+                      struct iwl_mvm_roc_ops *ops)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
        struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
@@ -4334,7 +4348,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
                lmac_id = iwl_mvm_get_lmac_id(mvm->fw, channel->band);
 
                /* Use aux roc framework (HS20) */
-               ret = iwl_mvm_add_aux_sta_for_hs20(mvm, lmac_id);
+               ret = ops->add_aux_sta_for_hs20(mvm, lmac_id);
                if (!ret)
                        ret = iwl_mvm_send_aux_roc_cmd(mvm, channel,
                                                       vif, duration);
@@ -4354,7 +4368,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
                        continue;
 
                if (phy_ctxt->ref && channel == phy_ctxt->channel) {
-                       ret = iwl_mvm_roc_switch_binding(mvm, vif, phy_ctxt);
+                       ret = ops->switch_phy_ctxt(mvm, vif, phy_ctxt);
                        if (ret)
                                goto out_unlock;
 
@@ -4408,7 +4422,7 @@ static int iwl_mvm_roc(struct ieee80211_hw *hw,
                        goto out_unlock;
                }
 
-               ret = iwl_mvm_roc_switch_binding(mvm, vif, phy_ctxt);
+               ret = ops->switch_phy_ctxt(mvm, vif, phy_ctxt);
                if (ret)
                        goto out_unlock;
 
@@ -4425,8 +4439,8 @@ out_unlock:
        return ret;
 }
 
-static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
-                             struct ieee80211_vif *vif)
+int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif)
 {
        struct iwl_mvm *mvm = IWL_MAC80211_GET_MVM(hw);
 
index 9d97098ab57c7406811415b78f16083a75db8b1d..871da586ebb48f6bdadb1b867d365c794535d10d 100644 (file)
@@ -592,10 +592,53 @@ iwl_mvm_mld_mac_conf_tx(struct ieee80211_hw *hw,
        return 0;
 }
 
+static int iwl_mvm_link_switch_phy_ctx(struct iwl_mvm *mvm,
+                                      struct ieee80211_vif *vif,
+                                      struct iwl_mvm_phy_ctxt *new_phy_ctxt)
+{
+       struct iwl_mvm_vif *mvmvif = iwl_mvm_vif_from_mac80211(vif);
+       int ret = 0;
+
+       lockdep_assert_held(&mvm->mutex);
+
+       /* Inorder to change the phy_ctx of a link, the link needs to be
+        * inactive. Therefore, first deactivate the link, then change its
+        * phy_ctx, and then activate it again.
+        */
+       ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, false);
+       if (WARN(ret, "Failed to deactivate link\n"))
+               return ret;
+
+       iwl_mvm_phy_ctxt_unref(mvm, mvmvif->deflink.phy_ctxt);
+
+       mvmvif->deflink.phy_ctxt = new_phy_ctxt;
+
+       ret = iwl_mvm_link_changed(mvm, vif, 0, false);
+       if (WARN(ret, "Failed to deactivate link\n"))
+               return ret;
+
+       ret = iwl_mvm_link_changed(mvm, vif, LINK_CONTEXT_MODIFY_ACTIVE, true);
+       WARN(ret, "Failed binding P2P_DEVICE\n");
+       return ret;
+}
+
+static int iwl_mvm_mld_roc(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          struct ieee80211_channel *channel, int duration,
+                          enum ieee80211_roc_type type)
+{
+       struct iwl_mvm_roc_ops ops = {
+               .add_aux_sta_for_hs20 = iwl_mvm_mld_add_aux_sta,
+               .switch_phy_ctxt = iwl_mvm_link_switch_phy_ctx,
+       };
+
+       return iwl_mvm_roc_common(hw, vif, channel, duration, type, &ops);
+}
 const struct ieee80211_ops iwl_mvm_mld_hw_ops = {
        .add_interface = iwl_mvm_mld_mac_add_interface,
        .remove_interface = iwl_mvm_mld_mac_remove_interface,
        .config_iface_filter = iwl_mvm_mld_config_iface_filter,
+       .remain_on_channel = iwl_mvm_mld_roc,
+       .cancel_remain_on_channel = iwl_mvm_cancel_roc,
        .assign_vif_chanctx = iwl_mvm_mld_assign_vif_chanctx,
        .unassign_vif_chanctx = iwl_mvm_mld_unassign_vif_chanctx,
        .switch_vif_chanctx = iwl_mvm_mld_switch_vif_chanctx,
index 16723d581a3d2f9fd080df6af3efcefe0b2dbf6e..643eb58317f042a5133d278173188767047b7bd2 100644 (file)
@@ -75,6 +75,24 @@ static int iwl_mvm_mld_rm_sta_from_fw(struct iwl_mvm *mvm, u32 sta_id)
        return 0;
 }
 
+static int iwl_mvm_add_aux_sta_to_fw(struct iwl_mvm *mvm,
+                                    struct iwl_mvm_int_sta *sta,
+                                    u32 lmac_id)
+{
+       int ret;
+
+       struct iwl_mvm_aux_sta_cmd cmd = {
+               .sta_id = cpu_to_le32(sta->sta_id),
+               .lmac_id = cpu_to_le32(lmac_id),
+       };
+
+       ret = iwl_mvm_send_cmd_pdu(mvm, WIDE_ID(MAC_CONF_GROUP, AUX_STA_CMD),
+                                  0, sizeof(cmd), &cmd);
+       if (ret)
+               IWL_ERR(mvm, "Failed to send AUX_STA_CMD\n");
+       return ret;
+}
+
 /*
  * Adds an internal sta to the FW table with its queues
  */
@@ -91,7 +109,10 @@ static int iwl_mvm_mld_add_int_sta_with_queue(struct iwl_mvm *mvm,
        if (WARN_ON_ONCE(sta->sta_id == IWL_MVM_INVALID_STA))
                return -ENOSPC;
 
-       ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, phy_id);
+       if (sta->type == STATION_TYPE_AUX)
+               ret = iwl_mvm_add_aux_sta_to_fw(mvm, sta, phy_id);
+       else
+               ret = iwl_mvm_mld_add_int_sta_to_fw(mvm, sta, addr, phy_id);
        if (ret)
                return ret;
 
@@ -224,6 +245,19 @@ int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                                       IWL_MAX_TID_COUNT, NULL);
 }
 
+int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       /* In CDB NICs we need to specify which lmac to use for aux activity
+        * using the phy_id argument place to send lmac_id to the function
+        */
+       return iwl_mvm_mld_add_int_sta(mvm, &mvm->aux_sta, &mvm->aux_queue,
+                                      NL80211_IFTYPE_UNSPECIFIED,
+                                      STATION_TYPE_AUX, lmac_id, NULL,
+                                      IWL_MAX_TID_COUNT, NULL);
+}
+
 static int iwl_mvm_mld_disable_txq(struct iwl_mvm *mvm,
                                   struct ieee80211_sta *sta,
                                   u16 *queueptr, u8 tid)
@@ -332,6 +366,14 @@ int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif)
                                      IWL_MAX_TID_COUNT, &mvm->snif_queue);
 }
 
+int iwl_mvm_mld_rm_aux_sta(struct iwl_mvm *mvm)
+{
+       lockdep_assert_held(&mvm->mutex);
+
+       return iwl_mvm_mld_rm_int_sta(mvm, &mvm->aux_sta, false,
+                                     IWL_MAX_TID_COUNT, &mvm->aux_queue);
+}
+
 /* send a cfg sta command to add/update a sta in firmware */
 static int iwl_mvm_mld_cfg_sta(struct iwl_mvm *mvm, struct ieee80211_sta *sta,
                               struct ieee80211_vif *vif, u16 phy_id)
index 2ea224acdea17fb49e25122b544187616aec9010..ba59a6c305295a0b4d7884d3391064d4f3da0eb7 100644 (file)
@@ -1827,6 +1827,32 @@ void iwl_mvm_bss_info_changed_station_assoc(struct iwl_mvm *mvm,
                                            struct ieee80211_vif *vif,
                                            u64 changes);
 
+/* ROC */
+/**
+ * struct iwl_mvm_roc_ops - callbacks for the remain_on_channel()
+ *
+ * Since the only difference between both MLD and
+ * non-MLD versions of remain_on_channel() is these function calls,
+ * each version will send its specific function calls to
+ * %iwl_mvm_roc_common().
+ *
+ * @add_aux_sta_for_hs20: pointer to the function that adds an aux sta
+ *     for Hot Spot 2.0
+ * @switch_phy_ctxt: pointer to the function that switches a vif from one
+ *     phy_ctx to another
+ */
+struct iwl_mvm_roc_ops {
+       int (*add_aux_sta_for_hs20)(struct iwl_mvm *mvm, u32 lmac_id);
+       int (*switch_phy_ctxt)(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
+                              struct iwl_mvm_phy_ctxt *new_phy_ctxt);
+};
+
+int iwl_mvm_roc_common(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                      struct ieee80211_channel *channel, int duration,
+                      enum ieee80211_roc_type type,
+                      struct iwl_mvm_roc_ops *ops);
+int iwl_mvm_cancel_roc(struct ieee80211_hw *hw,
+                      struct ieee80211_vif *vif);
 /*Session Protection */
 void iwl_mvm_protect_assoc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                           u32 duration_override);
index 770516b2030366761e4e8de7c2dc110436b5b053..5436e52ca6391e6ddb589b991ddbb886953995c3 100644 (file)
@@ -622,9 +622,11 @@ int iwl_mvm_mac_sta_state_common(struct ieee80211_hw *hw,
 int iwl_mvm_mld_add_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mld_add_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mld_add_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mld_add_aux_sta(struct iwl_mvm *mvm, u32 lmac_id);
 int iwl_mvm_mld_rm_bcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mld_rm_snif_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
 int iwl_mvm_mld_rm_mcast_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif);
+int iwl_mvm_mld_rm_aux_sta(struct iwl_mvm *mvm);
 int iwl_mvm_mld_add_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                        struct ieee80211_sta *sta);
 int iwl_mvm_mld_update_sta(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
index 3b17dd998d19f1dc4647aeb49146f9fb7ec560b5..6b7b6250f1bbdffd66681e28e5354fe884fc6eaf 100644 (file)
@@ -95,6 +95,11 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
                /* do the same in case of hot spot 2.0 */
                iwl_mvm_flush_sta(mvm, &mvm->aux_sta, true);
 
+               if (mvm->mld_api_is_used) {
+                       iwl_mvm_mld_rm_aux_sta(mvm);
+                       goto out_unlock;
+               }
+
                /* In newer version of this command an aux station is added only
                 * in cases of dedicated tx queue and need to be removed in end
                 * of use */
@@ -102,6 +107,7 @@ void iwl_mvm_roc_done_wk(struct work_struct *wk)
                        iwl_mvm_rm_aux_sta(mvm);
        }
 
+out_unlock:
        mutex_unlock(&mvm->mutex);
 }