mac80211: fix RX u64 stats consistency on 32-bit platforms
[cascardo/linux.git] / net / mac80211 / sta_info.c
index 0b50ae3..bdd303e 100644 (file)
@@ -335,6 +335,8 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
        sta->sdata = sdata;
        sta->rx_stats.last_rx = jiffies;
 
+       u64_stats_init(&sta->rx_stats.syncp);
+
        sta->sta_state = IEEE80211_STA_NONE;
 
        /* Mark TID as unreserved */
@@ -1971,6 +1973,41 @@ static void sta_set_rate_info_rx(struct sta_info *sta, struct rate_info *rinfo)
                sta_stats_decode_rate(sta->local, rate, rinfo);
 }
 
+static void sta_set_tidstats(struct sta_info *sta,
+                            struct cfg80211_tid_stats *tidstats,
+                            int tid)
+{
+       struct ieee80211_local *local = sta->local;
+
+       if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
+                       tidstats->rx_msdu = sta->rx_stats.msdu[tid];
+               } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
+
+               tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
+       }
+
+       if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
+               tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
+               tidstats->tx_msdu = sta->tx_stats.msdu[tid];
+       }
+
+       if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
+           ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+               tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
+               tidstats->tx_msdu_retries = sta->status_stats.msdu_retries[tid];
+       }
+
+       if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
+           ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
+               tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
+               tidstats->tx_msdu_failed = sta->status_stats.msdu_failed[tid];
+       }
+}
+
 void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
@@ -2025,7 +2062,12 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 
        if (!(sinfo->filled & (BIT(NL80211_STA_INFO_RX_BYTES64) |
                               BIT(NL80211_STA_INFO_RX_BYTES)))) {
-               sinfo->rx_bytes = sta->rx_stats.bytes;
+               unsigned int start;
+
+               do {
+                       start = u64_stats_fetch_begin(&sta->rx_stats.syncp);
+                       sinfo->rx_bytes = sta->rx_stats.bytes;
+               } while (u64_stats_fetch_retry(&sta->rx_stats.syncp, start));
                sinfo->filled |= BIT(NL80211_STA_INFO_RX_BYTES64);
        }
 
@@ -2097,33 +2139,7 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
                struct cfg80211_tid_stats *tidstats = &sinfo->pertid[i];
 
-               if (!(tidstats->filled & BIT(NL80211_TID_STATS_RX_MSDU))) {
-                       tidstats->filled |= BIT(NL80211_TID_STATS_RX_MSDU);
-                       tidstats->rx_msdu = sta->rx_stats.msdu[i];
-               }
-
-               if (!(tidstats->filled & BIT(NL80211_TID_STATS_TX_MSDU))) {
-                       tidstats->filled |= BIT(NL80211_TID_STATS_TX_MSDU);
-                       tidstats->tx_msdu = sta->tx_stats.msdu[i];
-               }
-
-               if (!(tidstats->filled &
-                               BIT(NL80211_TID_STATS_TX_MSDU_RETRIES)) &&
-                   ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
-                       tidstats->filled |=
-                               BIT(NL80211_TID_STATS_TX_MSDU_RETRIES);
-                       tidstats->tx_msdu_retries =
-                               sta->status_stats.msdu_retries[i];
-               }
-
-               if (!(tidstats->filled &
-                               BIT(NL80211_TID_STATS_TX_MSDU_FAILED)) &&
-                   ieee80211_hw_check(&local->hw, REPORTS_TX_ACK_STATUS)) {
-                       tidstats->filled |=
-                               BIT(NL80211_TID_STATS_TX_MSDU_FAILED);
-                       tidstats->tx_msdu_failed =
-                               sta->status_stats.msdu_failed[i];
-               }
+               sta_set_tidstats(sta, tidstats, i);
        }
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {