diff --git a/core/dp/ol/inc/ol_txrx_ctrl_api.h b/core/dp/ol/inc/ol_txrx_ctrl_api.h index a5dbcacbf3..bb7339d4d9 100644 --- a/core/dp/ol/inc/ol_txrx_ctrl_api.h +++ b/core/dp/ol/inc/ol_txrx_ctrl_api.h @@ -69,6 +69,7 @@ #define WLAN_DUMP_TX_FLOW_POOL_INFO 5 #define WLAN_TXRX_DESC_STATS 6 #define WLAN_HIF_STATS 7 +#define WLAN_LRO_STATS 8 #define WLAN_SCHEDULER_STATS 21 #define WLAN_TX_QUEUE_STATS 22 #define WLAN_BUNDLE_STATS 23 diff --git a/core/hdd/inc/wlan_hdd_lro.h b/core/hdd/inc/wlan_hdd_lro.h index 760347cc2f..0eaecdba83 100644 --- a/core/hdd/inc/wlan_hdd_lro.h +++ b/core/hdd/inc/wlan_hdd_lro.h @@ -97,16 +97,62 @@ struct hdd_lro_desc_info { struct hdd_lro_desc_pool lro_desc_pool; }; +/** + * enum hdd_lro_pkt_aggr_bucket - idenitifies the bucket holding + * the count of the aggregated packets + * @HDD_LRO_BUCKET_0_7: identifies the packet count when the + * aggregate size is between 0 to 7 packets + * @HDD_LRO_BUCKET_8_15: identifies the packet count when the + * aggregate size is between 8 to 15 packets + * @HDD_LRO_BUCKET_16_23: identifies the packet count when the + * aggregate size is between 16 to 23 packets + * @HDD_LRO_BUCKET_24_31: identifies the packet count when the + * aggregate size is between 24 to 31 packets + * @HDD_LRO_BUCKET_32_39: identifies the packet count when the + * aggregate size is between 32 to 39 packets + * @HDD_LRO_BUCKET_40_47: identifies the packet count when the + * aggregate size is between 40 to 47 packets + * @HDD_LRO_BUCKET_48_OR_MORE: identifies the packet count when + * the aggregate size is 48 or more packets + * @HDD_LRO_BUCKET_MAX: identifies the packet count when the + * aggregate size is 48 or more packets + */ +enum hdd_lro_pkt_aggr_bucket { + HDD_LRO_BUCKET_0_7 = 0, + HDD_LRO_BUCKET_8_15 = 1, + HDD_LRO_BUCKET_16_23 = 2, + HDD_LRO_BUCKET_24_31 = 3, + HDD_LRO_BUCKET_32_39 = 4, + HDD_LRO_BUCKET_40_47 = 5, + HDD_LRO_BUCKET_48_OR_MORE = 6, + HDD_LRO_BUCKET_MAX = HDD_LRO_BUCKET_48_OR_MORE, +}; + +/** + * hdd_lro_stats - structure containing the LRO statistics + * information + * @pkt_aggr_hist: histogram of the number of aggregated packets + * @lro_eligible_tcp: number of LRO elgible TCP packets + * @lro_ineligible_tcp: number of LRO inelgible TCP packets + */ +struct hdd_lro_stats { + uint16_t pkt_aggr_hist[HDD_LRO_BUCKET_MAX + 1]; + uint32_t lro_eligible_tcp; + uint32_t lro_ineligible_tcp; +}; + /** * hdd_lro_s - LRO information per HDD adapter * @lro_mgr: LRO manager * @lro_desc_info: LRO descriptor information * @lro_mgr_arr_access_lock: Lock to access LRO manager array. + * @lro_stats: LRO statistics */ struct hdd_lro_s { struct net_lro_mgr *lro_mgr; struct hdd_lro_desc_info lro_desc_info; qdf_spinlock_t lro_mgr_arr_access_lock; + struct hdd_lro_stats lro_stats; }; int hdd_lro_init(hdd_context_t *hdd_ctx); @@ -121,6 +167,8 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, void hdd_lro_flush_all(hdd_context_t *hdd_ctx, hdd_adapter_t *adapter); + +void hdd_lro_display_stats(hdd_context_t *hdd_ctx); #else struct hdd_lro_s {}; @@ -142,6 +190,14 @@ static inline int hdd_lro_init(hdd_context_t *hdd_ctx) } static inline void hdd_lro_disable(hdd_context_t *hdd_ctx, - hdd_adapter_t *adapter){} + hdd_adapter_t *adapter) +{ + return; +} + +static inline void hdd_lro_display_stats(hdd_context_t *hdd_ctx) +{ + return; +} #endif /* FEATURE_LRO */ #endif /* __WLAN_HDD_LRO_H__ */ diff --git a/core/hdd/src/wlan_hdd_lro.c b/core/hdd/src/wlan_hdd_lro.c index a312b8c548..1f4a8f0256 100644 --- a/core/hdd/src/wlan_hdd_lro.c +++ b/core/hdd/src/wlan_hdd_lro.c @@ -53,6 +53,14 @@ (LRO_DESC | LRO_ELIGIBILITY_CHECKED | LRO_TCP_ACK_NUM | \ LRO_TCP_DATA_CSUM | LRO_TCP_SEQ_NUM | LRO_TCP_WIN) +#define LRO_HIST_UPDATE(lro_desc, adapter) \ + do { \ + uint8_t bucket = lro_desc->pkt_aggr_cnt >> 3; \ + if (unlikely(bucket > HDD_LRO_BUCKET_MAX)) \ + bucket = HDD_LRO_BUCKET_MAX; \ + adapter->lro_info.lro_stats.pkt_aggr_hist[bucket]++; \ + } while (0); + /** * hdd_lro_get_skb_header() - LRO callback function * @skb: network buffer @@ -260,7 +268,7 @@ static int hdd_lro_desc_find(hdd_adapter_t *adapter, qdf_spin_unlock_bh(&free_pool->lro_pool_lock); if (NULL == entry->lro_desc) { - hdd_err("entry->lro_desc is NULL!\n"); + hdd_err("entry->lro_desc is NULL!"); return -EINVAL; } @@ -421,6 +429,9 @@ static void hdd_lro_flush_pkt(struct net_lro_mgr *lro_mgr, lro_desc = hdd_lro_get_desc(lro_mgr, lro_mgr->lro_arr, iph, tcph); if (lro_desc) { + /* statistics */ + LRO_HIST_UPDATE(lro_desc, adapter); + hdd_lro_desc_free(lro_desc, adapter); lro_flush_desc(lro_mgr, lro_desc); } @@ -474,6 +485,8 @@ static void hdd_lro_flush(void *data) lro_flush_desc( hdd_lro->lro_mgr, &hdd_lro->lro_mgr->lro_arr[i]); + LRO_HIST_UPDATE((&hdd_lro->lro_mgr->lro_arr[i]), + adapter); } } qdf_spin_unlock_bh(&hdd_lro->lro_mgr_arr_access_lock); @@ -556,6 +569,7 @@ int hdd_lro_enable(hdd_context_t *hdd_ctx, hdd_lro = &adapter->lro_info; qdf_mem_zero((void *)hdd_lro, sizeof(struct hdd_lro_s)); + /* * Allocate all the LRO data structures at once and then carve * them up as needed @@ -693,12 +707,107 @@ enum hdd_lro_rx_status hdd_lro_rx(hdd_context_t *hdd_ctx, } status = HDD_LRO_RX; + adapter->lro_info.lro_stats.lro_eligible_tcp++; } else { hdd_lro_flush_pkt(adapter->lro_info.lro_mgr, iph, tcph, adapter); + adapter->lro_info.lro_stats.lro_ineligible_tcp++; } qdf_spin_unlock_bh( &hdd_lro->lro_mgr_arr_access_lock); } return status; } + +/** + * hdd_lro_bucket_to_string() - return string conversion of + * bucket + * @bucket: bucket + * + * This utility function helps log string conversion of bucket + * enum + * + * Return: string conversion of the LRO bucket, if match found; + * "Invalid" otherwise. + */ +static const char *hdd_lro_bucket_to_string(enum hdd_lro_pkt_aggr_bucket bucket) +{ + switch (bucket) { + CASE_RETURN_STRING(HDD_LRO_BUCKET_0_7); + CASE_RETURN_STRING(HDD_LRO_BUCKET_8_15); + CASE_RETURN_STRING(HDD_LRO_BUCKET_16_23); + CASE_RETURN_STRING(HDD_LRO_BUCKET_24_31); + CASE_RETURN_STRING(HDD_LRO_BUCKET_32_39); + CASE_RETURN_STRING(HDD_LRO_BUCKET_40_47); + CASE_RETURN_STRING(HDD_LRO_BUCKET_48_OR_MORE); + default: + return "Invalid"; + } +} + +/** + * wlan_hdd_display_lro_stats() - display LRO statistics + * @hdd_ctx: hdd context + * + * Return: none + */ +void hdd_lro_display_stats(hdd_context_t *hdd_ctx) +{ + + hdd_adapter_t *adapter = NULL; + hdd_adapter_list_node_t *adapter_node = NULL, *next = NULL; + QDF_STATUS status; + int i; + + if (!hdd_ctx->config->lro_enable) { + hdd_err("LRO Disabled"); + return; + } + + status = hdd_get_front_adapter(hdd_ctx, &adapter_node); + while (NULL != adapter_node && QDF_STATUS_SUCCESS == status) { + struct hdd_lro_stats *stats; + hdd_err("\nLRO statistics:"); + + adapter = adapter_node->pAdapter; + if (!adapter) { + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + continue; + } + + stats = &adapter->lro_info.lro_stats; + hdd_err("Session_id %d device mode %d", + adapter->sessionId, adapter->device_mode); + + if (NL80211_IFTYPE_STATION != adapter->wdev.iftype) { + hdd_err("No LRO on interface type %d", + adapter->wdev.iftype); + status = hdd_get_next_adapter(hdd_ctx, + adapter_node, &next); + adapter_node = next; + continue; + } + + for (i = 0; i <= HDD_LRO_BUCKET_MAX; i++) { + if (stats && stats->pkt_aggr_hist) + hdd_err("bucket %s: %d packets", + hdd_lro_bucket_to_string(i), + stats->pkt_aggr_hist[i]); + } + + hdd_err("LRO eligible TCP packets %d\n" + "LRO ineligible TCP packets %d", + stats->lro_eligible_tcp, stats->lro_ineligible_tcp); + + if (adapter->lro_info.lro_mgr) + hdd_err("LRO manager aggr %lu flushed %lu no desc %lu", + adapter->lro_info.lro_mgr->stats.aggregated, + adapter->lro_info.lro_mgr->stats.flushed, + adapter->lro_info.lro_mgr->stats.no_desc); + + status = hdd_get_next_adapter(hdd_ctx, adapter_node, &next); + adapter_node = next; + } +} diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index f81f9e1cce..42fd9fa3cc 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -94,6 +94,7 @@ #include "hif.h" #include "pld_common.h" #endif +#include "wlan_hdd_lro.h" #define HDD_FINISH_ULA_TIME_OUT 800 #define HDD_SET_MCBC_FILTERS_TO_FW 1 @@ -720,6 +721,9 @@ void hdd_wlan_dump_stats(hdd_adapter_t *adapter, int value) case WLAN_HIF_STATS: hdd_display_hif_stats(); break; + case WLAN_LRO_STATS: + hdd_lro_display_stats(hdd_ctx); + break; default: ol_txrx_display_stats(value); break;