netfilter: nf_log: release skbuff on nlmsg put failure
[platform/adaptation/renesas_rcar/renesas_kernel.git] / net / mac80211 / status.c
index 52a152b..1ee85c4 100644 (file)
@@ -11,6 +11,7 @@
 
 #include <linux/export.h>
 #include <linux/etherdevice.h>
+#include <linux/time.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
 #include "ieee80211_i.h"
@@ -463,6 +464,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
 }
 
 /*
+ * Measure Tx frame completion and removal time for Tx latency statistics
+ * calculation. A single Tx frame latency should be measured from when it
+ * is entering the Kernel until we receive Tx complete confirmation indication
+ * and remove the skb.
+ */
+static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
+                                           struct sk_buff *skb,
+                                           struct sta_info *sta,
+                                           struct ieee80211_hdr *hdr)
+{
+       ktime_t skb_dprt;
+       struct timespec dprt_time;
+       u32 msrmnt;
+       u16 tid;
+       u8 *qc;
+       int i, bin_range_count, bin_count;
+       u32 *bin_ranges;
+       __le16 fc;
+       struct ieee80211_tx_latency_stat *tx_lat;
+       struct ieee80211_tx_latency_bin_ranges *tx_latency;
+       ktime_t skb_arv = skb->tstamp;
+
+       tx_latency = rcu_dereference(local->tx_latency);
+
+       /* assert Tx latency stats are enabled & frame arrived when enabled */
+       if (!tx_latency || !ktime_to_ns(skb_arv))
+               return;
+
+       fc = hdr->frame_control;
+
+       if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
+               return;
+
+       /* get frame tid */
+       if (ieee80211_is_data_qos(hdr->frame_control)) {
+               qc = ieee80211_get_qos_ctl(hdr);
+               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
+       } else {
+               tid = 0;
+       }
+
+       tx_lat = &sta->tx_lat[tid];
+
+       ktime_get_ts(&dprt_time); /* time stamp completion time */
+       skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);
+       msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));
+
+       if (tx_lat->max < msrmnt) /* update stats */
+               tx_lat->max = msrmnt;
+       tx_lat->counter++;
+       tx_lat->sum += msrmnt;
+
+       if (!tx_lat->bins) /* bins not activated */
+               return;
+
+       /* count how many Tx frames transmitted with the appropriate latency */
+       bin_range_count = tx_latency->n_ranges;
+       bin_ranges = tx_latency->ranges;
+       bin_count = tx_lat->bin_count;
+
+       for (i = 0; i < bin_range_count; i++) {
+               if (msrmnt <= bin_ranges[i]) {
+                       tx_lat->bins[i]++;
+                       break;
+               }
+       }
+       if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
+               tx_lat->bins[i]++;
+}
+
+/*
  * Use a static threshold for now, best value to be determined
  * by testing ...
  * Should it depend on:
@@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
 
                if (acked)
                        sta->last_ack_signal = info->status.ack_signal;
+
+               /*
+                * Measure frame removal for tx latency
+                * statistics calculation
+                */
+               ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
        }
 
        rcu_read_unlock();