iwlwifi: mvm: query firmware for non-QoS seqno
authorJohannes Berg <johannes.berg@intel.com>
Thu, 8 Aug 2013 07:30:13 +0000 (09:30 +0200)
committerJohannes Berg <johannes.berg@intel.com>
Wed, 2 Oct 2013 16:00:32 +0000 (18:00 +0200)
Instead of keeping track of the non-QoS seqno for each station,
query the firmware when suspending, that's more efficient. As
this can fail, move the station ID mangling later in the code.

Reviewed-by: Emmanuel Grumbach <emmanuel.grumbach@intel.com>
Signed-off-by: Johannes Berg <johannes.berg@intel.com>
drivers/net/wireless/iwlwifi/mvm/d3.c
drivers/net/wireless/iwlwifi/mvm/fw-api.h
drivers/net/wireless/iwlwifi/mvm/ops.c
drivers/net/wireless/iwlwifi/mvm/sta.h
drivers/net/wireless/iwlwifi/mvm/tx.c

index 417639f77b01c8a9a166de79e4374cefa2313ba6..123a44f031a79cde0fb9ae29db32cfc3394e86ff 100644 (file)
@@ -793,6 +793,31 @@ static int iwl_mvm_d3_reprogram(struct iwl_mvm *mvm, struct ieee80211_vif *vif,
        return 0;
 }
 
+static int iwl_mvm_get_last_nonqos_seq(struct iwl_mvm *mvm,
+                                      struct ieee80211_vif *vif)
+{
+       struct iwl_host_cmd cmd = {
+               .id = NON_QOS_TX_COUNTER_CMD,
+               .flags = CMD_SYNC | CMD_WANT_SKB,
+       };
+       int err;
+       u32 size;
+
+       err = iwl_mvm_send_cmd(mvm, &cmd);
+       if (err)
+               return err;
+
+       size = le32_to_cpu(cmd.resp_pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
+       size -= sizeof(cmd.resp_pkt->hdr);
+       if (size != sizeof(__le32))
+               err = -EINVAL;
+       else
+               err = le32_to_cpup((__le32 *)cmd.resp_pkt->data);
+
+       iwl_free_resp(&cmd);
+       return err;
+}
+
 static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
                             struct cfg80211_wowlan *wowlan,
                             bool test)
@@ -829,7 +854,6 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
        };
        int ret, i;
        int len __maybe_unused;
-       u16 seq;
        u8 old_aux_sta_id, old_ap_sta_id = IWL_MVM_STATION_COUNT;
 
        if (!wowlan) {
@@ -872,26 +896,15 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
        mvm_ap_sta = (struct iwl_mvm_sta *)ap_sta->drv_priv;
 
-       /*
-        * The D3 firmware still hardcodes the AP station ID for the
-        * BSS we're associated with as 0. Store the real STA ID here
-        * and assign 0. When we leave this function, we'll restore
-        * the original value for the resume code.
-        */
-       old_ap_sta_id = mvm_ap_sta->sta_id;
-       mvm_ap_sta->sta_id = 0;
-       mvmvif->ap_sta_id = 0;
-
        /* TODO: wowlan_config_cmd.wowlan_ba_teardown_tids */
 
        wowlan_config_cmd.is_11n_connection = ap_sta->ht_cap.ht_supported;
 
-       /*
-        * We know the last used seqno, and the uCode expects to know that
-        * one, it will increment before TX.
-        */
-       seq = mvm_ap_sta->last_seq_ctl & IEEE80211_SCTL_SEQ;
-       wowlan_config_cmd.non_qos_seq = cpu_to_le16(seq);
+       /* Query the last used seqno and set it */
+       ret = iwl_mvm_get_last_nonqos_seq(mvm, vif);
+       if (ret < 0)
+               goto out_noreset;
+       wowlan_config_cmd.non_qos_seq = cpu_to_le16(ret);
 
        /*
         * For QoS counters, we store the one to use next, so subtract 0x10
@@ -899,7 +912,7 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
         * increment after using the value (i.e. store the next value to use).
         */
        for (i = 0; i < IWL_MAX_TID_COUNT; i++) {
-               seq = mvm_ap_sta->tid_data[i].seq_number;
+               u16 seq = mvm_ap_sta->tid_data[i].seq_number;
                seq -= 0x10;
                wowlan_config_cmd.qos_seq[i] = cpu_to_le16(seq);
        }
@@ -944,6 +957,16 @@ static int __iwl_mvm_suspend(struct ieee80211_hw *hw,
 
        iwl_trans_stop_device(mvm->trans);
 
+       /*
+        * The D3 firmware still hardcodes the AP station ID for the
+        * BSS we're associated with as 0. Store the real STA ID here
+        * and assign 0. When we leave this function, we'll restore
+        * the original value for the resume code.
+        */
+       old_ap_sta_id = mvm_ap_sta->sta_id;
+       mvm_ap_sta->sta_id = 0;
+       mvmvif->ap_sta_id = 0;
+
        /*
         * Set the HW restart bit -- this is mostly true as we're
         * going to load new firmware and reprogram that, though
index 66264cc5a0168d296ddac86be6617cd56f1d84d5..7dfa31affaee4bfced39c2a8974f5579dec756f0 100644 (file)
@@ -114,6 +114,7 @@ enum {
        TIME_EVENT_NOTIFICATION = 0x2a,
        BINDING_CONTEXT_CMD = 0x2b,
        TIME_QUOTA_CMD = 0x2c,
+       NON_QOS_TX_COUNTER_CMD = 0x2d,
 
        LQ_CMD = 0x4e,
 
index 2fcc8ef88a68d78fbc0f2225bbabc733d8d4e619..950e809621e7eb59a5861c153c1c9a4ed14a9b0f 100644 (file)
@@ -249,6 +249,7 @@ static const char *iwl_mvm_cmd_strings[REPLY_MAX] = {
        CMD(TIME_EVENT_NOTIFICATION),
        CMD(BINDING_CONTEXT_CMD),
        CMD(TIME_QUOTA_CMD),
+       CMD(NON_QOS_TX_COUNTER_CMD),
        CMD(RADIO_VERSION_NOTIFICATION),
        CMD(SCAN_REQUEST_CMD),
        CMD(SCAN_ABORT_CMD),
index 94b265eb32b82bfb7a5f467cef60963f5da8d252..4dfc359a4bdda187cbb1fdcbda8b4cfe112c78fd 100644 (file)
@@ -293,10 +293,6 @@ struct iwl_mvm_sta {
        struct iwl_lq_sta lq_sta;
        struct ieee80211_vif *vif;
 
-#ifdef CONFIG_PM_SLEEP
-       u16 last_seq_ctl;
-#endif
-
        /* Temporary, until the new TLC will control the Tx protection */
        s8 tx_protection;
        bool tt_tx_protection;
index e05440d90319b339f203a2f1ff9658a0d97f615e..1ef70d0bd9e2d85b5721ba6bda8e8a47ec4cd455 100644 (file)
@@ -668,10 +668,6 @@ static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
                        iwl_mvm_check_ratid_empty(mvm, sta, tid);
                        spin_unlock_bh(&mvmsta->lock);
                }
-
-#ifdef CONFIG_PM_SLEEP
-               mvmsta->last_seq_ctl = seq_ctl;
-#endif
        } else {
                sta = NULL;
                mvmsta = NULL;