From c99a7e3cb009878232e1c0dfa044c0c5b0c35d9b Mon Sep 17 00:00:00 2001 From: Alok Kumar Date: Tue, 17 Mar 2020 16:05:43 +0530 Subject: [PATCH] qcacld-3.0: Add API to get adapter based netif queue history Currently, netif queue history is displayed for each adapter by iterating over adapter list in the HDD context. But, this iteration is not safe when unregistration of netdev going in parallel in other thread. In case the adapter is removed, the iteration will result in NULL pointer dereference. Avoid iterating over adapter list, add call newly added API, which is adapter based, to get netif queue history. When iteration over adapter list is needed, call hdd_for_each_adapter_dev_held API. Change-Id: I45fd8cd80cf21931ee352d612b10752ef0837c06 CRs-Fixed: 2639882 --- core/hdd/inc/wlan_hdd_main.h | 11 ++ core/hdd/src/wlan_hdd_main.c | 170 +++++++++++++++------------ core/hdd/src/wlan_hdd_softap_tx_rx.c | 4 +- core/hdd/src/wlan_hdd_stats.c | 9 +- core/hdd/src/wlan_hdd_tx_rx.c | 8 +- core/hdd/src/wlan_hdd_wext.c | 4 +- 6 files changed, 122 insertions(+), 84 deletions(-) diff --git a/core/hdd/inc/wlan_hdd_main.h b/core/hdd/inc/wlan_hdd_main.h index c2fedf865fdf..897b9023d4ea 100644 --- a/core/hdd/inc/wlan_hdd_main.h +++ b/core/hdd/inc/wlan_hdd_main.h @@ -2979,6 +2979,17 @@ void wlan_hdd_clear_tx_rx_histogram(struct hdd_context *hdd_ctx); void wlan_hdd_display_netif_queue_history(struct hdd_context *hdd_ctx, enum qdf_stats_verbosity_level verb_lvl); + +/** + * wlan_hdd_display_adapter_netif_queue_history() - display adapter based netif + * queue history + * @adapter: hdd adapter + * + * Return: none + */ +void +wlan_hdd_display_adapter_netif_queue_history(struct hdd_adapter *adapter); + void wlan_hdd_clear_netif_queue_history(struct hdd_context *hdd_ctx); const char *hdd_get_fwpath(void); void hdd_indicate_mgmt_frame(tSirSmeMgmtFrameInd *frame_ind); diff --git a/core/hdd/src/wlan_hdd_main.c b/core/hdd/src/wlan_hdd_main.c index b533965a2cd1..6bcd4eb02f7b 100644 --- a/core/hdd/src/wlan_hdd_main.c +++ b/core/hdd/src/wlan_hdd_main.c @@ -9274,7 +9274,7 @@ hdd_display_netif_queue_history_compact(struct hdd_context *hdd_ctx) bytes_written = 0; - hdd_for_each_adapter(hdd_ctx, adapter) { + hdd_for_each_adapter_dev_held(hdd_ctx, adapter) { curr_time = qdf_system_ticks(); total = curr_time - adapter->start_time; delta = curr_time - adapter->last_time; @@ -9318,6 +9318,8 @@ hdd_display_netif_queue_history_compact(struct hdd_context *hdd_ctx) temp_str); adapter_num++; + /* dev_put has to be done here */ + dev_put(adapter->dev); } /* using QDF_TRACE to avoid printing function name */ @@ -9332,6 +9334,95 @@ hdd_display_netif_queue_history_compact(struct hdd_context *hdd_ctx) /* Max size of a single netdev tx queue state string. e.g. "1: 0x1" */ #define HDD_NETDEV_TX_Q_STATE_STRLEN 15 +/** + * wlan_hdd_display_adapter_netif_queue_stats() - display adapter based + * netif queue stats + * @adapter: hdd adapter + * + * Return: none + */ +static void +wlan_hdd_display_adapter_netif_queue_stats(struct hdd_adapter *adapter) +{ + int i; + qdf_time_t total, pause, unpause, curr_time, delta; + struct hdd_netif_queue_history *q_hist_ptr; + char q_status_buf[NUM_TX_QUEUES * HDD_NETDEV_TX_Q_STATE_STRLEN] = {0}; + + hdd_nofl_debug("Netif queue operation statistics:"); + hdd_nofl_debug("vdev_id %d device mode %d", + adapter->vdev_id, adapter->device_mode); + hdd_nofl_debug("Current pause_map %x", adapter->pause_map); + curr_time = qdf_system_ticks(); + total = curr_time - adapter->start_time; + delta = curr_time - adapter->last_time; + if (adapter->pause_map) { + pause = adapter->total_pause_time + delta; + unpause = adapter->total_unpause_time; + } else { + unpause = adapter->total_unpause_time + delta; + pause = adapter->total_pause_time; + } + hdd_nofl_debug("Total: %ums Pause: %ums Unpause: %ums", + qdf_system_ticks_to_msecs(total), + qdf_system_ticks_to_msecs(pause), + qdf_system_ticks_to_msecs(unpause)); + hdd_nofl_debug("reason_type: pause_cnt: unpause_cnt: pause_time"); + + for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { + qdf_time_t pause_delta = 0; + + if (adapter->pause_map & (1 << i)) + pause_delta = delta; + + /* using hdd_log to avoid printing function name */ + hdd_nofl_debug("%s: %d: %d: %ums", + hdd_reason_type_to_string(i), + adapter->queue_oper_stats[i].pause_count, + adapter->queue_oper_stats[i]. + unpause_count, + qdf_system_ticks_to_msecs( + adapter->queue_oper_stats[i]. + total_pause_time + pause_delta)); + } + + hdd_nofl_debug("Netif queue operation history: Total entries: %d current index %d(-1) time %u", + WLAN_HDD_MAX_HISTORY_ENTRY, + adapter->history_index, + qdf_system_ticks_to_msecs(qdf_system_ticks())); + + hdd_nofl_debug("%2s%20s%50s%30s%10s %s", + "#", "time(ms)", "action_type", "reason_type", + "pause_map", "netdev-queue-status"); + + for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) { + /* using hdd_log to avoid printing function name */ + if (adapter->queue_oper_history[i].time == 0) + continue; + q_hist_ptr = &adapter->queue_oper_history[i]; + wlan_hdd_dump_queue_history_state(q_hist_ptr, + q_status_buf, + sizeof(q_status_buf)); + hdd_nofl_debug("%2d%20u%50s%30s%10x %s", + i, qdf_system_ticks_to_msecs( + adapter->queue_oper_history[i].time), + hdd_action_type_to_string( + adapter->queue_oper_history[i]. + netif_action), + hdd_reason_type_to_string( + adapter->queue_oper_history[i]. + netif_reason), + adapter->queue_oper_history[i].pause_map, + q_status_buf); + } +} + +void +wlan_hdd_display_adapter_netif_queue_history(struct hdd_adapter *adapter) +{ + wlan_hdd_display_adapter_netif_queue_stats(adapter); +} + /** * wlan_hdd_display_netif_queue_history() - display netif queue history * @hdd_ctx: hdd context @@ -9342,86 +9433,21 @@ void wlan_hdd_display_netif_queue_history(struct hdd_context *hdd_ctx, enum qdf_stats_verbosity_level verb_lvl) { - int i; struct hdd_adapter *adapter = NULL; - qdf_time_t total, pause, unpause, curr_time, delta; - struct hdd_netif_queue_history *q_hist_ptr; - char q_status_buf[NUM_TX_QUEUES * HDD_NETDEV_TX_Q_STATE_STRLEN] = {0}; if (verb_lvl == QDF_STATS_VERBOSITY_LEVEL_LOW) { hdd_display_netif_queue_history_compact(hdd_ctx); return; } - hdd_for_each_adapter(hdd_ctx, adapter) { - if (adapter->vdev_id == CDP_INVALID_VDEV_ID) + hdd_for_each_adapter_dev_held(hdd_ctx, adapter) { + if (adapter->vdev_id == CDP_INVALID_VDEV_ID) { + dev_put(adapter->dev); continue; - hdd_nofl_debug("Netif queue operation statistics:"); - hdd_nofl_debug("vdev_id %d device mode %d", - adapter->vdev_id, adapter->device_mode); - hdd_nofl_debug("Current pause_map %x", adapter->pause_map); - curr_time = qdf_system_ticks(); - total = curr_time - adapter->start_time; - delta = curr_time - adapter->last_time; - if (adapter->pause_map) { - pause = adapter->total_pause_time + delta; - unpause = adapter->total_unpause_time; - } else { - unpause = adapter->total_unpause_time + delta; - pause = adapter->total_pause_time; - } - hdd_nofl_debug("Total: %ums Pause: %ums Unpause: %ums", - qdf_system_ticks_to_msecs(total), - qdf_system_ticks_to_msecs(pause), - qdf_system_ticks_to_msecs(unpause)); - hdd_nofl_debug("reason_type: pause_cnt: unpause_cnt: pause_time"); - - for (i = WLAN_CONTROL_PATH; i < WLAN_REASON_TYPE_MAX; i++) { - qdf_time_t pause_delta = 0; - - if (adapter->pause_map & (1 << i)) - pause_delta = delta; - - /* using hdd_log to avoid printing function name */ - hdd_nofl_debug("%s: %d: %d: %ums", - hdd_reason_type_to_string(i), - adapter->queue_oper_stats[i].pause_count, - adapter->queue_oper_stats[i]. - unpause_count, - qdf_system_ticks_to_msecs( - adapter->queue_oper_stats[i]. - total_pause_time + pause_delta)); - } - - hdd_nofl_debug("Netif queue operation history: Total entries: %d current index %d(-1) time %u", - WLAN_HDD_MAX_HISTORY_ENTRY, - adapter->history_index, - qdf_system_ticks_to_msecs(qdf_system_ticks())); - - hdd_nofl_debug("%2s%20s%50s%30s%10s %s", - "#", "time(ms)", "action_type", "reason_type", - "pause_map", "netdev-queue-status"); - - for (i = 0; i < WLAN_HDD_MAX_HISTORY_ENTRY; i++) { - /* using hdd_log to avoid printing function name */ - if (adapter->queue_oper_history[i].time == 0) - continue; - q_hist_ptr = &adapter->queue_oper_history[i]; - wlan_hdd_dump_queue_history_state(q_hist_ptr, - q_status_buf, - sizeof(q_status_buf)); - hdd_nofl_debug("%2d%20u%50s%30s%10x %s", - i, qdf_system_ticks_to_msecs( - adapter->queue_oper_history[i].time), - hdd_action_type_to_string( - adapter->queue_oper_history[i]. - netif_action), - hdd_reason_type_to_string( - adapter->queue_oper_history[i]. - netif_reason), - adapter->queue_oper_history[i].pause_map, - q_status_buf); } + wlan_hdd_display_adapter_netif_queue_stats(adapter); + /* dev_put has to be done here */ + dev_put(adapter->dev); } } diff --git a/core/hdd/src/wlan_hdd_softap_tx_rx.c b/core/hdd/src/wlan_hdd_softap_tx_rx.c index fb832c8c4a95..fbf873a63b9d 100644 --- a/core/hdd/src/wlan_hdd_softap_tx_rx.c +++ b/core/hdd/src/wlan_hdd_softap_tx_rx.c @@ -686,8 +686,8 @@ static void __hdd_softap_tx_timeout(struct net_device *dev) i, netif_tx_queue_stopped(txq), txq->trans_start); } - wlan_hdd_display_netif_queue_history(hdd_ctx, - QDF_STATS_VERBOSITY_LEVEL_HIGH); + wlan_hdd_display_adapter_netif_queue_history(adapter); + cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); QDF_TRACE(QDF_MODULE_ID_HDD_DATA, QDF_TRACE_LEVEL_DEBUG, "carrier state: %d", netif_carrier_ok(dev)); diff --git a/core/hdd/src/wlan_hdd_stats.c b/core/hdd/src/wlan_hdd_stats.c index 5c9825f6994e..9030cde8cf06 100644 --- a/core/hdd/src/wlan_hdd_stats.c +++ b/core/hdd/src/wlan_hdd_stats.c @@ -6078,15 +6078,17 @@ void wlan_hdd_display_txrx_stats(struct hdd_context *ctx) uint32_t total_rx_pkt, total_rx_dropped, total_rx_delv, total_rx_refused; - hdd_for_each_adapter(ctx, adapter) { + hdd_for_each_adapter_dev_held(ctx, adapter) { total_rx_pkt = 0; total_rx_dropped = 0; total_rx_delv = 0; total_rx_refused = 0; stats = &adapter->hdd_stats.tx_rx_stats; - if (adapter->vdev_id == INVAL_VDEV_ID) + if (adapter->vdev_id == INVAL_VDEV_ID) { + dev_put(adapter->dev); continue; + } hdd_debug("adapter: %u", adapter->vdev_id); for (; i < NUM_CPUS; i++) { @@ -6096,6 +6098,9 @@ void wlan_hdd_display_txrx_stats(struct hdd_context *ctx) total_rx_refused += stats->rx_refused[i]; } + /* dev_put has to be done here */ + dev_put(adapter->dev); + hdd_debug("TX - called %u, dropped %u orphan %u", stats->tx_called, stats->tx_dropped, stats->tx_orphaned); diff --git a/core/hdd/src/wlan_hdd_tx_rx.c b/core/hdd/src/wlan_hdd_tx_rx.c index 834b1f8c386b..cac63c7ca532 100644 --- a/core/hdd/src/wlan_hdd_tx_rx.c +++ b/core/hdd/src/wlan_hdd_tx_rx.c @@ -133,7 +133,6 @@ void hdd_tx_resume_timer_expired_handler(void *adapter_context) { struct hdd_adapter *adapter = (struct hdd_adapter *)adapter_context; void *soc = cds_get_context(QDF_MODULE_ID_SOC); - struct hdd_context *hdd_ctx = WLAN_HDD_GET_CTX(adapter); u32 p_qpaused; u32 np_qpaused; @@ -144,8 +143,7 @@ void hdd_tx_resume_timer_expired_handler(void *adapter_context) cdp_display_stats(soc, CDP_DUMP_TX_FLOW_POOL_INFO, QDF_STATS_VERBOSITY_LEVEL_LOW); - wlan_hdd_display_netif_queue_history(hdd_ctx, - QDF_STATS_VERBOSITY_LEVEL_LOW); + wlan_hdd_display_adapter_netif_queue_history(adapter); hdd_debug("Enabling queues"); spin_lock_bh(&adapter->pause_map_lock); p_qpaused = adapter->pause_map & BIT(WLAN_DATA_FLOW_CONTROL_PRIORITY); @@ -1246,8 +1244,8 @@ static void __hdd_tx_timeout(struct net_device *dev) hdd_debug("carrier state: %d", netif_carrier_ok(dev)); - wlan_hdd_display_netif_queue_history(hdd_ctx, - QDF_STATS_VERBOSITY_LEVEL_HIGH); + wlan_hdd_display_adapter_netif_queue_history(adapter); + cdp_dump_flow_pool_info(cds_get_context(QDF_MODULE_ID_SOC)); ++adapter->hdd_stats.tx_rx_stats.tx_timeout_cnt; diff --git a/core/hdd/src/wlan_hdd_wext.c b/core/hdd/src/wlan_hdd_wext.c index 4ef26d49f250..4941bc32d9fe 100644 --- a/core/hdd/src/wlan_hdd_wext.c +++ b/core/hdd/src/wlan_hdd_wext.c @@ -3263,9 +3263,7 @@ int hdd_wlan_dump_stats(struct hdd_adapter *adapter, int value) wlan_hdd_display_tx_rx_histogram(hdd_ctx); break; case CDP_HDD_NETIF_OPER_HISTORY: - wlan_hdd_display_netif_queue_history - (hdd_ctx, - QDF_STATS_VERBOSITY_LEVEL_HIGH); + wlan_hdd_display_adapter_netif_queue_history(adapter); break; case CDP_HIF_STATS: hdd_display_hif_stats();