aboutsummaryrefslogtreecommitdiffstats
path: root/net/mac80211/status.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/mac80211/status.c')
-rw-r--r--net/mac80211/status.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/net/mac80211/status.c b/net/mac80211/status.c
index 52a152b01b06..1ee85c402439 100644
--- a/net/mac80211/status.c
+++ b/net/mac80211/status.c
@@ -11,6 +11,7 @@
11 11
12#include <linux/export.h> 12#include <linux/export.h>
13#include <linux/etherdevice.h> 13#include <linux/etherdevice.h>
14#include <linux/time.h>
14#include <net/mac80211.h> 15#include <net/mac80211.h>
15#include <asm/unaligned.h> 16#include <asm/unaligned.h>
16#include "ieee80211_i.h" 17#include "ieee80211_i.h"
@@ -463,6 +464,77 @@ static void ieee80211_report_used_skb(struct ieee80211_local *local,
463} 464}
464 465
465/* 466/*
467 * Measure Tx frame completion and removal time for Tx latency statistics
468 * calculation. A single Tx frame latency should be measured from when it
469 * is entering the Kernel until we receive Tx complete confirmation indication
470 * and remove the skb.
471 */
472static void ieee80211_tx_latency_end_msrmnt(struct ieee80211_local *local,
473 struct sk_buff *skb,
474 struct sta_info *sta,
475 struct ieee80211_hdr *hdr)
476{
477 ktime_t skb_dprt;
478 struct timespec dprt_time;
479 u32 msrmnt;
480 u16 tid;
481 u8 *qc;
482 int i, bin_range_count, bin_count;
483 u32 *bin_ranges;
484 __le16 fc;
485 struct ieee80211_tx_latency_stat *tx_lat;
486 struct ieee80211_tx_latency_bin_ranges *tx_latency;
487 ktime_t skb_arv = skb->tstamp;
488
489 tx_latency = rcu_dereference(local->tx_latency);
490
491 /* assert Tx latency stats are enabled & frame arrived when enabled */
492 if (!tx_latency || !ktime_to_ns(skb_arv))
493 return;
494
495 fc = hdr->frame_control;
496
497 if (!ieee80211_is_data(fc)) /* make sure it is a data frame */
498 return;
499
500 /* get frame tid */
501 if (ieee80211_is_data_qos(hdr->frame_control)) {
502 qc = ieee80211_get_qos_ctl(hdr);
503 tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
504 } else {
505 tid = 0;
506 }
507
508 tx_lat = &sta->tx_lat[tid];
509
510 ktime_get_ts(&dprt_time); /* time stamp completion time */
511 skb_dprt = ktime_set(dprt_time.tv_sec, dprt_time.tv_nsec);
512 msrmnt = ktime_to_ms(ktime_sub(skb_dprt, skb_arv));
513
514 if (tx_lat->max < msrmnt) /* update stats */
515 tx_lat->max = msrmnt;
516 tx_lat->counter++;
517 tx_lat->sum += msrmnt;
518
519 if (!tx_lat->bins) /* bins not activated */
520 return;
521
522 /* count how many Tx frames transmitted with the appropriate latency */
523 bin_range_count = tx_latency->n_ranges;
524 bin_ranges = tx_latency->ranges;
525 bin_count = tx_lat->bin_count;
526
527 for (i = 0; i < bin_range_count; i++) {
528 if (msrmnt <= bin_ranges[i]) {
529 tx_lat->bins[i]++;
530 break;
531 }
532 }
533 if (i == bin_range_count) /* msrmnt is bigger than the biggest range */
534 tx_lat->bins[i]++;
535}
536
537/*
466 * Use a static threshold for now, best value to be determined 538 * Use a static threshold for now, best value to be determined
467 * by testing ... 539 * by testing ...
468 * Should it depend on: 540 * Should it depend on:
@@ -620,6 +692,12 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
620 692
621 if (acked) 693 if (acked)
622 sta->last_ack_signal = info->status.ack_signal; 694 sta->last_ack_signal = info->status.ack_signal;
695
696 /*
697 * Measure frame removal for tx latency
698 * statistics calculation
699 */
700 ieee80211_tx_latency_end_msrmnt(local, skb, sta, hdr);
623 } 701 }
624 702
625 rcu_read_unlock(); 703 rcu_read_unlock();