From 99468025024f063702bef6093f2bbb7d0aefdc66 Mon Sep 17 00:00:00 2001 From: Yeshwanth Sriram Guntuka Date: Wed, 8 Sep 2021 11:52:13 +0530 Subject: [PATCH 1/8] qcacmn: Dump flow pool stats as part of periodic stats display Dump flow pool stats even for low verbosity level as part of periodic stats display. Change-Id: Iea59d20b0a81cfd0bfdac65ad54a11fa33f30f2f CRs-Fixed: 3031168 --- dp/wifi3.0/dp_internal.h | 12 +++++++++ dp/wifi3.0/dp_main.c | 17 +++++++++---- dp/wifi3.0/dp_stats.c | 2 ++ dp/wifi3.0/dp_tx.c | 1 + dp/wifi3.0/dp_tx_flow_control.c | 44 ++++++++++++++++++++++++++++++++- dp/wifi3.0/dp_types.h | 2 ++ qdf/inc/qdf_trace.h | 4 +-- qdf/linux/src/qdf_trace.c | 13 +++++++--- 8 files changed, 84 insertions(+), 11 deletions(-) diff --git a/dp/wifi3.0/dp_internal.h b/dp/wifi3.0/dp_internal.h index 0c631c17924a..22da8713a5cf 100644 --- a/dp/wifi3.0/dp_internal.h +++ b/dp/wifi3.0/dp_internal.h @@ -1837,8 +1837,20 @@ void dp_peer_stats_update_protocol_cnt(struct cdp_soc_t *soc, #ifdef QCA_LL_TX_FLOW_CONTROL_V2 void dp_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl); + +/** + * dp_tx_dump_flow_pool_info_compact() - dump flow pool info + * @soc: DP soc context + * + * Return: none + */ +void dp_tx_dump_flow_pool_info_compact(struct dp_soc *soc); int dp_tx_delete_flow_pool(struct dp_soc *soc, struct dp_tx_desc_pool_s *pool, bool force); +#else +static inline void dp_tx_dump_flow_pool_info_compact(struct dp_soc *soc) +{ +} #endif /* QCA_LL_TX_FLOW_CONTROL_V2 */ #ifdef QCA_OL_DP_SRNG_LOCK_LESS_ACCESS diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 4f907821a850..c1615ed0da86 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -7503,7 +7503,7 @@ QDF_STATUS dp_reset_monitor_mode(struct cdp_soc_t *soc_hdl, * * Return: outstanding tx */ -static uint32_t dp_get_tx_pending(struct cdp_pdev *pdev_handle) +static int32_t dp_get_tx_pending(struct cdp_pdev *pdev_handle) { struct dp_pdev *pdev = (struct dp_pdev *)pdev_handle; @@ -10085,6 +10085,8 @@ static QDF_STATUS dp_txrx_dump_stats(struct cdp_soc_t *psoc, uint16_t value, case CDP_DUMP_TX_FLOW_POOL_INFO: if (level == QDF_STATS_VERBOSITY_LEVEL_HIGH) cdp_dump_flow_pool_info((struct cdp_soc_t *)soc); + else + dp_tx_dump_flow_pool_info_compact(soc); break; case CDP_DP_NAPI_STATS: @@ -11559,6 +11561,7 @@ static QDF_STATUS dp_runtime_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) struct dp_soc *soc = cdp_soc_t_to_dp_soc(soc_hdl); struct dp_pdev *pdev; uint8_t i; + int32_t tx_pending; pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); if (!pdev) { @@ -11567,9 +11570,11 @@ static QDF_STATUS dp_runtime_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) } /* Abort if there are any pending TX packets */ - if (dp_get_tx_pending(dp_pdev_to_cdp_pdev(pdev)) > 0) { + tx_pending = dp_get_tx_pending(dp_pdev_to_cdp_pdev(pdev)); + if (tx_pending) { QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO, - FL("Abort suspend due to pending TX packets")); + FL("Abort suspend due to pending TX packets %d"), + tx_pending); /* perform a force flush if tx is pending */ for (i = 0; i < soc->num_tcl_data_rings; i++) { @@ -12042,6 +12047,7 @@ static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); int timeout = SUSPEND_DRAIN_WAIT; int drain_wait_delay = 50; /* 50 ms */ + int32_t tx_pending; if (qdf_unlikely(!pdev)) { dp_err("pdev is NULL"); @@ -12049,10 +12055,11 @@ static QDF_STATUS dp_bus_suspend(struct cdp_soc_t *soc_hdl, uint8_t pdev_id) } /* Abort if there are any pending TX packets */ - while (dp_get_tx_pending((struct cdp_pdev *)pdev) > 0) { + while ((tx_pending = dp_get_tx_pending((struct cdp_pdev *)pdev))) { qdf_sleep(drain_wait_delay); if (timeout <= 0) { - dp_err("TX frames are pending, abort suspend"); + dp_info("TX frames are pending %d, abort suspend", + tx_pending); return QDF_STATUS_E_TIMEOUT; } timeout = timeout - drain_wait_delay; diff --git a/dp/wifi3.0/dp_stats.c b/dp/wifi3.0/dp_stats.c index 86a3aa69f8bc..2d96e52c477c 100644 --- a/dp/wifi3.0/dp_stats.c +++ b/dp/wifi3.0/dp_stats.c @@ -5956,6 +5956,8 @@ void dp_txrx_path_stats(struct dp_soc *soc) pdev->stats.tx.dropped.fw_rem_notx); DP_PRINT_STATS("Invalid peer on tx path: %u", pdev->soc->stats.tx.tx_invalid_peer.num); + DP_PRINT_STATS("Tx desc freed in non-completion path: %u", + pdev->soc->stats.tx.tx_comp_exception); DP_PRINT_STATS("Tx packets sent per interrupt:"); DP_PRINT_STATS("Single Packet: %u", diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index 972fa3949b00..e54928cb66ca 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -4900,6 +4900,7 @@ more_data: !tx_desc->flags)) { dp_info_rl("Descriptor freed in vdev_detach %d", tx_desc_id); + DP_STATS_INC(soc, tx.tx_comp_exception, 1); continue; } diff --git a/dp/wifi3.0/dp_tx_flow_control.c b/dp/wifi3.0/dp_tx_flow_control.c index d14422294c4d..6d728d278d65 100644 --- a/dp/wifi3.0/dp_tx_flow_control.c +++ b/dp/wifi3.0/dp_tx_flow_control.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2015-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2015-2021 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 @@ -29,6 +29,8 @@ #include "dp_internal.h" #define INVALID_FLOW_ID 0xFF #define MAX_INVALID_BIN 3 +#define GLOBAL_FLOW_POOL_STATS_LEN 25 +#define FLOW_POOL_LOG_LEN 50 #ifdef QCA_AC_BASED_FLOW_CONTROL /** @@ -222,6 +224,46 @@ void dp_tx_dump_flow_pool_info(struct cdp_soc_t *soc_hdl) qdf_spin_unlock_bh(&soc->flow_pool_array_lock); } +void dp_tx_dump_flow_pool_info_compact(struct dp_soc *soc) +{ + struct dp_txrx_pool_stats *pool_stats = &soc->pool_stats; + struct dp_tx_desc_pool_s *pool = NULL; + char *comb_log_str; + uint32_t comb_log_str_size; + int bytes_written = 0; + int i; + + comb_log_str_size = GLOBAL_FLOW_POOL_STATS_LEN + + (FLOW_POOL_LOG_LEN * MAX_TXDESC_POOLS) + 1; + comb_log_str = qdf_mem_malloc(comb_log_str_size); + if (!comb_log_str) + return; + + bytes_written = qdf_snprintf(&comb_log_str[bytes_written], + comb_log_str_size, "G:(%d,%d,%d) ", + pool_stats->pool_map_count, + pool_stats->pool_unmap_count, + pool_stats->pkt_drop_no_pool); + + for (i = 0; i < MAX_TXDESC_POOLS; i++) { + pool = &soc->tx_desc[i]; + if (pool->status > FLOW_POOL_INVALID) + continue; + bytes_written += qdf_snprintf(&comb_log_str[bytes_written], + (bytes_written >= comb_log_str_size) ? 0 : + comb_log_str_size - bytes_written, + "| %d %d: (%d,%d,%d)", + pool->flow_pool_id, pool->status, + pool->pool_size, pool->avail_desc, + pool->pkt_drop_no_desc); + } + + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_INFO_HIGH, + "FLOW_POOL_STATS %s", comb_log_str); + + qdf_mem_free(comb_log_str); +} + /** * dp_tx_clear_flow_pool_stats() - clear flow pool statistics * diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 18bc9404d69d..2d3d0add270a 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -911,6 +911,8 @@ struct dp_soc_stats { uint32_t tx_comp_loop_pkt_limit_hit; /* Head pointer Out of sync at the end of dp_tx_comp_handler */ uint32_t hp_oos2; + /* tx desc freed as part of vdev detach */ + uint32_t tx_comp_exception; } tx; /* SOC level RX stats */ diff --git a/qdf/inc/qdf_trace.h b/qdf/inc/qdf_trace.h index f7bbe6a1717d..e60f4571de8c 100644 --- a/qdf/inc/qdf_trace.h +++ b/qdf/inc/qdf_trace.h @@ -1067,8 +1067,8 @@ enum qdf_dp_tx_rx_status qdf_dp_get_status_from_a_status(uint8_t status) void qdf_trace_display(void); -void __printf(3, 4) qdf_snprintf(char *str_buffer, unsigned int size, - char *str_format, ...); +int __printf(3, 4) qdf_snprintf(char *str_buffer, unsigned int size, + char *str_format, ...); #define QDF_SNPRINTF qdf_snprintf diff --git a/qdf/linux/src/qdf_trace.c b/qdf/linux/src/qdf_trace.c index db2746aa37fb..0b3e2dbd150d 100644 --- a/qdf/linux/src/qdf_trace.c +++ b/qdf/linux/src/qdf_trace.c @@ -110,11 +110,18 @@ static tp_qdf_dp_trace_cb qdf_dp_trace_cb_table[QDF_DP_TRACE_MAX + 1]; * string contains printf-like replacement parameters, which follow * this parameter in the variable argument list. * - * Return: None + * Return: num of bytes written to buffer */ -void qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...) +int qdf_snprintf(char *str_buffer, unsigned int size, char *str_format, ...) { - snprintf(str_buffer, size, str_format); + va_list args; + int i; + + va_start(args, str_format); + i = vsnprintf(str_buffer, size, str_format, args); + va_end(args); + + return i; } qdf_export_symbol(qdf_snprintf); From d0606448698e0fb891e6ba2183102155d0b6b4c0 Mon Sep 17 00:00:00 2001 From: Ashish Kumar Dhanotiya Date: Thu, 26 Aug 2021 19:45:33 +0530 Subject: [PATCH 2/8] qcacmn: Do not update dfs parameters for 6GHz frequencies 6GHz do not have any dfs channels so do not update dfs related parameters for 6GHz frequencies Change-Id: I791622ce4b401bca65f132665eb2a1ebd7c9e931 CRs-Fixed: 3020653 --- umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c b/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c index 236d342bf993..9e1db6c55676 100644 --- a/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c +++ b/umac/mlme/vdev_mgr/core/src/vdev_mgr_ops.c @@ -97,11 +97,10 @@ static bool vdev_mgr_is_opmode_sap_or_p2p_go(enum QDF_OPMODE op_mode) return (op_mode == QDF_SAP_MODE || op_mode == QDF_P2P_GO_MODE); } -static bool vdev_mgr_is_49G_5G_6G_chan_freq(uint16_t chan_freq) +static bool vdev_mgr_is_49G_5G_chan_freq(uint16_t chan_freq) { return WLAN_REG_IS_5GHZ_CH_FREQ(chan_freq) || - WLAN_REG_IS_49GHZ_FREQ(chan_freq) || - WLAN_REG_IS_6GHZ_CHAN_FREQ(chan_freq); + WLAN_REG_IS_49GHZ_FREQ(chan_freq); } #else static inline bool vdev_mgr_is_opmode_sap_or_p2p_go(enum QDF_OPMODE op_mode) @@ -109,7 +108,7 @@ static inline bool vdev_mgr_is_opmode_sap_or_p2p_go(enum QDF_OPMODE op_mode) return true; } -static inline bool vdev_mgr_is_49G_5G_6G_chan_freq(uint16_t chan_freq) +static inline bool vdev_mgr_is_49G_5G_chan_freq(uint16_t chan_freq) { return true; } @@ -151,7 +150,7 @@ static QDF_STATUS vdev_mgr_start_param_update( op_mode = wlan_vdev_mlme_get_opmode(vdev); if (vdev_mgr_is_opmode_sap_or_p2p_go(op_mode) && - vdev_mgr_is_49G_5G_6G_chan_freq(des_chan->ch_freq)) { + vdev_mgr_is_49G_5G_chan_freq(des_chan->ch_freq)) { tgt_dfs_set_current_channel_for_freq(pdev, des_chan->ch_freq, des_chan->ch_flags, des_chan->ch_flagext, From db60bc797a70d2192052ea89bce47e86c7b80e25 Mon Sep 17 00:00:00 2001 From: Liangwei Dong Date: Fri, 25 Sep 2020 12:13:19 +0800 Subject: [PATCH 3/8] qcacmn: Add host definition for target thermal throttle level Convert target thermal throttle level to host definition - enum thermal_throttle_level. Change-Id: I9914aaf56b781533565cd6a3f8b279ee67215c23 CRs-Fixed: 2786660 --- .../inc/wlan_thermal_public_struct.h | 36 +++++++++++++++++++ wmi/inc/wmi_unified_api.h | 6 ++-- wmi/inc/wmi_unified_priv.h | 2 +- wmi/src/wmi_unified_api.c | 3 +- wmi/src/wmi_unified_tlv.c | 30 +++++++++++++--- 5 files changed, 69 insertions(+), 8 deletions(-) create mode 100644 umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h diff --git a/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h b/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h new file mode 100644 index 000000000000..1e31dd4163ef --- /dev/null +++ b/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h @@ -0,0 +1,36 @@ +/* Copyright (c) 2020, 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 above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/** + * DOC: declare the thermal public structure + */ +#ifndef _WLAN_THERMAL_PUBLIC_STRUCT_H_ +#define _WLAN_THERMAL_PUBLIC_STRUCT_H_ + +/** + * enum thermal_throttle_level - firmware offload throttle level + * @THERMAL_FULLPERF: no any throtting + * @THERMAL_MITIGATION: throtting tx to do mitigation + * @THERMAL_SHUTOFF: shut down the tx completely + * @THERMAL_UNKNOWN: unknown level from target. + */ +enum thermal_throttle_level { + THERMAL_FULLPERF, + THERMAL_MITIGATION, + THERMAL_SHUTOFF, + THERMAL_UNKNOWN, +}; + +#endif /* _WLAN_THERMAL_PUBLIC_STRUCT_H_ */ diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index e77a24aff90a..f709a9c2a057 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -32,6 +32,7 @@ #include "wlan_mgmt_txrx_utils_api.h" #include #include +#include "wlan_thermal_public_struct.h" #ifdef WLAN_POWER_MANAGEMENT_OFFLOAD #include "wmi_unified_pmo_api.h" #endif @@ -2965,13 +2966,14 @@ wmi_extract_chan_stats(wmi_unified_t wmi_handle, void *evt_buf, * @wmi_handle: wmi handle * @evt_buf: Pointer to event buffer * @temp: Pointer to hold extracted temperature - * @level: Pointer to hold extracted level + * @level: Pointer to hold extracted level in host enum * @pdev_id: Pointer to hold extracted pdev_id * * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure */ QDF_STATUS wmi_extract_thermal_stats(wmi_unified_t wmi_handle, void *evt_buf, - uint32_t *temp, uint32_t *level, + uint32_t *temp, + enum thermal_throttle_level *level, uint32_t *pdev_id); /** diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 22140bf64ead..3155c553c0c5 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1796,7 +1796,7 @@ QDF_STATUS (*extract_mib_stats)(wmi_unified_t wmi_handle, void *evt_buf, #endif QDF_STATUS (*extract_thermal_stats)(wmi_unified_t wmi_handle, void *evt_buf, - uint32_t *temp, uint32_t *level, uint32_t *pdev_id); + uint32_t *temp, enum thermal_throttle_level *level, uint32_t *pdev_id); QDF_STATUS (*extract_thermal_level_stats)(wmi_unified_t wmi_handle, void *evt_buf, uint8_t idx, uint32_t *levelcount, diff --git a/wmi/src/wmi_unified_api.c b/wmi/src/wmi_unified_api.c index c6057c075eea..471f836789de 100644 --- a/wmi/src/wmi_unified_api.c +++ b/wmi/src/wmi_unified_api.c @@ -2225,7 +2225,8 @@ wmi_extract_chan_stats(wmi_unified_t wmi_handle, void *evt_buf, } QDF_STATUS wmi_extract_thermal_stats(wmi_unified_t wmi_handle, void *evt_buf, - uint32_t *temp, uint32_t *level, + uint32_t *temp, + enum thermal_throttle_level *level, uint32_t *pdev_id) { if (wmi_handle->ops->extract_thermal_stats) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 350162cb2ebf..5be9d8979694 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -11457,19 +11457,40 @@ static QDF_STATUS extract_scan_radio_cap_service_ready_ext2_tlv( return QDF_STATUS_SUCCESS; } +/** + * wmi_tgt_thermal_level_to_host() - Convert target thermal level to host enum + * @level: target thermal level from WMI_THERM_THROT_STATS_EVENTID event + * + * Return: host thermal throt level + */ +static enum thermal_throttle_level +wmi_tgt_thermal_level_to_host(uint32_t level) +{ + switch (level) { + case WMI_THERMAL_FULLPERF: + return THERMAL_FULLPERF; + case WMI_THERMAL_MITIGATION: + return THERMAL_MITIGATION; + case WMI_THERMAL_SHUTOFF: + return THERMAL_SHUTOFF; + default: + return THERMAL_UNKNOWN; + } +} + /** * extract_thermal_stats_tlv() - extract thermal stats from event * @wmi_handle: wmi handle * @param evt_buf: Pointer to event buffer * @param temp: Pointer to hold extracted temperature - * @param level: Pointer to hold extracted level + * @param level: Pointer to hold extracted level in host enum * * Return: 0 for success or error code */ static QDF_STATUS extract_thermal_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t *temp, - uint32_t *level, uint32_t *pdev_id) + enum thermal_throttle_level *level, uint32_t *pdev_id) { WMI_THERM_THROT_STATS_EVENTID_param_tlvs *param_buf; wmi_therm_throt_stats_event_fixed_param *tt_stats_event; @@ -11480,12 +11501,13 @@ extract_thermal_stats_tlv(wmi_unified_t wmi_handle, return QDF_STATUS_E_INVAL; tt_stats_event = param_buf->fixed_param; - + wmi_debug("thermal temperature %d level %d", + tt_stats_event->temp, tt_stats_event->level); *pdev_id = wmi_handle->ops->convert_pdev_id_target_to_host( wmi_handle, tt_stats_event->pdev_id); *temp = tt_stats_event->temp; - *level = tt_stats_event->level; + *level = wmi_tgt_thermal_level_to_host(tt_stats_event->level); return QDF_STATUS_SUCCESS; } From ce92e8c74b06d6e91b9c47be22bf46f449e7fc30 Mon Sep 17 00:00:00 2001 From: Varsha Mishra Date: Thu, 10 Jun 2021 14:36:58 +0530 Subject: [PATCH 4/8] qcacmn: Drop non-eapol packets for unauthorized peer Until peer is authorized, drop non-eapol frames in rx error path. Change-Id: I339b9248b8ae63e4b6ab0268c4ed28130404ba33 --- dp/wifi3.0/dp_rx_err.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index fba5c29d46cb..74c40099c526 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -1140,6 +1140,7 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, qdf_ether_header_t *eh; struct hal_rx_msdu_metadata msdu_metadata; uint16_t sa_idx = 0; + bool is_eapol; qdf_nbuf_set_rx_chfrag_start(nbuf, hal_rx_msdu_end_first_msdu_get(soc->hal_soc, @@ -1294,6 +1295,22 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, /* IEEE80211_SEQ_MAX indicates invalid start_seq */ } + eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); + + if (!peer->authorize) { + is_eapol = qdf_nbuf_is_ipv4_eapol_pkt(nbuf) || + qdf_nbuf_is_ipv4_wapi_pkt(nbuf); + + if (is_eapol) { + if (qdf_mem_cmp(eh->ether_dhost, + &vdev->mac_addr.raw[0], + QDF_MAC_ADDR_SIZE)) + goto drop_nbuf; + } else { + goto drop_nbuf; + } + } + /* * Drop packets in this path if cce_match is found. Packets will come * in following path depending on whether tidQ is setup. @@ -1307,8 +1324,7 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, * to stack. */ if (qdf_unlikely(dp_rx_err_cce_drop(soc, vdev, nbuf, rx_tlv_hdr))) { - qdf_nbuf_free(nbuf); - return QDF_STATUS_E_FAILURE; + goto drop_nbuf; } if (qdf_unlikely(vdev->rx_decap_type == htt_cmn_pkt_type_raw)) { @@ -1335,7 +1351,6 @@ dp_rx_null_q_desc_handle(struct dp_soc *soc, qdf_nbuf_t nbuf, soc->hal_soc, rx_tlv_hdr) && (vdev->rx_decap_type == htt_cmn_pkt_type_ethernet))) { - eh = (qdf_ether_header_t *)qdf_nbuf_data(nbuf); DP_STATS_INC_PKT(peer, rx.multicast, 1, qdf_nbuf_len(nbuf)); From 540002f8863a7d8da9a96b546cd4481e186a247a Mon Sep 17 00:00:00 2001 From: Utkarsh Bhatnagar Date: Fri, 17 Sep 2021 12:03:49 +0530 Subject: [PATCH 5/8] qcacmn: Add support for Thermal Stats Events Add support for extracting Thermal Stats Events from thermal event TLV for FW event WMI_THERM_THROT_STATS_EVENTID. Also, added support for FW Cmd to request for Thermal Stats: WMI_REQUEST_THERMAL_STATS_CMDID Change-Id: I2bc80d082bda45e2255371bcb0c31d35d9806525 CRs-Fixed: 3016845 --- .../inc/wlan_thermal_public_struct.h | 26 ++++++- wmi/inc/wmi_unified_api.h | 5 ++ wmi/inc/wmi_unified_fwol_api.h | 18 ++++- wmi/inc/wmi_unified_param.h | 3 + wmi/inc/wmi_unified_priv.h | 11 ++- wmi/src/wmi_unified_api.c | 5 +- wmi/src/wmi_unified_fwol_api.c | 17 ++++- wmi/src/wmi_unified_fwol_tlv.c | 58 +++++++++++++++- wmi/src/wmi_unified_tlv.c | 67 ++++++++++++++++++- 9 files changed, 202 insertions(+), 8 deletions(-) diff --git a/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h b/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h index 1e31dd4163ef..1c579241639c 100644 --- a/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h +++ b/umac/thermal/dispatcher/inc/wlan_thermal_public_struct.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2020, The Linux Foundation. All rights reserved. +/* Copyright (c) 2020-2021, 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 above @@ -33,4 +33,28 @@ enum thermal_throttle_level { THERMAL_UNKNOWN, }; +enum thermal_stats_request_type { + thermal_stats_none = 0, + thermal_stats_init, + thermal_stats_req, + thermal_stats_clear, + thermal_stats_current_all_sensors_temp, +}; + +/** + * thermal_throt_level_stats - thermal throttle info from Target + * @start_temp_level: Start temperature range to capture thermal stats + * @end_temp_level: End temperature range to capture thermal stats + * @total_time_ms_lo: Start time for every thermal stats level in msec + * @total_time_ms_hi: End time for every thermal stats level in msec + * @num_entry: Thermal stats counter for every time temp level for this range + */ +struct thermal_throt_level_stats { + uint32_t start_temp_level; + uint32_t end_temp_level; + uint32_t total_time_ms_lo; + uint32_t total_time_ms_hi; + uint32_t num_entry; +}; + #endif /* _WLAN_THERMAL_PUBLIC_STRUCT_H_ */ diff --git a/wmi/inc/wmi_unified_api.h b/wmi/inc/wmi_unified_api.h index f709a9c2a057..6956d03061fb 100644 --- a/wmi/inc/wmi_unified_api.h +++ b/wmi/inc/wmi_unified_api.h @@ -2967,6 +2967,9 @@ wmi_extract_chan_stats(wmi_unified_t wmi_handle, void *evt_buf, * @evt_buf: Pointer to event buffer * @temp: Pointer to hold extracted temperature * @level: Pointer to hold extracted level in host enum + * @therm_throt_levels: Pointer to hold extracted number of level in thermal + * stats + * @tt_lvl_stats_event: Pointer to hold extracted thermal stats for each level * @pdev_id: Pointer to hold extracted pdev_id * * Return: QDF_STATUS_SUCCESS on success and QDF_STATUS_E_FAILURE for failure @@ -2974,6 +2977,8 @@ wmi_extract_chan_stats(wmi_unified_t wmi_handle, void *evt_buf, QDF_STATUS wmi_extract_thermal_stats(wmi_unified_t wmi_handle, void *evt_buf, uint32_t *temp, enum thermal_throttle_level *level, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_stats, uint32_t *pdev_id); /** diff --git a/wmi/inc/wmi_unified_fwol_api.h b/wmi/inc/wmi_unified_fwol_api.h index 478246ca3e64..d1546f839e5c 100644 --- a/wmi/inc/wmi_unified_fwol_api.h +++ b/wmi/inc/wmi_unified_fwol_api.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 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 @@ -87,4 +87,20 @@ wmi_unified_send_dscp_tip_map_cmd(struct wmi_unified *wmi_handle, } #endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ +/** + * wmi_unified_send_get_thermal_stats_cmd() - Send WMI get thermal stats req + * @wmi_handle: wmi handle + * @req_type: Request type + * @temp_offset: temperature offset for setting the range for thermal stats + + * Send WMI get thermal stats req command to firmware. + * + * Return: QDF_STATUS + */ +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS +wmi_unified_send_get_thermal_stats_cmd(struct wmi_unified *wmi_handle, + enum thermal_stats_request_type req_type, + uint8_t temp_offset); +#endif /* THERMAL_STATS_SUPPORT */ #endif /* _WMI_UNIFIED_FWOL_API_H_ */ diff --git a/wmi/inc/wmi_unified_param.h b/wmi/inc/wmi_unified_param.h index 6b6ccabdd271..85fbd47c86de 100644 --- a/wmi/inc/wmi_unified_param.h +++ b/wmi/inc/wmi_unified_param.h @@ -5257,6 +5257,9 @@ typedef enum { #ifdef FEATURE_WLAN_TDLS wmi_service_tdls_ax_support, #endif +#endif +#ifdef THERMAL_STATS_SUPPORT + wmi_service_thermal_stats_temp_range_supported, #endif wmi_services_max, } wmi_conv_service_ids; diff --git a/wmi/inc/wmi_unified_priv.h b/wmi/inc/wmi_unified_priv.h index 3155c553c0c5..6ed14454981a 100644 --- a/wmi/inc/wmi_unified_priv.h +++ b/wmi/inc/wmi_unified_priv.h @@ -1796,7 +1796,10 @@ QDF_STATUS (*extract_mib_stats)(wmi_unified_t wmi_handle, void *evt_buf, #endif QDF_STATUS (*extract_thermal_stats)(wmi_unified_t wmi_handle, void *evt_buf, - uint32_t *temp, enum thermal_throttle_level *level, uint32_t *pdev_id); + uint32_t *temp, enum thermal_throttle_level *level, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_temp_range_stats_event, + uint32_t *pdev_id); QDF_STATUS (*extract_thermal_level_stats)(wmi_unified_t wmi_handle, void *evt_buf, uint8_t idx, uint32_t *levelcount, @@ -2416,6 +2419,12 @@ QDF_STATUS (*send_dscp_tid_map_cmd)(wmi_unified_t wmi_handle, uint32_t *dscp_to_tid_map); #endif +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS (*send_get_thermal_stats_cmd)(wmi_unified_t wmi_handle, + enum thermal_stats_request_type req, + uint8_t temp_offset); +#endif /* THERMAL_STATS_SUPPORT */ + QDF_STATUS (*send_pdev_get_pn_cmd)(wmi_unified_t wmi_handle, struct peer_request_pn_param *pn_params); QDF_STATUS (*extract_get_pn_data)(wmi_unified_t wmi_handle, diff --git a/wmi/src/wmi_unified_api.c b/wmi/src/wmi_unified_api.c index 471f836789de..71733a726529 100644 --- a/wmi/src/wmi_unified_api.c +++ b/wmi/src/wmi_unified_api.c @@ -2227,11 +2227,14 @@ wmi_extract_chan_stats(wmi_unified_t wmi_handle, void *evt_buf, QDF_STATUS wmi_extract_thermal_stats(wmi_unified_t wmi_handle, void *evt_buf, uint32_t *temp, enum thermal_throttle_level *level, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_stats, uint32_t *pdev_id) { if (wmi_handle->ops->extract_thermal_stats) return wmi_handle->ops->extract_thermal_stats(wmi_handle, - evt_buf, temp, level, pdev_id); + evt_buf, temp, level, therm_throt_levels, + tt_stats, pdev_id); return QDF_STATUS_E_FAILURE; } diff --git a/wmi/src/wmi_unified_fwol_api.c b/wmi/src/wmi_unified_fwol_api.c index 7bca133af9f4..17f490b69454 100644 --- a/wmi/src/wmi_unified_fwol_api.c +++ b/wmi/src/wmi_unified_fwol_api.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 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 @@ -71,3 +71,18 @@ wmi_unified_send_dscp_tip_map_cmd(struct wmi_unified *wmi_handle, return QDF_STATUS_E_FAILURE; } #endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ + +#ifdef THERMAL_STATS_SUPPORT +QDF_STATUS +wmi_unified_send_get_thermal_stats_cmd(struct wmi_unified *wmi_handle, + enum thermal_stats_request_type req_type, + uint8_t temp_offset) +{ + if (wmi_handle->ops->send_get_thermal_stats_cmd) + return wmi_handle->ops->send_get_thermal_stats_cmd(wmi_handle, + req_type, + temp_offset); + + return QDF_STATUS_E_FAILURE; +} +#endif /* THERMAL_STATS_SUPPORT */ diff --git a/wmi/src/wmi_unified_fwol_tlv.c b/wmi/src/wmi_unified_fwol_tlv.c index 39751fd83d52..6c0900dbfffb 100644 --- a/wmi/src/wmi_unified_fwol_tlv.c +++ b/wmi/src/wmi_unified_fwol_tlv.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019-2020 The Linux Foundation. All rights reserved. + * Copyright (c) 2019-2021 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 @@ -207,11 +207,65 @@ static void wmi_fwol_attach_dscp_tid_tlv(struct wmi_ops *ops) } #endif /* WLAN_SEND_DSCP_UP_MAP_TO_FW */ +#ifdef THERMAL_STATS_SUPPORT +/** + * send_get_thermal_stats_cmd_tlv() - send get thermal stats cmd to fw + * @wmi_handle: wmi handle + * @req_type: req type + * @temp_offset: temperature offset + * + * Send WMI_REQUEST_THERMAL_STATS_CMDID to fw. + * + * Return: QDF_STATUS + */ +static QDF_STATUS +send_get_thermal_stats_cmd_tlv(wmi_unified_t wmi_handle, + enum thermal_stats_request_type req_type, + uint8_t temp_offset) +{ + wmi_buf_t buf; + wmi_thermal_stats_cmd_fixed_param *cmd; + uint16_t len = sizeof(*cmd); + QDF_STATUS ret; + + buf = wmi_buf_alloc(wmi_handle, len); + if (!buf) { + wmi_err("Failed to allocate wmi buffer"); + return QDF_STATUS_E_NOMEM; + } + + cmd = (wmi_thermal_stats_cmd_fixed_param *)wmi_buf_data(buf); + WMITLV_SET_HDR(&cmd->tlv_header, + WMITLV_TAG_STRUC_wmi_thermal_stats_cmd_fixed_param, + WMITLV_GET_STRUCT_TLVLEN + (wmi_thermal_stats_cmd_fixed_param)); + cmd->thermal_action = req_type; + cmd->thermal_offset = temp_offset; + ret = wmi_unified_cmd_send(wmi_handle, buf, len, + WMI_REQUEST_THERMAL_STATS_CMDID); + if (QDF_IS_STATUS_ERROR(ret)) { + wmi_err("Failed to send get thermal stats cmd = %d", ret); + wmi_buf_free(buf); + } + + return ret; +} + +static void wmi_fwol_attach_thermal_stats_tlv(struct wmi_ops *ops) +{ + ops->send_get_thermal_stats_cmd = send_get_thermal_stats_cmd_tlv; +} +#else +static void wmi_fwol_attach_thermal_stats_tlv(struct wmi_ops *ops) +{ +} +#endif /* THERMAL_STATS_SUPPORT */ + void wmi_fwol_attach_tlv(wmi_unified_t wmi_handle) { struct wmi_ops *ops = wmi_handle->ops; wmi_fwol_attach_elna_tlv(ops); wmi_fwol_attach_dscp_tid_tlv(ops); - + wmi_fwol_attach_thermal_stats_tlv(ops); } diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 5be9d8979694..3750ec17e938 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -11478,19 +11478,76 @@ wmi_tgt_thermal_level_to_host(uint32_t level) } } +#ifdef THERMAL_STATS_SUPPORT +static void +populate_thermal_stats(WMI_THERM_THROT_STATS_EVENTID_param_tlvs *param_buf, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_temp_range_stats) +{ + uint8_t lvl_idx; + wmi_therm_throt_stats_event_fixed_param *tt_stats_event; + wmi_thermal_throt_temp_range_stats *wmi_tt_stats; + + tt_stats_event = param_buf->fixed_param; + *therm_throt_levels = (tt_stats_event->therm_throt_levels > + WMI_THERMAL_STATS_TEMP_THRESH_LEVEL_MAX) ? + WMI_THERMAL_STATS_TEMP_THRESH_LEVEL_MAX : + tt_stats_event->therm_throt_levels; + + wmi_tt_stats = param_buf->temp_range_stats; + if (!wmi_tt_stats) { + wmi_err("wmi_tt_stats Null"); + return; + } + + for (lvl_idx = 0; lvl_idx < *therm_throt_levels; lvl_idx++) { + tt_temp_range_stats[lvl_idx].start_temp_level = + wmi_tt_stats[lvl_idx].start_temp_level; + tt_temp_range_stats[lvl_idx].end_temp_level = + wmi_tt_stats[lvl_idx].end_temp_level; + tt_temp_range_stats[lvl_idx].total_time_ms_lo = + wmi_tt_stats[lvl_idx].total_time_ms_lo; + tt_temp_range_stats[lvl_idx].total_time_ms_hi = + wmi_tt_stats[lvl_idx].total_time_ms_hi; + tt_temp_range_stats[lvl_idx].num_entry = + wmi_tt_stats[lvl_idx].num_entry; + wmi_debug("level %d, start temp %d, end temp %d, total time low %d, total time high %d, counter %d", + lvl_idx, wmi_tt_stats[lvl_idx].start_temp_level, + wmi_tt_stats[lvl_idx].end_temp_level, + wmi_tt_stats[lvl_idx].total_time_ms_lo, + wmi_tt_stats[lvl_idx].total_time_ms_hi, + wmi_tt_stats[lvl_idx].num_entry); + } +} +#else +static void +populate_thermal_stats(WMI_THERM_THROT_STATS_EVENTID_param_tlvs *param_buf, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_temp_range_stats) +{ +} +#endif + /** * extract_thermal_stats_tlv() - extract thermal stats from event * @wmi_handle: wmi handle * @param evt_buf: Pointer to event buffer * @param temp: Pointer to hold extracted temperature * @param level: Pointer to hold extracted level in host enum + * @param therm_throt_levels: Pointer to hold extracted thermal throttle temp + * range + * @param tt_temp_range_stats_event: Pointer to hold extracted thermal stats for + * every level * * Return: 0 for success or error code */ static QDF_STATUS extract_thermal_stats_tlv(wmi_unified_t wmi_handle, void *evt_buf, uint32_t *temp, - enum thermal_throttle_level *level, uint32_t *pdev_id) + enum thermal_throttle_level *level, + uint32_t *therm_throt_levels, + struct thermal_throt_level_stats *tt_temp_range_stats_event, + uint32_t *pdev_id) { WMI_THERM_THROT_STATS_EVENTID_param_tlvs *param_buf; wmi_therm_throt_stats_event_fixed_param *tt_stats_event; @@ -11509,6 +11566,10 @@ extract_thermal_stats_tlv(wmi_unified_t wmi_handle, *temp = tt_stats_event->temp; *level = wmi_tgt_thermal_level_to_host(tt_stats_event->level); + if (tt_stats_event->therm_throt_levels) + populate_thermal_stats(param_buf, therm_throt_levels, + tt_temp_range_stats_event); + return QDF_STATUS_SUCCESS; } @@ -15781,6 +15842,10 @@ static void populate_tlv_service(uint32_t *wmi_service) #endif wmi_service[wmi_service_ampdu_tx_buf_size_256_support] = WMI_SERVICE_AMPDU_TX_BUF_SIZE_256_SUPPORT; +#ifdef THERMAL_STATS_SUPPORT + wmi_service[wmi_service_thermal_stats_temp_range_supported] = + WMI_SERVICE_THERMAL_THROT_STATS_TEMP_RANGE_SUPPORT; +#endif } /** From 41fd3bd485388dfaec8fc4c5e5b2b1aace5e51bd Mon Sep 17 00:00:00 2001 From: Yu Tian Date: Tue, 31 Aug 2021 15:24:14 +0800 Subject: [PATCH 6/8] qcacmn: Correct pkt length check for scatter frame rx When a scattered frame is received, msdu length caclulation is incorrect, this leads to while loop can't break. At last skb, null pointer dereference happned. Change is aimed to correct the length caclulation. Change-Id: Ifb316f004ea5829b1130ce4c0fc9253134e26713 CRs-Fixed: 3025973 --- dp/wifi3.0/dp_rx.c | 80 ++++++++++++++++++++++++++++++++++++------ dp/wifi3.0/dp_rx.h | 3 +- dp/wifi3.0/dp_rx_err.c | 4 +-- 3 files changed, 74 insertions(+), 13 deletions(-) diff --git a/dp/wifi3.0/dp_rx.c b/dp/wifi3.0/dp_rx.c index 4b6615a75a63..9fd2fe6c87d0 100644 --- a/dp/wifi3.0/dp_rx.c +++ b/dp/wifi3.0/dp_rx.c @@ -1199,29 +1199,67 @@ static void dp_rx_fill_gro_info(struct dp_soc *soc, uint8_t *rx_tlv, * * @nbuf: pointer to msdu. * @mpdu_len: mpdu length + * @l3_pad_len: L3 padding length by HW * * Return: returns true if nbuf is last msdu of mpdu else retuns false. */ -static inline bool dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, uint16_t *mpdu_len) +static inline bool dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, + uint16_t *mpdu_len, + uint32_t l3_pad_len) { bool last_nbuf; + uint32_t pkt_hdr_size; - if (*mpdu_len > (RX_DATA_BUFFER_SIZE - RX_PKT_TLVS_LEN)) { + pkt_hdr_size = RX_PKT_TLVS_LEN + l3_pad_len; + + if ((*mpdu_len + pkt_hdr_size) > RX_DATA_BUFFER_SIZE) { qdf_nbuf_set_pktlen(nbuf, RX_DATA_BUFFER_SIZE); last_nbuf = false; + *mpdu_len -= (RX_DATA_BUFFER_SIZE - pkt_hdr_size); } else { - qdf_nbuf_set_pktlen(nbuf, (*mpdu_len + RX_PKT_TLVS_LEN)); + qdf_nbuf_set_pktlen(nbuf, (*mpdu_len + pkt_hdr_size)); last_nbuf = true; + *mpdu_len = 0; } - *mpdu_len -= (RX_DATA_BUFFER_SIZE - RX_PKT_TLVS_LEN); - return last_nbuf; } +/** + * dp_get_l3_hdr_pad_len() - get L3 header padding length. + * + * @soc: DP soc handle + * @nbuf: pointer to msdu. + * + * Return: returns padding length in bytes. + */ +static inline uint32_t dp_get_l3_hdr_pad_len(struct dp_soc *soc, + qdf_nbuf_t nbuf) +{ + uint32_t l3_hdr_pad = 0; + uint8_t *rx_tlv_hdr; + struct hal_rx_msdu_metadata msdu_metadata; + + while (nbuf) { + if (!qdf_nbuf_is_rx_chfrag_cont(nbuf)) { + /* scattered msdu end with continuation is 0 */ + rx_tlv_hdr = qdf_nbuf_data(nbuf); + hal_rx_msdu_metadata_get(soc->hal_soc, + rx_tlv_hdr, + &msdu_metadata); + l3_hdr_pad = msdu_metadata.l3_hdr_pad; + break; + } + nbuf = nbuf->next; + } + + return l3_hdr_pad; +} + /** * dp_rx_sg_create() - create a frag_list for MSDUs which are spread across * multiple nbufs. + * @soc: DP SOC handle * @nbuf: pointer to the first msdu of an amsdu. * * This function implements the creation of RX frag_list for cases @@ -1229,12 +1267,13 @@ static inline bool dp_rx_adjust_nbuf_len(qdf_nbuf_t nbuf, uint16_t *mpdu_len) * * Return: returns the head nbuf which contains complete frag_list. */ -qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) +qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf) { qdf_nbuf_t parent, frag_list, next = NULL; uint16_t frag_list_len = 0; uint16_t mpdu_len; bool last_nbuf; + uint32_t l3_hdr_pad_offset = 0; /* * Use msdu len got from REO entry descriptor instead since @@ -1242,6 +1281,7 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) * from REO descriptor is right for non-raw RX scatter msdu. */ mpdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); + /* * this is a case where the complete msdu fits in one single nbuf. * in this case HW sets both start and end bit and we only need to @@ -1254,6 +1294,8 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) return nbuf; } + l3_hdr_pad_offset = dp_get_l3_hdr_pad_len(soc, nbuf); + /* * This is a case where we have multiple msdus (A-MSDU) spread across * multiple nbufs. here we create a fraglist out of these nbufs. @@ -1273,7 +1315,24 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) * nbufs will form the frag_list of the parent nbuf. */ qdf_nbuf_set_rx_chfrag_start(parent, 1); - last_nbuf = dp_rx_adjust_nbuf_len(parent, &mpdu_len); + /* + * L3 header padding is only needed for the 1st buffer + * in a scattered msdu + */ + last_nbuf = dp_rx_adjust_nbuf_len(parent, &mpdu_len, + l3_hdr_pad_offset); + + /* + * HW issue: MSDU cont bit is set but reported MPDU length can fit + * in to single buffer + * + * Increment error stats and avoid SG list creation + */ + if (last_nbuf) { + qdf_nbuf_pull_head(parent, + RX_PKT_TLVS_LEN + l3_hdr_pad_offset); + return parent; + } /* * this is where we set the length of the fragments which are @@ -1281,7 +1340,7 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) * till we hit the last_nbuf of the list. */ do { - last_nbuf = dp_rx_adjust_nbuf_len(nbuf, &mpdu_len); + last_nbuf = dp_rx_adjust_nbuf_len(nbuf, &mpdu_len, 0); qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); frag_list_len += qdf_nbuf_len(nbuf); @@ -1298,7 +1357,8 @@ qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf) qdf_nbuf_append_ext_list(parent, frag_list, frag_list_len); parent->next = next; - qdf_nbuf_pull_head(parent, RX_PKT_TLVS_LEN); + qdf_nbuf_pull_head(parent, + RX_PKT_TLVS_LEN + l3_hdr_pad_offset); return parent; } @@ -2833,7 +2893,7 @@ done: qdf_nbuf_pull_head(nbuf, RX_PKT_TLVS_LEN); } else if (qdf_nbuf_is_rx_chfrag_cont(nbuf)) { msdu_len = QDF_NBUF_CB_RX_PKT_LEN(nbuf); - nbuf = dp_rx_sg_create(nbuf); + nbuf = dp_rx_sg_create(soc, nbuf); next = nbuf->next; if (qdf_nbuf_is_raw_frame(nbuf)) { diff --git a/dp/wifi3.0/dp_rx.h b/dp/wifi3.0/dp_rx.h index a5de867a7bbf..0818acf4aebf 100644 --- a/dp/wifi3.0/dp_rx.h +++ b/dp/wifi3.0/dp_rx.h @@ -676,6 +676,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, /** * dp_rx_sg_create() - create a frag_list for MSDUs which are spread across * multiple nbufs. + * @soc: core txrx main context * @nbuf: pointer to the first msdu of an amsdu. * * This function implements the creation of RX frag_list for cases @@ -683,7 +684,7 @@ dp_rx_wbm_err_process(struct dp_intr *int_ctx, struct dp_soc *soc, * * Return: returns the head nbuf which contains complete frag_list. */ -qdf_nbuf_t dp_rx_sg_create(qdf_nbuf_t nbuf); +qdf_nbuf_t dp_rx_sg_create(struct dp_soc *soc, qdf_nbuf_t nbuf); /* diff --git a/dp/wifi3.0/dp_rx_err.c b/dp/wifi3.0/dp_rx_err.c index 74c40099c526..dfd7f0b62e04 100644 --- a/dp/wifi3.0/dp_rx_err.c +++ b/dp/wifi3.0/dp_rx_err.c @@ -606,7 +606,7 @@ more_msdu_link_desc: rx_tlv_hdr_last = qdf_nbuf_data(tail_nbuf); if (qdf_unlikely(head_nbuf != tail_nbuf)) { - nbuf = dp_rx_sg_create(head_nbuf); + nbuf = dp_rx_sg_create(soc, head_nbuf); qdf_nbuf_set_is_frag(nbuf, 1); DP_STATS_INC(soc, rx.err.reo_err_oor_sg_count, 1); } @@ -2375,7 +2375,7 @@ done: * QCN9000 has this support */ if (qdf_nbuf_is_rx_chfrag_cont(nbuf)) { - nbuf = dp_rx_sg_create(nbuf); + nbuf = dp_rx_sg_create(soc, nbuf); next = nbuf->next; /* * SG error handling is not done correctly, From a2b6f199362b46aae7eb6f05fe391f276c2d85ef Mon Sep 17 00:00:00 2001 From: Surabhi Vishnoi Date: Tue, 14 Sep 2021 10:55:14 +0530 Subject: [PATCH 7/8] qcacmn: Fix possible OOB write in extract_time_sync_ftm_offset_event_tlv In extract_time_sync_ftm_offset_event_tlv there is a possible OOB write when value of num_qtime received from firmware is greater than FTM_TIME_SYNC_QTIME_PAIR_MAX. Fix is to add a sanity check for value of num_qtime received from firmware to avoid the OOB write. Change-Id: I6e57b1d716992d1a3c7d2f7ea911fefcbfbeff34 CRs-Fixed: 3033509 --- wmi/src/wmi_unified_tlv.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/wmi/src/wmi_unified_tlv.c b/wmi/src/wmi_unified_tlv.c index 3750ec17e938..76da4ea51604 100644 --- a/wmi/src/wmi_unified_tlv.c +++ b/wmi/src/wmi_unified_tlv.c @@ -14549,6 +14549,9 @@ extract_time_sync_ftm_offset_event_tlv(wmi_unified_t wmi, void *buf, param->vdev_id = resp_event->vdev_id; param->num_qtime = param_buf->num_audio_sync_q_master_slave_times; + if (param->num_qtime > FTM_TIME_SYNC_QTIME_PAIR_MAX) + param->num_qtime = FTM_TIME_SYNC_QTIME_PAIR_MAX; + q_pair = param_buf->audio_sync_q_master_slave_times; if (!q_pair) { wmi_err("Invalid q_master_slave_times buffer"); From 5e1b73532e6b7150038b6f156acb20d28ad3fa1f Mon Sep 17 00:00:00 2001 From: Wu Gao Date: Mon, 13 Sep 2021 22:32:42 +0800 Subject: [PATCH 8/8] qcacmn: Check smode value to avoid OOB read It doesn't check smode before used as array index, the potential risk is that OOB read or write once get invalid value from target. So, this change checks smode value before using. Change-Id: Ibc0625f43e31bc8b49694cca778726c6528290a8 CRs-Fixed: 3034136 --- target_if/spectral/target_if_spectral.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/target_if/spectral/target_if_spectral.c b/target_if/spectral/target_if_spectral.c index ff1880105719..c7ed9933d611 100644 --- a/target_if/spectral/target_if_spectral.c +++ b/target_if/spectral/target_if_spectral.c @@ -5594,6 +5594,12 @@ target_if_spectral_fw_param_event_handler(ol_scn_t scn, uint8_t *data_buf, return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); } + if (event_params.smode >= SPECTRAL_SCAN_MODE_MAX || + event_params.smode < SPECTRAL_SCAN_MODE_NORMAL) { + spectral_err("Invalid smode %d", event_params.smode); + return qdf_status_to_os_return(QDF_STATUS_E_FAILURE); + } + pdev = wlan_objmgr_get_pdev_by_id(psoc, event_params.pdev_id, WLAN_SPECTRAL_ID); if (!pdev) {