qcacmn: Enable TSO Stats for Lithium based products
Add support to account for TSO jumbo packets on the
Tx path and print the statistics using dumpStats 3.
Change-Id: I6cc446df5c84e3ac436d922935fcd559e0704ec5
CRs-Fixed: 2356244
diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h
index a2d096b..bfa2839 100644
--- a/dp/inc/cdp_txrx_ops.h
+++ b/dp/inc/cdp_txrx_ops.h
@@ -1165,7 +1165,8 @@
* @stats:
*/
struct cdp_mob_stats_ops {
- void (*clear_stats)(uint16_t bitmap);
+ QDF_STATUS
+ (*clear_stats)(struct cdp_soc *soc, uint8_t bitmap);
int (*stats)(uint8_t vdev_id, char *buffer, unsigned buf_len);
};
diff --git a/dp/inc/cdp_txrx_stats.h b/dp/inc/cdp_txrx_stats.h
index 69814a0..d367e02 100644
--- a/dp/inc/cdp_txrx_stats.h
+++ b/dp/inc/cdp_txrx_stats.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2016-2017 The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2017,2019 The Linux Foundation. All rights reserved.
*
* Permission to use, copy, modify, and/or distribute this software for
* any purpose with or without fee is hereby granted, provided that the
@@ -25,22 +25,23 @@
#define _CDP_TXRX_STATS_H_
#include <cdp_txrx_ops.h>
-static inline void
-cdp_clear_stats(ol_txrx_soc_handle soc, uint16_t bitmap)
+static inline QDF_STATUS
+cdp_clear_stats(ol_txrx_soc_handle soc, uint8_t bitmap)
{
if (!soc || !soc->ops) {
QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG,
"%s: Invalid Instance", __func__);
QDF_BUG(0);
- return;
+ return QDF_STATUS_E_INVAL;
}
if (!soc->ops->mob_stats_ops ||
!soc->ops->mob_stats_ops->clear_stats)
- return;
+ return QDF_STATUS_E_INVAL;
- soc->ops->mob_stats_ops->clear_stats(bitmap);
+ return soc->ops->mob_stats_ops->clear_stats((struct cdp_soc *)soc,
+ bitmap);
}
static inline int
diff --git a/dp/inc/cdp_txrx_stats_struct.h b/dp/inc/cdp_txrx_stats_struct.h
index ca32697..9a86e2e 100644
--- a/dp/inc/cdp_txrx_stats_struct.h
+++ b/dp/inc/cdp_txrx_stats_struct.h
@@ -23,6 +23,11 @@
*/
#ifndef _CDP_TXRX_STATS_STRUCT_H_
#define _CDP_TXRX_STATS_STRUCT_H_
+
+#ifdef FEATURE_TSO_STATS
+#include <qdf_types.h>
+#endif /* FEATURE_TSO_STATS */
+
#define TXRX_STATS_LEVEL_OFF 0
#define TXRX_STATS_LEVEL_BASIC 1
#define TXRX_STATS_LEVEL_FULL 2
@@ -171,6 +176,15 @@
RU_996_INDEX,
};
+#ifdef FEATURE_TSO_STATS
+/* Number of TSO Packet Statistics captured */
+#define CDP_MAX_TSO_PACKETS 5
+/* Information for Number of Segments for a TSO Packet captured */
+#define CDP_MAX_TSO_SEGMENTS 2
+/* Information for Number of Fragments for a TSO Segment captured */
+#define CDP_MAX_TSO_FRAGMENTS 6
+#endif /* FEATURE_TSO_STATS */
+
/* Different Packet Types */
enum cdp_packet_type {
DOT11_A = 0,
@@ -444,6 +458,68 @@
uint32_t mpdu_tried;
};
+#ifdef FEATURE_TSO_STATS
+/**
+ * struct cdp_tso_seg_histogram - Segment histogram for TCP Packets
+ * @segs_1: packets with single segments
+ * @segs_2_5: packets with 2-5 segments
+ * @segs_6_10: packets with 6-10 segments
+ * @segs_11_15: packets with 11-15 segments
+ * @segs_16_20: packets with 16-20 segments
+ * @segs_20_plus: packets with 20 plus segments
+ */
+struct cdp_tso_seg_histogram {
+ uint64_t segs_1;
+ uint64_t segs_2_5;
+ uint64_t segs_6_10;
+ uint64_t segs_11_15;
+ uint64_t segs_16_20;
+ uint64_t segs_20_plus;
+};
+
+/**
+ * struct cdp_tso_packet_info - Stats for TSO segments within a TSO packet
+ * @tso_seg: TSO Segment information
+ * @num_seg: Number of segments
+ * @tso_packet_len: Size of the tso packet
+ * @tso_seg_idx: segment number
+ */
+struct cdp_tso_packet_info {
+ struct qdf_tso_seg_t tso_seg[CDP_MAX_TSO_SEGMENTS];
+ uint8_t num_seg;
+ size_t tso_packet_len;
+ uint32_t tso_seg_idx;
+};
+
+/**
+ * struct cdp_tso_info - stats for tso packets
+ * @tso_packet_info: TSO packet information
+ */
+struct cdp_tso_info {
+ struct cdp_tso_packet_info tso_packet_info[CDP_MAX_TSO_PACKETS];
+};
+#endif /* FEATURE_TSO_STATS */
+
+/**
+ * struct cdp_tso_stats - TSO stats information
+ * @num_tso_pkts: Total number of TSO Packets
+ * @tso_comp: Total tso packet completions
+ * @dropped_host: TSO packets dropped by host
+ * @dropped_target: TSO packets_dropped by target
+ * @tso_info: Per TSO packet counters
+ * @seg_histogram: TSO histogram stats
+ */
+struct cdp_tso_stats {
+ struct cdp_pkt_info num_tso_pkts;
+ uint32_t tso_comp;
+ struct cdp_pkt_info dropped_host;
+ uint32_t dropped_target;
+#ifdef FEATURE_TSO_STATS
+ struct cdp_tso_info tso_info;
+ struct cdp_tso_seg_histogram seg_histogram;
+#endif /* FEATURE_TSO_STATS */
+};
+
/* struct cdp_tx_stats - tx stats
* @cdp_pkt_info comp_pkt: Pkt Info for which completions were received
* @cdp_pkt_info ucast: Unicast Packet Count
@@ -771,15 +847,6 @@
uint32_t invalid_raw_pkt_datatype;
} raw;
- /* TSO packets info */
- struct {
- uint32_t num_seg;
- struct cdp_pkt_info tso_pkt;
- struct cdp_pkt_info non_tso_pkts;
- struct cdp_pkt_info dropped_host;
- uint32_t dropped_target;
- } tso;
-
/* Scatter Gather packet info */
struct {
struct cdp_pkt_info sg_pkt;
@@ -821,17 +888,20 @@
uint32_t cce_classified;
uint32_t cce_classified_raw;
struct cdp_pkt_info sniffer_rcvd;
+ struct cdp_tso_stats tso_stats;
};
/* struct cdp_vdev_stats - vdev stats structure
* @tx_i: ingress tx stats
* @tx: cdp tx stats
* @rx: cdp rx stats
+ * @tso_stats: tso stats
*/
struct cdp_vdev_stats {
struct cdp_tx_ingress_stats tx_i;
struct cdp_tx_stats tx;
struct cdp_rx_stats rx;
+ struct cdp_tso_stats tso_stats;
};
/* struct cdp_peer_stats - peer stats structure
@@ -1381,6 +1451,8 @@
uint32_t data_rx_ppdu;
uint32_t data_users[OFDMA_NUM_USERS];
} ul_ofdma;
+
+ struct cdp_tso_stats tso_stats;
};
#ifdef QCA_ENH_V3_STATS_SUPPORT
diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h
index 14e0120..c669e9b 100644
--- a/dp/wifi3.0/dp_internal.h
+++ b/dp/wifi3.0/dp_internal.h
@@ -315,7 +315,6 @@
} \
} while (0)
-
#else
#define DP_HIST_INIT()
#define DP_HIST_PACKET_COUNT_INC(_pdev_id)
@@ -323,7 +322,134 @@
#define DP_RX_HISTOGRAM_UPDATE(_pdev, _p_cntrs)
#define DP_RX_HIST_STATS_PER_PDEV()
#define DP_TX_HIST_STATS_PER_PDEV()
-#endif
+#endif /* DISABLE_DP_STATS */
+
+#ifdef FEATURE_TSO_STATS
+/**
+ * dp_init_tso_stats() - Clear tso stats
+ * @pdev: pdev handle
+ *
+ * Return: None
+ */
+static inline
+void dp_init_tso_stats(struct dp_pdev *pdev)
+{
+ if (pdev) {
+ qdf_mem_zero(&((pdev)->stats.tso_stats),
+ sizeof((pdev)->stats.tso_stats));
+ qdf_atomic_init(&pdev->tso_idx);
+ }
+}
+
+/**
+ * dp_stats_tso_segment_histogram_update() - TSO Segment Histogram
+ * @pdev: pdev handle
+ * @_p_cntrs: number of tso segments for a tso packet
+ *
+ * Return: None
+ */
+void dp_stats_tso_segment_histogram_update(struct dp_pdev *pdev,
+ uint8_t _p_cntrs);
+
+/**
+ * dp_tso_segment_update() - Collect tso segment information
+ * @pdev: pdev handle
+ * @stats_idx: tso packet number
+ * @idx: tso segment number
+ * @seg: tso segment
+ *
+ * Return: None
+ */
+void dp_tso_segment_update(struct dp_pdev *pdev,
+ uint32_t stats_idx,
+ uint8_t idx,
+ struct qdf_tso_seg_t seg);
+
+/**
+ * dp_tso_packet_update() - TSO Packet information
+ * @pdev: pdev handle
+ * @stats_idx: tso packet number
+ * @msdu: nbuf handle
+ * @num_segs: tso segments
+ *
+ * Return: None
+ */
+void dp_tso_packet_update(struct dp_pdev *pdev, uint32_t stats_idx,
+ qdf_nbuf_t msdu, uint16_t num_segs);
+
+/**
+ * dp_tso_segment_stats_update() - TSO Segment stats
+ * @pdev: pdev handle
+ * @stats_seg: tso segment list
+ * @stats_idx: tso packet number
+ *
+ * Return: None
+ */
+void dp_tso_segment_stats_update(struct dp_pdev *pdev,
+ struct qdf_tso_seg_elem_t *stats_seg,
+ uint32_t stats_idx);
+
+/**
+ * dp_print_tso_stats() - dump tso statistics
+ * @soc:soc handle
+ * @level: verbosity level
+ *
+ * Return: None
+ */
+void dp_print_tso_stats(struct dp_soc *soc,
+ enum qdf_stats_verbosity_level level);
+
+/**
+ * dp_txrx_clear_tso_stats() - clear tso stats
+ * @soc: soc handle
+ *
+ * Return: None
+ */
+void dp_txrx_clear_tso_stats(struct dp_soc *soc);
+#else
+static inline
+void dp_init_tso_stats(struct dp_pdev *pdev)
+{
+}
+
+static inline
+void dp_stats_tso_segment_histogram_update(struct dp_pdev *pdev,
+ uint8_t _p_cntrs)
+{
+}
+
+static inline
+void dp_tso_segment_update(struct dp_pdev *pdev,
+ uint32_t stats_idx,
+ uint32_t idx,
+ struct qdf_tso_seg_t seg)
+{
+}
+
+static inline
+void dp_tso_packet_update(struct dp_pdev *pdev, uint32_t stats_idx,
+ qdf_nbuf_t msdu, uint16_t num_segs)
+{
+}
+
+static inline
+void dp_tso_segment_stats_update(struct dp_pdev *pdev,
+ struct qdf_tso_seg_elem_t *stats_seg,
+ uint32_t stats_idx)
+{
+}
+
+static inline
+void dp_print_tso_stats(struct dp_soc *soc,
+ enum qdf_stats_verbosity_level level)
+{
+}
+
+static inline
+void dp_txrx_clear_tso_stats(struct dp_soc *soc)
+{
+}
+#endif /* FEATURE_TSO_STATS */
#define DP_HTT_T2H_HP_PIPE 5
static inline void dp_update_pdev_stats(struct dp_pdev *tgtobj,
@@ -478,9 +604,6 @@
DP_STATS_AGGR_PKT(tgtobj, srcobj, tx_i.inspect_pkts);
DP_STATS_AGGR_PKT(tgtobj, srcobj, tx_i.raw.raw_pkt);
DP_STATS_AGGR(tgtobj, srcobj, tx_i.raw.dma_map_error);
- DP_STATS_AGGR_PKT(tgtobj, srcobj, tx_i.tso.tso_pkt);
- DP_STATS_AGGR(tgtobj, srcobj, tx_i.tso.dropped_host.num);
- DP_STATS_AGGR(tgtobj, srcobj, tx_i.tso.dropped_target);
DP_STATS_AGGR(tgtobj, srcobj, tx_i.sg.dropped_host.num);
DP_STATS_AGGR(tgtobj, srcobj, tx_i.sg.dropped_target);
DP_STATS_AGGR_PKT(tgtobj, srcobj, tx_i.sg.sg_pkt);
@@ -511,8 +634,6 @@
tgtobj->stats.tx_i.dropped.desc_na.num +
tgtobj->stats.tx_i.dropped.res_full;
- tgtobj->stats.tx_i.tso.num_seg =
- srcobj->stats.tx_i.tso.num_seg;
}
static inline void dp_update_vdev_stats(struct cdp_vdev_stats *tgtobj,
diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c
index dcb62cb..c397411 100644
--- a/dp/wifi3.0/dp_main.c
+++ b/dp/wifi3.0/dp_main.c
@@ -3598,6 +3598,8 @@
pdev->num_tx_allowed = wlan_cfg_get_num_tx_desc(soc->wlan_cfg_ctx);
+ dp_init_tso_stats(pdev);
+
if (dp_htt_ppdu_stats_attach(pdev) != QDF_STATUS_SUCCESS)
goto fail1;
@@ -8328,7 +8330,7 @@
break;
case CDP_TXRX_TSO_STATS:
- /* TODO: NOT IMPLEMENTED */
+ dp_print_tso_stats(soc, level);
break;
case CDP_DUMP_TX_FLOW_POOL_INFO:
@@ -8353,6 +8355,38 @@
}
+/**
+ * dp_txrx_clear_dump_stats() - clear dumpStats
+ * @soc- soc handle
+ * @value - stats option
+ *
+ * Return: 0 - Success, non-zero - failure
+ */
+static
+QDF_STATUS dp_txrx_clear_dump_stats(struct cdp_soc *psoc, uint8_t value)
+{
+ struct dp_soc *soc =
+ (struct dp_soc *)psoc;
+ QDF_STATUS status = QDF_STATUS_SUCCESS;
+
+ if (!soc) {
+ dp_err("%s: soc is NULL", __func__);
+ return QDF_STATUS_E_INVAL;
+ }
+
+ switch (value) {
+ case CDP_TXRX_TSO_STATS:
+ dp_txrx_clear_tso_stats(soc);
+ break;
+
+ default:
+ status = QDF_STATUS_E_INVAL;
+ break;
+ }
+
+ return status;
+}
+
#ifdef QCA_LL_TX_FLOW_CONTROL_V2
/**
* dp_update_flow_control_parameters() - API to store datapath
@@ -9531,7 +9565,7 @@
};
static struct cdp_mob_stats_ops dp_ops_mob_stats = {
- /* WIFI 3.0 DP NOT IMPLEMENTED YET */
+ .clear_stats = dp_txrx_clear_dump_stats,
};
/*
diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c
index 4077be0..8825af0 100644
--- a/dp/wifi3.0/dp_stats.c
+++ b/dp/wifi3.0/dp_stats.c
@@ -4624,6 +4624,62 @@
}
}
+#ifdef FEATURE_TSO_STATS
+/**
+ * dp_print_tso_seg_stats - tso segment stats
+ * @pdev: pdev handle
+ * @id: tso packet id
+ *
+ * Return: None
+ */
+static void dp_print_tso_seg_stats(struct dp_pdev *pdev, uint32_t id)
+{
+ uint8_t num_seg;
+ uint32_t segid;
+
+ /* TSO LEVEL 2 - SEGMENT INFO */
+ num_seg = pdev->stats.tso_stats.tso_info.tso_packet_info[id].num_seg;
+ for (segid = 0; segid < CDP_MAX_TSO_SEGMENTS && segid < num_seg; segid++) {
+ DP_PRINT_STATS(
+ "Segment id:[%u] fragments: %u | Segment Length %u | TCP Seq no.: %u | ip_id: %u",
+ segid,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].num_frags,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].total_len,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.tcp_seq_num,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.ip_id);
+ DP_PRINT_STATS(
+ "fin: %u syn: %u rst: %u psh: %u ack: %u urg: %u ece: %u cwr: %u ns: %u",
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.fin,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.syn,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.rst,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.psh,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.ack,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.urg,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.ece,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.cwr,
+ pdev->stats.tso_stats.tso_info.tso_packet_info[id]
+ .tso_seg[segid].tso_flags.ns);
+ }
+}
+#else
+static inline
+void dp_print_tso_seg_stats(struct dp_pdev *pdev, uint32_t id)
+{
+}
+#endif /* FEATURE_TSO_STATS */
+
/**
* dp_print_mon_ring_stats_from_hal() - Print stat for monitor rings based
* on target
@@ -5369,15 +5425,6 @@
pdev->stats.tx_i.sg.dropped_host.num);
DP_PRINT_STATS(" Dropped By Target = %d",
pdev->stats.tx_i.sg.dropped_target);
- DP_PRINT_STATS("TSO:");
- DP_PRINT_STATS(" Number of Segments = %d",
- pdev->stats.tx_i.tso.num_seg);
- DP_PRINT_STATS(" Packets = %d",
- pdev->stats.tx_i.tso.tso_pkt.num);
- DP_PRINT_STATS(" Bytes = %llu",
- pdev->stats.tx_i.tso.tso_pkt.bytes);
- DP_PRINT_STATS(" Dropped By Host = %d",
- pdev->stats.tx_i.tso.dropped_host.num);
DP_PRINT_STATS("Mcast Enhancement:");
DP_PRINT_STATS(" Packets = %d",
pdev->stats.tx_i.mcast_en.mcast_pkt.num);
@@ -5712,3 +5759,161 @@
DP_PRINT_STATS("REO Error(0-14):%s", reo_error);
}
+#ifdef FEATURE_TSO_STATS
+void dp_print_tso_stats(struct dp_soc *soc,
+ enum qdf_stats_verbosity_level level)
+{
+ uint8_t loop_pdev;
+ uint32_t id;
+ struct dp_pdev *pdev;
+
+ for (loop_pdev = 0; loop_pdev < soc->pdev_count; loop_pdev++) {
+ pdev = soc->pdev_list[loop_pdev];
+ DP_PRINT_STATS("TSO Statistics\n");
+ DP_PRINT_STATS(
+ "From stack: %d | Successful completions: %d | TSO Packets: %d | TSO Completions: %d",
+ pdev->stats.tx_i.rcvd.num,
+ pdev->stats.tx.tx_success.num,
+ pdev->stats.tso_stats.num_tso_pkts.num,
+ pdev->stats.tso_stats.tso_comp);
+
+ for (id = 0; id < CDP_MAX_TSO_PACKETS; id++) {
+ /* TSO LEVEL 1 - PACKET INFO */
+ DP_PRINT_STATS(
+ "Packet_Id:[%u]: Packet Length %lu | No. of segments: %u",
+ id,
+ pdev->stats.tso_stats.tso_info
+ .tso_packet_info[id].tso_packet_len,
+ pdev->stats.tso_stats.tso_info
+ .tso_packet_info[id].num_seg);
+ /* TSO LEVEL 2 */
+ if (level == QDF_STATS_VERBOSITY_LEVEL_HIGH)
+ dp_print_tso_seg_stats(pdev, id);
+ }
+
+ DP_PRINT_STATS(
+ "TSO Histogram: Single: %llu | 2-5 segs: %llu | 6-10: %llu segs | 11-15 segs: %llu | 16-20 segs: %llu | 20+ segs: %llu",
+ pdev->stats.tso_stats.seg_histogram.segs_1,
+ pdev->stats.tso_stats.seg_histogram.segs_2_5,
+ pdev->stats.tso_stats.seg_histogram.segs_6_10,
+ pdev->stats.tso_stats.seg_histogram.segs_11_15,
+ pdev->stats.tso_stats.seg_histogram.segs_16_20,
+ pdev->stats.tso_stats.seg_histogram.segs_20_plus);
+ }
+}
+
+void dp_stats_tso_segment_histogram_update(struct dp_pdev *pdev,
+ uint8_t _p_cntrs)
+{
+ if (_p_cntrs == 1) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_1, 1);
+ } else if (_p_cntrs >= 2 && _p_cntrs <= 5) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_2_5, 1);
+ } else if (_p_cntrs > 5 && _p_cntrs <= 10) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_6_10, 1);
+ } else if (_p_cntrs > 10 && _p_cntrs <= 15) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_11_15, 1);
+ } else if (_p_cntrs > 15 && _p_cntrs <= 20) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_16_20, 1);
+ } else if (_p_cntrs > 20) {
+ DP_STATS_INC(pdev,
+ tso_stats.seg_histogram.segs_20_plus, 1);
+ }
+}
+
+void dp_tso_segment_update(struct dp_pdev *pdev,
+ uint32_t stats_idx,
+ uint8_t idx,
+ struct qdf_tso_seg_t seg)
+{
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].num_frags,
+ seg.num_frags);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].total_len,
+ seg.total_len);
+
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.tso_enable,
+ seg.tso_flags.tso_enable);
+
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.fin,
+ seg.tso_flags.fin);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.syn,
+ seg.tso_flags.syn);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.rst,
+ seg.tso_flags.rst);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.psh,
+ seg.tso_flags.psh);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.ack,
+ seg.tso_flags.ack);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.urg,
+ seg.tso_flags.urg);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.ece,
+ seg.tso_flags.ece);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.cwr,
+ seg.tso_flags.cwr);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.ns,
+ seg.tso_flags.ns);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.tcp_seq_num,
+ seg.tso_flags.tcp_seq_num);
+ DP_STATS_UPD(pdev, tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_seg[idx].tso_flags.ip_id,
+ seg.tso_flags.ip_id);
+}
+
+void dp_tso_packet_update(struct dp_pdev *pdev, uint32_t stats_idx,
+ qdf_nbuf_t msdu, uint16_t num_segs)
+{
+ DP_STATS_UPD(pdev,
+ tso_stats.tso_info.tso_packet_info[stats_idx]
+ .num_seg,
+ num_segs);
+
+ DP_STATS_UPD(pdev,
+ tso_stats.tso_info.tso_packet_info[stats_idx]
+ .tso_packet_len,
+ qdf_nbuf_get_tcp_payload_len(msdu));
+}
+
+void dp_tso_segment_stats_update(struct dp_pdev *pdev,
+ struct qdf_tso_seg_elem_t *stats_seg,
+ uint32_t stats_idx)
+{
+ uint8_t tso_seg_idx = 0;
+
+ while (stats_seg && (tso_seg_idx < CDP_MAX_TSO_SEGMENTS)) {
+ dp_tso_segment_update(pdev, stats_idx,
+ tso_seg_idx,
+ stats_seg->seg);
+ ++tso_seg_idx;
+ stats_seg = stats_seg->next;
+ }
+}
+
+void dp_txrx_clear_tso_stats(struct dp_soc *soc)
+{
+ uint8_t loop_pdev;
+ struct dp_pdev *pdev;
+
+ for (loop_pdev = 0; loop_pdev < soc->pdev_count; loop_pdev++) {
+ pdev = soc->pdev_list[loop_pdev];
+ dp_init_tso_stats(pdev);
+ }
+}
+#endif /* FEATURE_TSO_STATS */
diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c
index 86e59dd..878d22a 100644
--- a/dp/wifi3.0/dp_tx.c
+++ b/dp/wifi3.0/dp_tx.c
@@ -215,6 +215,7 @@
dp_tso_num_seg_free(soc, tx_desc->pool_id,
tx_desc->tso_num_desc);
tx_desc->tso_num_desc = NULL;
+ DP_STATS_INC(tx_desc->pdev, tso_stats.tso_comp, 1);
}
/* Add the tso segment into the free list*/
@@ -497,6 +498,28 @@
}
}
+#ifdef FEATURE_TSO_STATS
+/**
+ * dp_tso_get_stats_idx: Retrieve the tso packet id
+ * @pdev - pdev handle
+ *
+ * Return: id
+ */
+static uint32_t dp_tso_get_stats_idx(struct dp_pdev *pdev)
+{
+ uint32_t stats_idx;
+
+ stats_idx = (((uint32_t)qdf_atomic_inc_return(&pdev->tso_idx))
+ % CDP_MAX_TSO_PACKETS);
+ return stats_idx;
+}
+#else
+static int dp_tso_get_stats_idx(struct dp_pdev *pdev)
+{
+ return 0;
+}
+#endif /* FEATURE_TSO_STATS */
+
/**
* dp_tx_free_remaining_tso_desc() - do dma unmap for tso segments if any,
* free the tso segments descriptor and
@@ -542,9 +565,9 @@
struct qdf_tso_seg_elem_t *tso_seg;
int num_seg = qdf_nbuf_get_tso_num_seg(msdu);
struct dp_soc *soc = vdev->pdev->soc;
+ struct dp_pdev *pdev = vdev->pdev;
struct qdf_tso_info_t *tso_info;
struct qdf_tso_num_seg_elem_t *tso_num_seg;
-
tso_info = &msdu_info->u.tso_info;
tso_info->curr_seg = NULL;
tso_info->tso_seg_list = NULL;
@@ -605,6 +628,12 @@
tso_info->curr_seg = tso_info->tso_seg_list;
+ tso_info->msdu_stats_idx = dp_tso_get_stats_idx(pdev);
+ dp_tso_packet_update(pdev, tso_info->msdu_stats_idx,
+ msdu, msdu_info->num_seg);
+ dp_tso_segment_stats_update(pdev, tso_info->tso_seg_list,
+ tso_info->msdu_stats_idx);
+ dp_stats_tso_segment_histogram_update(pdev, msdu_info->num_seg);
return QDF_STATUS_SUCCESS;
}
#else
@@ -2244,11 +2273,11 @@
*/
if (qdf_nbuf_is_tso(nbuf)) {
dp_verbose_debug("TSO frame %pK", vdev);
- DP_STATS_INC_PKT(vdev, tx_i.tso.tso_pkt, 1,
- qdf_nbuf_len(nbuf));
+ DP_STATS_INC_PKT(vdev->pdev, tso_stats.num_tso_pkts, 1,
+ qdf_nbuf_len(nbuf));
if (dp_tx_prepare_tso(vdev, nbuf, &msdu_info)) {
- DP_STATS_INC_PKT(vdev, tx_i.tso.dropped_host, 1,
+ DP_STATS_INC_PKT(vdev->pdev, tso_stats.dropped_host, 1,
qdf_nbuf_len(nbuf));
return nbuf;
}
diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h
index 7120cfd..bb5a562 100644
--- a/dp/wifi3.0/dp_types.h
+++ b/dp/wifi3.0/dp_types.h
@@ -1700,6 +1700,11 @@
*/
struct dp_rx_fst *rx_fst;
#endif /* WLAN_SUPPORT_RX_FLOW_TAG */
+
+#ifdef FEATURE_TSO_STATS
+ /* TSO Id to index into TSO packet information */
+ qdf_atomic_t tso_idx;
+#endif /* FEATURE_TSO_STATS */
};
struct dp_peer;
diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h
index 1c5f207..154d595 100644
--- a/qdf/inc/qdf_nbuf.h
+++ b/qdf/inc/qdf_nbuf.h
@@ -3149,6 +3149,17 @@
}
/**
+ * qdf_nbuf_get_tcp_payload_len() - function to return the tso payload len
+ * @nbuf: network buffer
+ *
+ * Return: size of the tso packet
+ */
+static inline size_t qdf_nbuf_get_tcp_payload_len(qdf_nbuf_t nbuf)
+{
+ return __qdf_nbuf_get_tcp_payload_len(nbuf);
+}
+
+/**
* qdf_nbuf_get_tso_num_seg() - function to calculate the number
* of TCP segments within the TSO jumbo packet
* @nbuf: TSO jumbo network buffer to be segmented
diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h
index 90bd851..9dae8a7 100644
--- a/qdf/linux/src/i_qdf_nbuf.h
+++ b/qdf/linux/src/i_qdf_nbuf.h
@@ -1453,9 +1453,23 @@
bool is_last_seg);
#ifdef FEATURE_TSO
+/**
+ * __qdf_nbuf_get_tcp_payload_len() - function to return the tcp
+ * payload len
+ * @skb: buffer
+ *
+ * Return: size
+ */
+size_t __qdf_nbuf_get_tcp_payload_len(struct sk_buff *skb);
uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb);
#else
+static inline
+size_t __qdf_nbuf_get_tcp_payload_len(struct sk_buff *skb)
+{
+ return 0;
+}
+
static inline uint32_t __qdf_nbuf_get_tso_num_seg(struct sk_buff *skb)
{
return 0;
diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c
index e7691b8..7feb537 100644
--- a/qdf/linux/src/qdf_nbuf.c
+++ b/qdf/linux/src/qdf_nbuf.c
@@ -3138,6 +3138,19 @@
}
qdf_export_symbol(__qdf_nbuf_unmap_tso_segment);
+size_t __qdf_nbuf_get_tcp_payload_len(struct sk_buff *skb)
+{
+ size_t packet_len;
+
+ packet_len = skb->len -
+ ((skb_transport_header(skb) - skb_mac_header(skb)) +
+ tcp_hdrlen(skb));
+
+ return packet_len;
+}
+
+qdf_export_symbol(__qdf_nbuf_get_tcp_payload_len);
+
/**
* __qdf_nbuf_get_tso_num_seg() - function to divide a TSO nbuf
* into segments