iwlwifi: mvm: add remove flow for AUX ROC time events
authorMatti Gottlieb <matti.gottlieb@intel.com>
Sun, 16 Nov 2014 08:25:12 +0000 (10:25 +0200)
committerEmmanuel Grumbach <emmanuel.grumbach@intel.com>
Mon, 24 Nov 2014 06:30:14 +0000 (08:30 +0200)
Add a flow that handles the requests to cancel the roc time event,
that has been triggered via the aux framework.

The roc for bss is different than the roc for p2p devices, and  is done
via the aux framework using the aux queue, thus requires a different flow
to cancel the time event.

Signed-off-by: Matti Gottlieb <matti.gottlieb@intel.com>
Reviewed-by: Johannes Berg <johannes.berg@intel.com>
Signed-off-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
drivers/net/wireless/iwlwifi/mvm/mac80211.c
drivers/net/wireless/iwlwifi/mvm/time-event.c
drivers/net/wireless/iwlwifi/mvm/time-event.h

index d37d5a8b383ee85f8b0d1efda893e5042381549d..f3379d76f3db75ee3c2300d6ef0828307cabfe8a 100644 (file)
@@ -2652,7 +2652,7 @@ static int iwl_mvm_cancel_roc(struct ieee80211_hw *hw)
        IWL_DEBUG_MAC80211(mvm, "enter\n");
 
        mutex_lock(&mvm->mutex);
-       iwl_mvm_stop_p2p_roc(mvm);
+       iwl_mvm_stop_roc(mvm);
        mutex_unlock(&mvm->mutex);
 
        IWL_DEBUG_MAC80211(mvm, "leave\n");
index 6dfad230be5ed658f2cb3f295e71b43d724d293c..8cf246b695c45d5ab87183f53be00cd6a27191ab 100644 (file)
@@ -549,18 +549,11 @@ void iwl_mvm_protect_session(struct iwl_mvm *mvm,
        }
 }
 
-/*
- * Explicit request to remove a time event. The removal of a time event needs to
- * be synchronized with the flow of a time event's end notification, which also
- * removes the time event from the op mode data structures.
- */
-void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
-                              struct iwl_mvm_vif *mvmvif,
-                              struct iwl_mvm_time_event_data *te_data)
+static bool __iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+                                       struct iwl_mvm_time_event_data *te_data,
+                                       u32 *uid)
 {
-       struct iwl_time_event_cmd time_cmd = {};
-       u32 id, uid;
-       int ret;
+       u32 id;
 
        /*
         * It is possible that by the time we got to this point the time
@@ -569,7 +562,7 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
        spin_lock_bh(&mvm->time_event_lock);
 
        /* Save time event uid before clearing its data */
-       uid = te_data->uid;
+       *uid = te_data->uid;
        id = te_data->id;
 
        /*
@@ -584,10 +577,59 @@ void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
         * send a removal command.
         */
        if (id == TE_MAX) {
-               IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", uid);
-               return;
+               IWL_DEBUG_TE(mvm, "TE 0x%x has already ended\n", *uid);
+               return false;
        }
 
+       return true;
+}
+
+/*
+ * Explicit request to remove a aux roc time event. The removal of a time
+ * event needs to be synchronized with the flow of a time event's end
+ * notification, which also removes the time event from the op mode
+ * data structures.
+ */
+static void iwl_mvm_remove_aux_roc_te(struct iwl_mvm *mvm,
+                                     struct iwl_mvm_vif *mvmvif,
+                                     struct iwl_mvm_time_event_data *te_data)
+{
+       struct iwl_hs20_roc_req aux_cmd = {};
+       u32 uid;
+       int ret;
+
+       if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
+               return;
+
+       aux_cmd.event_unique_id = cpu_to_le32(uid);
+       aux_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
+       aux_cmd.id_and_color =
+               cpu_to_le32(FW_CMD_ID_AND_COLOR(mvmvif->id, mvmvif->color));
+       IWL_DEBUG_TE(mvm, "Removing BSS AUX ROC TE 0x%x\n",
+                    le32_to_cpu(aux_cmd.event_unique_id));
+       ret = iwl_mvm_send_cmd_pdu(mvm, HOT_SPOT_CMD, 0,
+                                  sizeof(aux_cmd), &aux_cmd);
+
+       if (WARN_ON(ret))
+               return;
+}
+
+/*
+ * Explicit request to remove a time event. The removal of a time event needs to
+ * be synchronized with the flow of a time event's end notification, which also
+ * removes the time event from the op mode data structures.
+ */
+void iwl_mvm_remove_time_event(struct iwl_mvm *mvm,
+                              struct iwl_mvm_vif *mvmvif,
+                              struct iwl_mvm_time_event_data *te_data)
+{
+       struct iwl_time_event_cmd time_cmd = {};
+       u32 uid;
+       int ret;
+
+       if (!__iwl_mvm_remove_time_event(mvm, te_data, &uid))
+               return;
+
        /* When we remove a TE, the UID is to be set in the id field */
        time_cmd.id = cpu_to_le32(uid);
        time_cmd.action = cpu_to_le32(FW_CTXT_ACTION_REMOVE);
@@ -666,13 +708,17 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return iwl_mvm_time_event_send_add(mvm, vif, te_data, &time_cmd);
 }
 
-void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
+void iwl_mvm_stop_roc(struct iwl_mvm *mvm)
 {
        struct iwl_mvm_vif *mvmvif;
        struct iwl_mvm_time_event_data *te_data;
+       bool is_p2p = false;
 
        lockdep_assert_held(&mvm->mutex);
 
+       mvmvif = NULL;
+       spin_lock_bh(&mvm->time_event_lock);
+
        /*
         * Iterate over the list of time events and find the time event that is
         * associated with a P2P_DEVICE interface.
@@ -680,22 +726,41 @@ void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm)
         * event at any given time and this time event coresponds to a ROC
         * request
         */
-       mvmvif = NULL;
-       spin_lock_bh(&mvm->time_event_lock);
        list_for_each_entry(te_data, &mvm->time_event_list, list) {
-               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE) {
+               if (te_data->vif->type == NL80211_IFTYPE_P2P_DEVICE &&
+                   te_data->running) {
                        mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
-                       break;
+                       is_p2p = true;
+                       goto remove_te;
+               }
+       }
+
+       /*
+        * Iterate over the list of aux roc time events and find the time
+        * event that is associated with a BSS interface.
+        * This assumes that a BSS interface can have only a single time
+        * event at any given time and this time event coresponds to a ROC
+        * request
+        */
+       list_for_each_entry(te_data, &mvm->aux_roc_te_list, list) {
+               if (te_data->running) {
+                       mvmvif = iwl_mvm_vif_from_mac80211(te_data->vif);
+                       goto remove_te;
                }
        }
+
+remove_te:
        spin_unlock_bh(&mvm->time_event_lock);
 
        if (!mvmvif) {
-               IWL_WARN(mvm, "P2P_DEVICE no remain on channel event\n");
+               IWL_WARN(mvm, "No remain on channel event\n");
                return;
        }
 
-       iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+       if (is_p2p)
+               iwl_mvm_remove_time_event(mvm, mvmvif, te_data);
+       else
+               iwl_mvm_remove_aux_roc_te(mvm, mvmvif, te_data);
 
        iwl_mvm_roc_finished(mvm);
 }
index b350e47e19dab0606737a8950d7f2604e1f90016..6f6b35db3ab8eb9b71c8bf178d7227254340a41a 100644 (file)
@@ -182,14 +182,14 @@ int iwl_mvm_start_p2p_roc(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
                          int duration, enum ieee80211_roc_type type);
 
 /**
- * iwl_mvm_stop_p2p_roc - stop remain on channel for p2p device functionlity
+ * iwl_mvm_stop_roc - stop remain on channel functionality
  * @mvm: the mvm component
  *
  * This function can be used to cancel an ongoing ROC session.
  * The function is async, it will instruct the FW to stop serving the ROC
  * session, but will not wait for the actual stopping of the session.
  */
-void iwl_mvm_stop_p2p_roc(struct iwl_mvm *mvm);
+void iwl_mvm_stop_roc(struct iwl_mvm *mvm);
 
 /**
  * iwl_mvm_remove_time_event - general function to clean up of time event