mac80211: move averaged values out of rx_stats
[cascardo/linux.git] / net / mac80211 / sta_info.c
index d20bab5..4f19505 100644 (file)
@@ -2,7 +2,7 @@
  * Copyright 2002-2005, Instant802 Networks, Inc.
  * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
  * Copyright 2013-2014  Intel Mobile Communications GmbH
- * Copyright (C) 2015 Intel Deutschland GmbH
+ * Copyright (C) 2015 - 2016 Intel Deutschland GmbH
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -341,9 +341,9 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->reserved_tid = IEEE80211_TID_UNRESERVED;
 
        sta->last_connected = ktime_get_seconds();
-       ewma_signal_init(&sta->rx_stats.avg_signal);
-       for (i = 0; i < ARRAY_SIZE(sta->rx_stats.chain_signal_avg); i++)
-               ewma_signal_init(&sta->rx_stats.chain_signal_avg[i]);
+       ewma_signal_init(&sta->rx_stats_avg.signal);
+       for (i = 0; i < ARRAY_SIZE(sta->rx_stats_avg.chain_signal); i++)
+               ewma_signal_init(&sta->rx_stats_avg.chain_signal[i]);
 
        if (local->ops->wake_tx_queue) {
                void *txq_data;
@@ -875,6 +875,13 @@ static int __must_check __sta_info_destroy_part1(struct sta_info *sta)
        set_sta_flag(sta, WLAN_STA_BLOCK_BA);
        ieee80211_sta_tear_down_BA_sessions(sta, AGG_STOP_DESTROY_STA);
 
+       /*
+        * Before removing the station from the driver there might be pending
+        * rx frames on RSS queues sent prior to the disassociation - wait for
+        * all such frames to be processed.
+        */
+       drv_sync_rx_queues(local, sta);
+
        ret = sta_info_hash_del(local, sta);
        if (WARN_ON(ret))
                return ret;
@@ -1760,6 +1767,31 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
 }
 EXPORT_SYMBOL(ieee80211_sta_set_buffered);
 
+static void
+ieee80211_recalc_p2p_go_ps_allowed(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       bool allow_p2p_go_ps = sdata->vif.p2p;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (sdata != sta->sdata ||
+                   !test_sta_flag(sta, WLAN_STA_ASSOC))
+                       continue;
+               if (!sta->sta.support_p2p_ps) {
+                       allow_p2p_go_ps = false;
+                       break;
+               }
+       }
+       rcu_read_unlock();
+
+       if (allow_p2p_go_ps != sdata->vif.bss_conf.allow_p2p_go_ps) {
+               sdata->vif.bss_conf.allow_p2p_go_ps = allow_p2p_go_ps;
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_P2P_PS);
+       }
+}
+
 int sta_info_move_state(struct sta_info *sta,
                        enum ieee80211_sta_state new_state)
 {
@@ -1821,12 +1853,16 @@ int sta_info_move_state(struct sta_info *sta,
                } else if (sta->sta_state == IEEE80211_STA_ASSOC) {
                        clear_bit(WLAN_STA_ASSOC, &sta->_flags);
                        ieee80211_recalc_min_chandef(sta->sdata);
+                       if (!sta->sta.support_p2p_ps)
+                               ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
                }
                break;
        case IEEE80211_STA_ASSOC:
                if (sta->sta_state == IEEE80211_STA_AUTH) {
                        set_bit(WLAN_STA_ASSOC, &sta->_flags);
                        ieee80211_recalc_min_chandef(sta->sdata);
+                       if (!sta->sta.support_p2p_ps)
+                               ieee80211_recalc_p2p_go_ps_allowed(sta->sdata);
                } else if (sta->sta_state == IEEE80211_STA_AUTHORIZED) {
                        if (sta->sdata->vif.type == NL80211_IFTYPE_AP ||
                            (sta->sdata->vif.type == NL80211_IFTYPE_AP_VLAN &&
@@ -2020,7 +2056,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 
                if (!(sinfo->filled & BIT(NL80211_STA_INFO_SIGNAL_AVG))) {
                        sinfo->signal_avg =
-                               -ewma_signal_read(&sta->rx_stats.avg_signal);
+                               -ewma_signal_read(&sta->rx_stats_avg.signal);
                        sinfo->filled |= BIT(NL80211_STA_INFO_SIGNAL_AVG);
                }
        }
@@ -2036,7 +2072,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
                        sinfo->chain_signal[i] =
                                sta->rx_stats.chain_signal_last[i];
                        sinfo->chain_signal_avg[i] =
-                               -ewma_signal_read(&sta->rx_stats.chain_signal_avg[i]);
+                               -ewma_signal_read(&sta->rx_stats_avg.chain_signal[i]);
                }
        }