From 8a4812f7fc1046897a11dc1421967282a68c2e05 Mon Sep 17 00:00:00 2001 From: Venkata Sharath Chandra Manchala Date: Fri, 5 Oct 2018 13:04:18 -0700 Subject: [PATCH] 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 --- dp/inc/cdp_txrx_ops.h | 3 +- dp/inc/cdp_txrx_stats.h | 13 +- dp/inc/cdp_txrx_stats_struct.h | 90 +++++++++++-- dp/wifi3.0/dp_internal.h | 135 ++++++++++++++++++-- dp/wifi3.0/dp_main.c | 38 +++++- dp/wifi3.0/dp_stats.c | 223 +++++++++++++++++++++++++++++++-- dp/wifi3.0/dp_tx.c | 37 +++++- dp/wifi3.0/dp_types.h | 5 + qdf/inc/qdf_nbuf.h | 11 ++ qdf/linux/src/i_qdf_nbuf.h | 14 +++ qdf/linux/src/qdf_nbuf.c | 13 ++ 11 files changed, 544 insertions(+), 38 deletions(-) diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index a2d096b1ff..bfa2839da0 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -1165,7 +1165,8 @@ struct cdp_peer_ops { * @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 69814a071e..d367e02f21 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 -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 ca326979d5..9a86e2e282 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 +#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 @@ enum cdp_ru_index { 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 @@ struct cdp_tx_pkt_info { 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 @@ struct cdp_tx_ingress_stats { 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 @@ struct cdp_tx_ingress_stats { 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 @@ struct cdp_pdev_stats { 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 14e0120c6a..c669e9bec2 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -315,7 +315,6 @@ while (0) } \ } while (0) - #else #define DP_HIST_INIT() #define DP_HIST_PACKET_COUNT_INC(_pdev_id) @@ -323,7 +322,134 @@ while (0) #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 @@ static inline void dp_update_pdev_ingress_stats(struct dp_pdev *tgtobj, 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 @@ static inline void dp_update_pdev_ingress_stats(struct dp_pdev *tgtobj, 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 dcb62cbc86..c397411253 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -3598,6 +3598,8 @@ static struct cdp_pdev *dp_pdev_attach_wifi3(struct cdp_soc_t *txrx_soc, 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 @@ static QDF_STATUS dp_txrx_dump_stats(void *psoc, uint16_t value, 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 @@ static QDF_STATUS dp_txrx_dump_stats(void *psoc, uint16_t value, } +/** + * 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_ocb_ops dp_ops_ocb = { }; 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 4077be00d3..8825af0555 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -4624,6 +4624,62 @@ dp_print_ring_stat_from_hal(struct dp_soc *soc, struct dp_srng *srng, } } +#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 @@ dp_print_pdev_tx_stats(struct dp_pdev *pdev) 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_soc_rx_stats(struct dp_soc *soc) 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 86e59ddc86..878d22ac95 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -215,6 +215,7 @@ static void dp_tx_tso_desc_release(struct dp_soc *soc, 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 @@ static void dp_tx_unmap_tso_seg_list( } } +#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 @@ static QDF_STATUS dp_tx_prepare_tso(struct dp_vdev *vdev, 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 @@ static QDF_STATUS dp_tx_prepare_tso(struct dp_vdev *vdev, 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 @@ qdf_nbuf_t dp_tx_send(struct cdp_vdev *vap_dev, qdf_nbuf_t nbuf) */ 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 7120cfd120..bb5a5626f6 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1700,6 +1700,11 @@ struct dp_pdev { */ 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 1c5f207a64..154d5952ef 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -3148,6 +3148,17 @@ static inline void qdf_nbuf_unmap_tso_segment(qdf_device_t osdev, return __qdf_nbuf_unmap_tso_segment(osdev, tso_seg, is_last_seg); } +/** + * 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 diff --git a/qdf/linux/src/i_qdf_nbuf.h b/qdf/linux/src/i_qdf_nbuf.h index 90bd851431..9dae8a7c25 100644 --- a/qdf/linux/src/i_qdf_nbuf.h +++ b/qdf/linux/src/i_qdf_nbuf.h @@ -1453,9 +1453,23 @@ void __qdf_nbuf_unmap_tso_segment(qdf_device_t osdev, 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 e7691b8642..7feb537e56 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -3138,6 +3138,19 @@ last_seg_free_first_frag: } 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