diff --git a/core/mac/inc/sir_api.h b/core/mac/inc/sir_api.h index 46e6ba8660..8a9e19450c 100644 --- a/core/mac/inc/sir_api.h +++ b/core/mac/inc/sir_api.h @@ -5082,6 +5082,450 @@ struct sir_wifi_iface_tx_fail { enum htt_tx_status status; }; +/** + * struct sir_wifi_chan_cca_stats - channal CCA stats + * @vdev_id: vdev ID + * @idle_time: percentage of idle time, no TX, no RX, no interference + * @tx_time: percentage of time transmitting packets + * @rx_in_bss_time: percentage of time receiving packets in current BSS + * @rx_out_bss_time: percentage of time receiving packets not in current BSS + * @rx_busy_time: percentage of time interference detected + * @rx_in_bad_cond_time: percentage of time receiving packets with errors + * or packets flagged as retransmission or seqnum discontinued. + * @tx_in_bad_cond_time: percentage of time the device transmitted packets + * that haven't been ACKed. + * @wlan_not_avail_time: percentage of time the chip is unable to + * work in normal conditions. + */ +struct sir_wifi_chan_cca_stats { + uint32_t vdev_id; + uint32_t idle_time; + uint32_t tx_time; + uint32_t rx_in_bss_time; + uint32_t rx_out_bss_time; + uint32_t rx_busy_time; + uint32_t rx_in_bad_cond_time; + uint32_t tx_in_bad_cond_time; + uint32_t wlan_not_avail_time; +}; + +#define WIFI_MAX_CHAINS 8 + +/** + * struct sir_wifi_peer_signal_stats - peer signal stats + * @vdev_id: vdev ID + * @peer_id: peer ID + * @per_ant_snr: per antenna SNR + * @nf: peer background noise + */ +struct sir_wifi_peer_signal_stats { + uint32_t vdev_id; + uint32_t peer_id; + + /* per antenna SNR in current bss */ + int32_t per_ant_snr[WIFI_MAX_CHAINS]; + + /* Background noise */ + int32_t nf[WIFI_MAX_CHAINS]; +}; + +#define WIFI_VDEV_NUM 4 +#define WFIF_MCS_NUM 10 +#define WIFI_AGGR_NUM 8 +#define WIFI_DELAY_SIZE 11 + +/** + * struct sir_wifi_tx - per AC tx stats + * @msdus: number of totoal MSDUs on MAC layer in the period + * @mpdus: number of totoal MPDUs on MAC layer in the period + * @ppdus: number of totoal PPDUs on PHY layer in the period + * @bytes: bytes of tx data on MAC layer in the period + * @drops: number of TX packets cancelled due to any reason in the period, + * such as WMM limitation/bandwidth limitation/radio congestion + * @drop_bytes: bytes of dropped TX packets in the period + * @retries: number of unacked transmissions of MPDUs + * @failed: number of packets have not been ACKed despite retried + * @aggr_len: length of the MPDU aggregation size buffer + * @mpdu_aggr_size: histogram of MPDU aggregation size + * @success_mcs_len: length of success mcs buffer + * @success_mcs: histogram of successed received MPDUs encoding rate + * @fail_mcs_len: length of failed mcs buffer + * @fail_mcs: histogram of failed received MPDUs encoding rate + * @delay_len: length of the delay histofram buffer + * @delay: histogram of delays on MAC layer + */ +struct sir_wifi_tx { + uint32_t msdus; + uint32_t mpdus; + uint32_t ppdus; + uint32_t bytes; + uint32_t drops; + uint32_t drop_bytes; + uint32_t retries; + uint32_t failed; + uint32_t aggr_len; + uint32_t *mpdu_aggr_size; + uint32_t success_mcs_len; + uint32_t *success_mcs; + uint32_t fail_mcs_len; + uint32_t *fail_mcs; + uint32_t delay_len; + uint32_t *delay; +}; + +/** + * struct sir_wifi_rx - per AC rx stats + * @mpdus: number of RX packets on MAC layer + * @bytes: bytes of RX packets on MAC layer + * @ppdus: number of RX packets on PHY layer + * @ppdu_bytes: bytes of RX packets on PHY layer + * @mpdu_lost: number of discontinuity in seqnum + * @mpdu_retry: number of RX packets flagged as retransmissions + * @mpdu_dup: number of RX packets identified as duplicates + * @mpdu_discard: number of RX packets discarded + * @aggr_len: length of MPDU aggregation histogram buffer + * @mpdu_aggr: histogram of MPDU aggregation size + * @mcs_len: length of mcs histogram buffer + * @mcs: histogram of encoding rate. + */ +struct sir_wifi_rx { + uint32_t mpdus; + uint32_t bytes; + uint32_t ppdus; + uint32_t ppdu_bytes; + uint32_t mpdu_lost; + uint32_t mpdu_retry; + uint32_t mpdu_dup; + uint32_t mpdu_discard; + uint32_t aggr_len; + uint32_t *mpdu_aggr; + uint32_t mcs_len; + uint32_t *mcs; +}; + +/** + * struct sir_wifi_ll_ext_wmm_ac_stats - stats for WMM AC + * @type: WMM AC type + * @tx_stats: pointer to TX stats + * @rx_stats: pointer to RX stats + */ +struct sir_wifi_ll_ext_wmm_ac_stats { + uint32_t type; + struct sir_wifi_tx *tx_stats; + struct sir_wifi_rx *rx_stats; +}; + +#define WIFI_INVALID_PEER_ID (-1) +#define WIFI_INVALID_VDEV_ID (-1) +#define WIFI_MAX_AC (4) + +/** + * struct sir_wifi_ll_ext_peer_stats - per peer stats + * @peer_id: peer ID + * @vdev_id: VDEV ID + * mac_address: MAC address + * @sta_ps_inds: how many times STAs go to sleep + * @sta_ps_durs: total sleep time of STAs (units in ms) + * @rx_probe_reqs: number of probe requests received + * @rx_oth_mgmts: number of other management frames received, + * not including probe requests + * @peer_signal_stat: signal stats + * @ac_stats: WMM BE/BK/VI/VO stats + */ +struct sir_wifi_ll_ext_peer_stats { + uint32_t peer_id; + uint32_t vdev_id; + tSirMacAddr mac_address; + uint32_t sta_ps_inds; + uint32_t sta_ps_durs; + uint32_t rx_probe_reqs; + uint32_t rx_oth_mgmts; + struct sir_wifi_peer_signal_stats peer_signal_stats; + struct sir_wifi_ll_ext_wmm_ac_stats ac_stats[WIFI_MAX_AC]; +}; + +/** + * struct sir_wifi_ll_ext_stats - link layer stats report + * @trigger_cond_id: Indicate what triggered this event. + * 1: timeout. 2: threshold + * @cca_chgd_bitmap: Bitmap to indicate changed channel CCA stats + * which exceeded the thresholds + * @sig_chgd_bitmap: Bitmap to indicate changed peer signal stats + * which exceeded the thresholds + * @tx_chgd_bitmap: Bitmap to indicate changed TX counters + * which exceeded the thresholds + * @rx_chgd_bitmap: Bitmap to indicate changed RX counters + * which exceeded the thresholds + * @chan_cca_stats: channel CCA stats + * @peer_signal_stats: peer signal stats + * @tx_mpdu_aggr_array_len: length of TX MPDU aggregation buffer + * @tx_succ_mcs_array_len: length of mcs buffer for ACKed MPDUs + * @tx_fail_mcs_array_len: length of mcs buffer for no-ACKed MPDUs + * @tx_delay_array_len: length of delay stats buffer + * @rx_mpdu_aggr_array_len: length of RX MPDU aggregation buffer + * @rx_mcs_array_len: length of RX mcs stats buffer + * @peer_stats: peer stats + * @cca: physical channel CCA stats + * @stats: pointer to stats data buffer. + * + * Structure of the whole statictics is like this: + * --------------------------------- + * | trigger_cond_i | + * +-------------------------------+ + * | cca_chgd_bitmap | + * +-------------------------------+ + * | sig_chgd_bitmap | + * +-------------------------------+ + * | tx_chgd_bitmap | + * +-------------------------------+ + * | rx_chgd_bitmap | + * +-------------------------------+ + * | peer_num | + * +-------------------------------+ + * | channel_num | + * +-------------------------------+ + * | tx_mpdu_aggr_array_len | + * +-------------------------------+ + * | tx_succ_mcs_array_len | + * +-------------------------------+ + * | tx_fail_mcs_array_len | + * +-------------------------------+ + * | tx_delay_array_len | + * +-------------------------------+ + * | rx_mpdu_aggr_array_len | + * +-------------------------------+ + * | rx_mcs_array_len | + * +-------------------------------+ + * | pointer to CCA stats | + * +-------------------------------+ + * | pointer to peer stats | + * +-------------------------------+ + * | CCA stats | + * +-------------------------------+ + * | peer_stats |----+ + * +-------------------------------+ | + * | per peer signals stats |<---+ + * | peer0 ~ peern | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | configurable for user layer. |<-+ | + * +-------------------------------+ | | + * | per peer tx stats |--+ | + * | BE | <--+ + * | BK | | + * | VI | | + * | VO | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | configurable for user layer. |<-+ | + * +-------------------------------+ | | + * | peer peer rx stats |--+ | + * | BE | <--+ + * | BE | + * | BK | + * | VI | + * | VO | + * --------------------------------- + */ +struct sir_wifi_ll_ext_stats { + uint32_t trigger_cond_id; + uint32_t cca_chgd_bitmap; + uint32_t sig_chgd_bitmap; + uint32_t tx_chgd_bitmap; + uint32_t rx_chgd_bitmap; + uint8_t peer_num; + uint8_t channel_num; + uint32_t tx_mpdu_aggr_array_len; + uint32_t tx_succ_mcs_array_len; + uint32_t tx_fail_mcs_array_len; + uint32_t tx_delay_array_len; + uint32_t rx_mpdu_aggr_array_len; + uint32_t rx_mcs_array_len; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + struct sir_wifi_chan_cca_stats *cca; + uint8_t stats[]; +}; + +/** + * struct sir_channel_cca_threshold - threshold for channel CCA + * @idle_time: idle time, no TX, no RX, no interference + * @tx_time: time transmitting packets + * @rx_in_bss_time: time receiving packets in current BSSs + * @rx_out_bss_time: time receiving packets not in current BSSs + * @rx_busy_time: time interference detected + * @rx_in_bad_cond_time: receiving packets with errors + * @tx_in_bad_cond_time: time transmitted packets not been ACKed + * @wlan_not_avail_time: wlan card cannot work + */ +struct sir_channel_cca_threshold { + uint32_t idle_time; + uint32_t tx_time; + uint32_t rx_in_bss_time; + uint32_t rx_out_bss_time; + uint32_t rx_busy_time; + uint32_t rx_in_bad_cond_time; + uint32_t tx_in_bad_cond_time; + uint32_t wlan_not_avail_time; +}; + +/** + * struct sir_signal_threshold - threshold for per peer sigbal + * @snr: signal to noise rate + * @nf: noise floor + */ +struct sir_signal_threshold { + uint32_t snr; + uint32_t nf; +}; + +/** + * struct sir_tx_threshold - threshold for TX + * @msdu: TX MSDUs on MAC layer + * @mpdu: TX MPDUs on MAC layer + * @ppdu: TX PPDUs on MAC layer + * @bytes: TX bytes on MAC layer + * @msdu_drop: drooped MSDUs + * @byte_drop: dropped Bytes + * @mpdu_retry: MPDU not acked + * @ppdu_fail: PPDUs which received no block ack + * @aggregation: aggregation size + * @succ_mcs: histogram of encoding rate for acked PPDUs + * @fail_mcs: histogram of encoding rate for no-acked PPDUs + */ +struct sir_tx_threshold { + uint32_t msdu; + uint32_t mpdu; + uint32_t ppdu; + uint32_t bytes; + uint32_t msdu_drop; + uint32_t byte_drop; + uint32_t mpdu_retry; + uint32_t mpdu_fail; + uint32_t ppdu_fail; + uint32_t aggregation; + uint32_t succ_mcs; + uint32_t fail_mcs; + uint32_t delay; +}; + +/** + * struct sir_rx_threshold - threshold for RX + * @mpdu: RX MPDUs on MAC layer + * @bytes: RX bytes on MAC layer + * @ppdu: RX PPDU on PHY layer + * @ppdu_bytes: RX bytes on PHY layer + * @disorder: discontinuity in seqnum + * @mpdu_retry: MPDUs flagged as retry + * @mpdu_dup: MPDUs identified as duplicated + * @aggregation: aggregation size + * @mcs: histogram of encoding rate for PPDUs + * @ps_inds: power save indication + * @ps_durs: total time in power save + * @probe_reqs: probe request received + * @other_mgmt: other MGMT frames received + */ +struct sir_rx_threshold { + uint32_t mpdu; + uint32_t bytes; + uint32_t ppdu; + uint32_t ppdu_bytes; + uint32_t disorder; + uint32_t mpdu_lost; + uint32_t mpdu_retry; + uint32_t mpdu_dup; + uint32_t mpdu_discard; + uint32_t aggregation; + uint32_t mcs; + uint32_t ps_inds; + uint32_t ps_durs; + uint32_t probe_reqs; + uint32_t other_mgmt; +}; + +/** + * struct sir_wifi_ll_ext_stats_threshold - Threshold for stats update + * @period: MAC counter indication period (unit in ms) + * @enable: if threshold mechnism is enabled or disabled + * @enable_bitmap: whether dedicated threshold is enabed. + * Every MAC counter has a dedicated threshold. If the dedicated + * threshold is not set in the bitmap, global threshold will take + * effect. + * @global: whether clobal threshold is enabled. + * When both global and dedicated threshold are diabled, MAC counter + * will indicate stats periodically. + * @global_threshold: global threshold value + * @cca_bitmap: bitmap for CCA. + * Bit0: idle time + * Bit1: tx time + * Bit2: RX in BSS + * Bit3: RX out of BSS + * Bit4: medium busy + * Bit5: RX bad + * Bit6: TX bad + * Bit7: WLAN card not available + * @signal_bitmap: + * Bit0: Per channel SNR counter + * Bit1: Per channel noise floor counter + * @tx_bitmap: bitmap for TX counters + * Bit0: TX counter unit in MSDU + * Bit1: TX counter unit in MPDU + * Bit2: TX counter unit in PPDU + * Bit3: TX counter unit in byte + * Bit4: Dropped MSDUs + * Bit5: Dropped Bytes + * Bit6: MPDU retry counter + * Bit7: MPDU failure counter + * Bit8: PPDU failure counter + * Bit9: MPDU aggregation counter + * Bit10: MCS counter for ACKed MPDUs + * Bit11: MCS counter for Failed MPDUs + * Bit12: TX Delay counter + * @rx_bitmap:bitmap for RX counters + * Bit0: MAC RX counter unit in MPDU + * Bit1: MAC RX counter unit in byte + * Bit2: PHY RX counter unit in PPDU + * Bit3: PHY RX counter unit in byte + * Bit4: Disorder counter + * Bit5: Retry counter + * Bit6: Duplication counter + * Bit7: Discard counter + * Bit8: MPDU aggregation size counter + * Bit9: MCS counter + * Bit10: Peer STA power state change (wake to sleep) counter + * Bit11: Peer STA power save counter, total time in PS mode + * Bit12: Probe request counter + * Bit13: Other management frames counter + * @cca_thresh: CCA threshold + * @signal_thresh: signal threshold + * @tx_thresh: TX threshold + * @rx_thresh: RX threshold + * + * Generally, Link layer statistics is reported periodically. But if the + * variation of one stats of compared to the pervious notification exceeds + * a threshold, FW will report the new stats immediately. + * This structure contains threshold for different counters. + */ +struct sir_ll_ext_stats_threshold { + uint32_t period; + uint32_t enable; + uint32_t enable_bitmap; + uint32_t global; + uint32_t global_threshold; + uint32_t cca_bitmap; + uint32_t signal_bitmap; + uint32_t tx_bitmap; + uint32_t rx_bitmap; + struct sir_channel_cca_threshold cca; + struct sir_signal_threshold signal; + struct sir_tx_threshold tx; + struct sir_rx_threshold rx; +}; + +#define LL_STATS_MIN_PERIOD 10 +#define LL_STATS_INVALID_PERIOD 0xFFFFFFFF + typedef struct { uint32_t paramId; uint8_t ifaceId; diff --git a/core/mac/src/include/sir_params.h b/core/mac/src/include/sir_params.h index cb8a3b932d..707dc7a947 100644 --- a/core/mac/src/include/sir_params.h +++ b/core/mac/src/include/sir_params.h @@ -639,7 +639,11 @@ typedef struct sSirMbMsgP2p { #define SIR_HAL_SET_PER_ROAM_CONFIG_CMD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 371) -#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) +#ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define SIR_HAL_LL_STATS_EXT_SET_THRESHOLD (SIR_HAL_ITC_MSG_TYPES_BEGIN + 378) +#endif + +#define SIR_HAL_MSG_TYPES_END (SIR_HAL_MSG_TYPES_BEGIN + 0x1FF) /* CFG message types */ #define SIR_CFG_MSG_TYPES_BEGIN (SIR_CFG_MODULE_ID << 8) diff --git a/core/sme/inc/sme_api.h b/core/sme/inc/sme_api.h index 1362a2d950..cca5809c3a 100644 --- a/core/sme/inc/sme_api.h +++ b/core/sme/inc/sme_api.h @@ -889,6 +889,8 @@ QDF_STATUS sme_set_link_layer_ext_cb(tHalHandle hal, void (*ll_stats_ext_cb)(tHddHandle callback_ctx, tSirLLStatsResults * rsp)); QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle hhal); +QDF_STATUS sme_ll_stats_set_thresh(tHalHandle hal, + struct sir_ll_ext_stats_threshold *threshold); #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ QDF_STATUS sme_fw_mem_dump(tHalHandle hHal, void *recvd_req); diff --git a/core/sme/src/common/sme_api.c b/core/sme/src/common/sme_api.c index d6158c1694..798bc93da5 100644 --- a/core/sme/src/common/sme_api.c +++ b/core/sme/src/common/sme_api.c @@ -13266,6 +13266,64 @@ QDF_STATUS sme_reset_link_layer_stats_ind_cb(tHalHandle h_hal) return status; } +/** + * sme_ll_stats_set_thresh - set threshold for mac counters + * @hal, hal layer handle + * @threshold, threshold for mac counters + * + * Return: QDF_STATUS Enumeration + */ +QDF_STATUS sme_ll_stats_set_thresh(tHalHandle hal, + struct sir_ll_ext_stats_threshold *threshold) +{ + QDF_STATUS status; + tpAniSirGlobal mac; + struct scheduler_msg message; + struct sir_ll_ext_stats_threshold *thresh; + + if (!threshold) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("threshold is not valid")); + return QDF_STATUS_E_INVAL; + } + + if (!hal) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("hal is not valid")); + return QDF_STATUS_E_INVAL; + } + mac = PMAC_STRUCT(hal); + + thresh = qdf_mem_malloc(sizeof(*thresh)); + if (!thresh) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: Fail to alloc mem", __func__); + return QDF_STATUS_E_NOMEM; + } + *thresh = *threshold; + + status = sme_acquire_global_lock(&mac->sme); + if (QDF_IS_STATUS_SUCCESS(status)) { + /* Serialize the req through MC thread */ + message.bodyptr = thresh; + message.type = WDA_LINK_LAYER_STATS_SET_THRESHOLD; + MTRACE(qdf_trace(QDF_MODULE_ID_SME, TRACE_CODE_SME_TX_WMA_MSG, + NO_SESSION, message.type)); + status = scheduler_post_msg(QDF_MODULE_ID_WMA, &message); + if (!QDF_IS_STATUS_SUCCESS(status)) { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + "%s: not able to post WDA_LL_STATS_GET_REQ", + __func__); + qdf_mem_free(thresh); + } + sme_release_global_lock(&mac->sme); + } else { + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_ERROR, + FL("sme_acquire_global_lock error")); + qdf_mem_free(thresh); + } + return status; +} #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ diff --git a/core/wma/inc/wma_internal.h b/core/wma/inc/wma_internal.h index e73c958745..9e59b6b003 100644 --- a/core/wma/inc/wma_internal.h +++ b/core/wma/inc/wma_internal.h @@ -822,6 +822,8 @@ QDF_STATUS wma_process_ll_stats_get_req int wma_unified_link_iface_stats_event_handler(void *handle, uint8_t *cmd_param_info, uint32_t len); +void wma_config_stats_ext_threshold(tp_wma_handle wma, + struct sir_ll_ext_stats_threshold *thresh); #endif void wma_post_link_status(tAniGetLinkStatus *pGetLinkStatus, diff --git a/core/wma/inc/wma_types.h b/core/wma/inc/wma_types.h index ad3ec0c4b1..57a1f48427 100644 --- a/core/wma/inc/wma_types.h +++ b/core/wma/inc/wma_types.h @@ -413,6 +413,7 @@ #define WMA_LINK_LAYER_STATS_SET_REQ SIR_HAL_LL_STATS_SET_REQ #define WMA_LINK_LAYER_STATS_GET_REQ SIR_HAL_LL_STATS_GET_REQ #define WMA_LINK_LAYER_STATS_RESULTS_RSP SIR_HAL_LL_STATS_RESULTS_RSP +#define WDA_LINK_LAYER_STATS_SET_THRESHOLD SIR_HAL_LL_STATS_EXT_SET_THRESHOLD #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ #define WMA_LINK_STATUS_GET_REQ SIR_HAL_LINK_STATUS_GET_REQ diff --git a/core/wma/src/wma_main.c b/core/wma/src/wma_main.c index 8c8cfe5ef5..57f148f121 100644 --- a/core/wma/src/wma_main.c +++ b/core/wma/src/wma_main.c @@ -6794,6 +6794,11 @@ QDF_STATUS wma_mc_process_msg(void *cds_context, struct scheduler_msg *msg) (tpSirLLStatsGetReq) msg->bodyptr); qdf_mem_free(msg->bodyptr); break; + case WDA_LINK_LAYER_STATS_SET_THRESHOLD: + wma_config_stats_ext_threshold(wma_handle, + (struct sir_ll_ext_stats_threshold *)msg->bodyptr); + qdf_mem_free(msg->bodyptr); + break; #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ case SIR_HAL_UNIT_TEST_CMD: wma_process_unit_test_cmd(wma_handle, diff --git a/core/wma/src/wma_utils.c b/core/wma/src/wma_utils.c index e765f12054..12acc35025 100644 --- a/core/wma/src/wma_utils.c +++ b/core/wma/src/wma_utils.c @@ -556,6 +556,556 @@ int wma_profile_data_report_event_handler(void *handle, uint8_t *event_buf, #ifdef WLAN_FEATURE_LINK_LAYER_STATS +#define WMA_FILL_TX_STATS(eve, msg) do {\ + (msg)->msdus = (eve)->tx_msdu_cnt;\ + (msg)->mpdus = (eve)->tx_mpdu_cnt;\ + (msg)->ppdus = (eve)->tx_ppdu_cnt;\ + (msg)->bytes = (eve)->tx_bytes;\ + (msg)->drops = (eve)->tx_msdu_drop_cnt;\ + (msg)->drop_bytes = (eve)->tx_drop_bytes;\ + (msg)->retries = (eve)->tx_mpdu_retry_cnt;\ + (msg)->failed = (eve)->tx_mpdu_fail_cnt;\ +} while (0) + +#define WMA_FILL_RX_STATS(eve, msg) do {\ + (msg)->mpdus = (eve)->mac_rx_mpdu_cnt;\ + (msg)->bytes = (eve)->mac_rx_bytes;\ + (msg)->ppdus = (eve)->phy_rx_ppdu_cnt;\ + (msg)->ppdu_bytes = (eve)->phy_rx_bytes;\ + (msg)->mpdu_retry = (eve)->rx_mpdu_retry_cnt;\ + (msg)->mpdu_dup = (eve)->rx_mpdu_dup_cnt;\ + (msg)->mpdu_discard = (eve)->rx_mpdu_discard_cnt;\ +} while (0) + +/** + * wma_get_ll_stats_ext_buf() - alloc result buffer for MAC counters + * @len: buffer length output + * @peer_num: peer number + * @fixed_param: fixed parameters in WMI event + * + * Structure of the stats message + * LL_EXT_STATS + * | + * |--Channel stats[1~n] + * |--Peer[1~n] + * | + * +---Signal + * +---TX + * | +---BE + * | +---BK + * | +---VI + * | +---VO + * | + * +---RX + * +---BE + * +---BK + * +---VI + * +---VO + * For each Access Category, the arregation and mcs + * stats are as this: + * TX + * +-BE/BK/VI/VO + * +----tx_mpdu_aggr_array + * +----tx_succ_mcs_array + * +----tx_fail_mcs_array + * +----tx_delay_array + * RX + * +-BE/BK/VI/VO + * +----rx_mpdu_aggr_array + * +----rx_mcs_array + * + * return: Address for result buffer. + */ +static tSirLLStatsResults *wma_get_ll_stats_ext_buf(uint32_t *len, + uint32_t peer_num, + wmi_report_stats_event_fixed_param *fixed_param) +{ + tSirLLStatsResults *buf; + uint32_t buf_len; + + if (!len || !fixed_param) { + WMA_LOGE(FL("Invalid input parameters.")); + return NULL; + } + + /* + * Result buffer has a structure like this: + * --------------------------------- + * | trigger_cond_i | + * +-------------------------------+ + * | cca_chgd_bitmap | + * +-------------------------------+ + * | sig_chgd_bitmap | + * +-------------------------------+ + * | tx_chgd_bitmap | + * +-------------------------------+ + * | rx_chgd_bitmap | + * +-------------------------------+ + * | peer_num | + * +-------------------------------+ + * | channel_num | + * +-------------------------------+ + * | tx_mpdu_aggr_array_len | + * +-------------------------------+ + * | tx_succ_mcs_array_len | + * +-------------------------------+ + * | tx_fail_mcs_array_len | + * +-------------------------------+ + * | tx_delay_array_len | + * +-------------------------------+ + * | rx_mpdu_aggr_array_len | + * +-------------------------------+ + * | rx_mcs_array_len | + * +-------------------------------+ + * | pointer to CCA stats | + * +-------------------------------+ + * | CCA stats | + * +-------------------------------+ + * | peer_stats |----+ + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | not fixed. |<-+ | + * +-------------------------------+ | | + * | per peer tx stats |--+ | + * | BE | <--+ + * | BK | | + * | VI | | + * | VO | | + * +-------------------------------+ | + * | TX aggr/mcs parameters array | | + * | Length of this buffer is | | + * | not fixed. |<-+ | + * +-------------------------------+ | | + * | peer peer rx stats |--+ | + * | BE | <--+ + * | BK | + * | VI | + * | VO | + * --------------------------------- + */ + buf_len = sizeof(tSirLLStatsResults) + + sizeof(struct sir_wifi_ll_ext_stats) + + fixed_param->num_chan_cca_stats * + sizeof(struct sir_wifi_chan_cca_stats) + + peer_num * + (sizeof(struct sir_wifi_ll_ext_peer_stats) + + WLAN_MAX_AC * + (sizeof(struct sir_wifi_tx) + + sizeof(struct sir_wifi_rx)) + + sizeof(uint32_t) * WLAN_MAX_AC * + (fixed_param->tx_mpdu_aggr_array_len + + fixed_param->tx_succ_mcs_array_len + + fixed_param->tx_fail_mcs_array_len + + fixed_param->tx_ppdu_delay_array_len + + fixed_param->rx_mpdu_aggr_array_len + + fixed_param->rx_mcs_array_len)); + + buf = (tSirLLStatsResults *)qdf_mem_malloc(buf_len); + if (buf == NULL) { + WMA_LOGE("%s: Cannot allocate link layer stats.", __func__); + buf_len = 0; + return NULL; + } + + *len = buf_len; + return buf; +} + +/** + * wma_fill_tx_stats() - Fix TX stats into result buffer + * @ll_stats: LL stats buffer + * @fix_param: parameters with fixed length in WMI event + * @param_buf: parameters without fixed length in WMI event + * @buf: buffer for TLV parameters + * + * Return: None + */ +static void wma_fill_tx_stats(struct sir_wifi_ll_ext_stats *ll_stats, + wmi_report_stats_event_fixed_param *fix_param, + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf, + uint8_t **buf, uint32_t *buf_length) +{ + uint8_t *result; + uint32_t i, j, k; + wmi_peer_ac_tx_stats *wmi_peer_tx; + wmi_tx_stats *wmi_tx; + struct sir_wifi_tx *tx_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + uint32_t *tx_mpdu_aggr, *tx_succ_mcs, *tx_fail_mcs, *tx_delay; + uint32_t len, dst_len, tx_mpdu_aggr_array_len, tx_succ_mcs_array_len, + tx_fail_mcs_array_len, tx_delay_array_len; + + result = *buf; + dst_len = *buf_length; + tx_mpdu_aggr_array_len = fix_param->tx_mpdu_aggr_array_len; + ll_stats->tx_mpdu_aggr_array_len = tx_mpdu_aggr_array_len; + tx_succ_mcs_array_len = fix_param->tx_succ_mcs_array_len; + ll_stats->tx_succ_mcs_array_len = tx_succ_mcs_array_len; + tx_fail_mcs_array_len = fix_param->tx_fail_mcs_array_len; + ll_stats->tx_fail_mcs_array_len = tx_fail_mcs_array_len; + tx_delay_array_len = fix_param->tx_ppdu_delay_array_len; + ll_stats->tx_delay_array_len = tx_delay_array_len; + wmi_peer_tx = param_buf->peer_ac_tx_stats; + wmi_tx = param_buf->tx_stats; + + len = fix_param->num_peer_ac_tx_stats * + WLAN_MAX_AC * tx_mpdu_aggr_array_len * sizeof(uint32_t); + if (len <= dst_len) { + tx_mpdu_aggr = (uint32_t *)result; + qdf_mem_copy(tx_mpdu_aggr, param_buf->tx_mpdu_aggr, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("TX_MPDU_AGGR buffer length is wrong.")); + tx_mpdu_aggr = NULL; + } + + len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC * + tx_succ_mcs_array_len * sizeof(uint32_t); + if (len <= dst_len) { + tx_succ_mcs = (uint32_t *)result; + qdf_mem_copy(tx_succ_mcs, param_buf->tx_succ_mcs, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("TX_SUCC_MCS buffer length is wrong.")); + tx_succ_mcs = NULL; + } + + len = fix_param->num_peer_ac_tx_stats * WLAN_MAX_AC * + tx_fail_mcs_array_len * sizeof(uint32_t); + if (len <= dst_len) { + tx_fail_mcs = (uint32_t *)result; + qdf_mem_copy(tx_fail_mcs, param_buf->tx_fail_mcs, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("TX_FAIL_MCS buffer length is wrong.")); + tx_fail_mcs = NULL; + } + + len = fix_param->num_peer_ac_tx_stats * + WLAN_MAX_AC * tx_delay_array_len * sizeof(uint32_t); + if (len <= dst_len) { + tx_delay = (uint32_t *)result; + qdf_mem_copy(tx_delay, param_buf->tx_ppdu_delay, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("TX_DELAY buffer length is wrong.")); + tx_delay = NULL; + } + + /* per peer tx stats */ + peer_stats = ll_stats->peer_stats; + + for (i = 0; i < fix_param->num_peer_ac_tx_stats; i++) { + uint32_t peer_id = wmi_peer_tx[i].peer_id; + struct sir_wifi_tx *ac; + wmi_tx_stats *wmi_tx_stats; + + for (j = 0; j < ll_stats->peer_num; j++) { + peer_stats += j; + if (peer_stats->peer_id == WIFI_INVALID_PEER_ID || + peer_stats->peer_id == peer_id) + break; + } + + if (j < ll_stats->peer_num) { + peer_stats->peer_id = wmi_peer_tx[i].peer_id; + peer_stats->vdev_id = wmi_peer_tx[i].vdev_id; + tx_stats = (struct sir_wifi_tx *)result; + for (k = 0; k < WLAN_MAX_AC; k++) { + wmi_tx_stats = &wmi_tx[i * WLAN_MAX_AC + k]; + ac = &tx_stats[k]; + WMA_FILL_TX_STATS(wmi_tx_stats, ac); + ac->mpdu_aggr_size = tx_mpdu_aggr; + ac->aggr_len = tx_mpdu_aggr_array_len * + sizeof(uint32_t); + ac->success_mcs_len = tx_succ_mcs_array_len * + sizeof(uint32_t); + ac->success_mcs = tx_succ_mcs; + ac->fail_mcs = tx_fail_mcs; + ac->fail_mcs_len = tx_fail_mcs_array_len * + sizeof(uint32_t); + ac->delay = tx_delay; + ac->delay_len = tx_delay_array_len * + sizeof(uint32_t); + peer_stats->ac_stats[k].tx_stats = ac; + peer_stats->ac_stats[k].type = k; + tx_mpdu_aggr += tx_mpdu_aggr_array_len; + tx_succ_mcs += tx_succ_mcs_array_len; + tx_fail_mcs += tx_fail_mcs_array_len; + tx_delay += tx_delay_array_len; + } + result += WLAN_MAX_AC * sizeof(struct sir_wifi_tx); + } else { + /* + * Buffer for Peer TX counter overflow. + * There is peer ID mismatch between TX, RX, + * signal counters. + */ + WMA_LOGE(FL("One peer TX info is dropped.")); + + tx_mpdu_aggr += tx_mpdu_aggr_array_len * WLAN_MAX_AC; + tx_succ_mcs += tx_succ_mcs_array_len * WLAN_MAX_AC; + tx_fail_mcs += tx_fail_mcs_array_len * WLAN_MAX_AC; + tx_delay += tx_delay_array_len * WLAN_MAX_AC; + } + } + *buf = result; + *buf_length = dst_len; +} + +/** + * wma_fill_rx_stats() - Fix RX stats into result buffer + * @ll_stats: LL stats buffer + * @fix_param: parameters with fixed length in WMI event + * @param_buf: parameters without fixed length in WMI event + * @buf: buffer for TLV parameters + * + * Return: None + */ +static void wma_fill_rx_stats(struct sir_wifi_ll_ext_stats *ll_stats, + wmi_report_stats_event_fixed_param *fix_param, + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf, + uint8_t **buf, uint32_t *buf_length) +{ + uint8_t *result; + uint32_t i, j, k; + uint32_t *rx_mpdu_aggr, *rx_mcs; + wmi_rx_stats *wmi_rx; + wmi_peer_ac_rx_stats *wmi_peer_rx; + struct sir_wifi_rx *rx_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + uint32_t len, dst_len, rx_mpdu_aggr_array_len, rx_mcs_array_len; + + rx_mpdu_aggr_array_len = fix_param->rx_mpdu_aggr_array_len; + ll_stats->rx_mpdu_aggr_array_len = rx_mpdu_aggr_array_len; + rx_mcs_array_len = fix_param->rx_mcs_array_len; + ll_stats->rx_mcs_array_len = rx_mcs_array_len; + wmi_peer_rx = param_buf->peer_ac_rx_stats; + wmi_rx = param_buf->rx_stats; + + result = *buf; + dst_len = *buf_length; + len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats * + WLAN_MAX_AC * rx_mpdu_aggr_array_len); + if (len <= dst_len) { + rx_mpdu_aggr = (uint32_t *)result; + qdf_mem_copy(rx_mpdu_aggr, param_buf->rx_mpdu_aggr, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("RX_MPDU_AGGR array length is wrong.")); + rx_mpdu_aggr = NULL; + } + + len = sizeof(uint32_t) * (fix_param->num_peer_ac_rx_stats * + WLAN_MAX_AC * rx_mcs_array_len); + if (len <= dst_len) { + rx_mcs = (uint32_t *)result; + qdf_mem_copy(rx_mcs, param_buf->rx_mcs, len); + result += len; + dst_len -= len; + } else { + WMA_LOGE(FL("RX_MCS array length is wrong.")); + rx_mcs = NULL; + } + + /* per peer rx stats */ + peer_stats = ll_stats->peer_stats; + for (i = 0; i < fix_param->num_peer_ac_rx_stats; i++) { + uint32_t peer_id = wmi_peer_rx[i].peer_id; + struct sir_wifi_rx *ac; + wmi_rx_stats *wmi_rx_stats; + + for (j = 0; j < ll_stats->peer_num; j++) { + peer_stats += j; + if ((peer_stats->peer_id == WIFI_INVALID_PEER_ID) || + (peer_stats->peer_id == peer_id)) + break; + } + + if (j < ll_stats->peer_num) { + peer_stats->peer_id = wmi_peer_rx[i].peer_id; + peer_stats->vdev_id = wmi_peer_rx[i].vdev_id; + peer_stats->sta_ps_inds = wmi_peer_rx[i].sta_ps_inds; + peer_stats->sta_ps_durs = wmi_peer_rx[i].sta_ps_durs; + peer_stats->rx_probe_reqs = + wmi_peer_rx[i].rx_probe_reqs; + peer_stats->rx_oth_mgmts = wmi_peer_rx[i].rx_oth_mgmts; + rx_stats = (struct sir_wifi_rx *)result; + + for (k = 0; k < WLAN_MAX_AC; k++) { + wmi_rx_stats = &wmi_rx[i * WLAN_MAX_AC + k]; + ac = &rx_stats[k]; + WMA_FILL_RX_STATS(wmi_rx_stats, ac); + ac->mpdu_aggr = rx_mpdu_aggr; + ac->aggr_len = rx_mpdu_aggr_array_len * + sizeof(uint32_t); + ac->mcs = rx_mcs; + ac->mcs_len = rx_mcs_array_len * + sizeof(uint32_t); + peer_stats->ac_stats[k].rx_stats = ac; + peer_stats->ac_stats[k].type = k; + rx_mpdu_aggr += rx_mpdu_aggr_array_len; + rx_mcs += rx_mcs_array_len; + } + result += WLAN_MAX_AC * sizeof(struct sir_wifi_rx); + } else { + /* + * Buffer for Peer RX counter overflow. + * There is peer ID mismatch between TX, RX, + * signal counters. + */ + WMA_LOGE(FL("One peer RX info is dropped.")); + rx_mpdu_aggr += rx_mpdu_aggr_array_len * WLAN_MAX_AC; + rx_mcs += rx_mcs_array_len * WLAN_MAX_AC; + } + } + *buf = result; + *buf_length = dst_len; +} + +/** + * wma_ll_stats_evt_handler() - handler for MAC layer counters. + * @handle - wma handle + * @event - FW event + * @len - length of FW event + * + * return: 0 success. + */ +static int wma_ll_stats_evt_handler(void *handle, u_int8_t *event, + u_int32_t len) +{ + WMI_REPORT_STATS_EVENTID_param_tlvs *param_buf; + wmi_report_stats_event_fixed_param *fixed_param; + tSirLLStatsResults *link_stats_results; + wmi_chan_cca_stats *wmi_cca_stats; + wmi_peer_signal_stats *wmi_peer_signal; + wmi_peer_ac_rx_stats *wmi_peer_rx; + struct sir_wifi_ll_ext_stats *ll_stats; + struct sir_wifi_ll_ext_peer_stats *peer_stats; + struct sir_wifi_chan_cca_stats *cca_stats; + struct sir_wifi_peer_signal_stats *peer_signal; + uint8_t *result; + uint32_t i, peer_num, result_size, dst_len; + tpAniSirGlobal mac; + struct scheduler_msg sme_msg = { 0 }; + QDF_STATUS qdf_status; + + mac = (tpAniSirGlobal)cds_get_context(QDF_MODULE_ID_PE); + if (!mac) { + WMA_LOGD("%s: NULL mac ptr. Exiting", __func__); + return -EINVAL; + } + + if (!mac->sme.link_layer_stats_ext_cb) { + WMA_LOGD("%s: HDD callback is null", __func__); + return -EINVAL; + } + + WMA_LOGD("%s: Posting MAC counters event to HDD", __func__); + + param_buf = (WMI_REPORT_STATS_EVENTID_param_tlvs *)event; + fixed_param = param_buf->fixed_param; + wmi_cca_stats = param_buf->chan_cca_stats; + wmi_peer_signal = param_buf->peer_signal_stats; + wmi_peer_rx = param_buf->peer_ac_rx_stats; + + /* Get the MAX of three peer numbers */ + peer_num = fixed_param->num_peer_signal_stats > + fixed_param->num_peer_ac_tx_stats ? + fixed_param->num_peer_signal_stats : + fixed_param->num_peer_ac_tx_stats; + peer_num = peer_num > fixed_param->num_peer_ac_rx_stats ? + peer_num : fixed_param->num_peer_ac_rx_stats; + + if (peer_num == 0) + return -EINVAL; + + link_stats_results = wma_get_ll_stats_ext_buf(&result_size, + peer_num, + fixed_param); + if (!link_stats_results) { + WMA_LOGE("%s: Fail to allocate stats buffer", __func__); + return -EINVAL; + } + link_stats_results->paramId = WMI_LL_STATS_EXT_MAC_COUNTER; + link_stats_results->num_peers = peer_num; + link_stats_results->peer_event_number = 1; + link_stats_results->moreResultToFollow = 0; + + ll_stats = (struct sir_wifi_ll_ext_stats *)link_stats_results->results; + ll_stats->trigger_cond_id = fixed_param->trigger_cond_id; + ll_stats->cca_chgd_bitmap = fixed_param->cca_chgd_bitmap; + ll_stats->sig_chgd_bitmap = fixed_param->sig_chgd_bitmap; + ll_stats->tx_chgd_bitmap = fixed_param->tx_chgd_bitmap; + ll_stats->rx_chgd_bitmap = fixed_param->rx_chgd_bitmap; + ll_stats->channel_num = fixed_param->num_chan_cca_stats; + ll_stats->peer_num = peer_num; + + result = (uint8_t *)ll_stats->stats; + peer_stats = (struct sir_wifi_ll_ext_peer_stats *)result; + ll_stats->peer_stats = peer_stats; + + for (i = 0; i < peer_num; i++) { + peer_stats[i].peer_id = WIFI_INVALID_PEER_ID; + peer_stats[i].vdev_id = WIFI_INVALID_VDEV_ID; + } + + /* Per peer signal */ + result_size -= sizeof(struct sir_wifi_ll_ext_stats); + dst_len = sizeof(struct sir_wifi_peer_signal_stats); + for (i = 0; i < fixed_param->num_peer_signal_stats; i++) { + peer_stats[i].peer_id = wmi_peer_signal->peer_id; + peer_stats[i].vdev_id = wmi_peer_signal->vdev_id; + peer_signal = &peer_stats[i].peer_signal_stats; + + if (dst_len <= result_size) { + qdf_mem_copy(peer_signal, + &wmi_peer_signal->vdev_id, dst_len); + result_size -= dst_len; + } else { + WMA_LOGE(FL("Invalid length of PEER signal.")); + } + wmi_peer_signal++; + } + + result += peer_num * sizeof(struct sir_wifi_ll_ext_peer_stats); + cca_stats = (struct sir_wifi_chan_cca_stats *)result; + ll_stats->cca = cca_stats; + dst_len = sizeof(struct sir_wifi_chan_cca_stats); + for (i = 0; i < ll_stats->channel_num; i++) { + if (dst_len <= result_size) { + qdf_mem_copy(&cca_stats[i], &wmi_cca_stats->vdev_id, + dst_len); + result_size -= dst_len; + } else { + WMA_LOGE(FL("Invalid length of CCA.")); + } + } + + result += i * sizeof(struct sir_wifi_chan_cca_stats); + wma_fill_tx_stats(ll_stats, fixed_param, param_buf, + &result, &result_size); + wma_fill_rx_stats(ll_stats, fixed_param, param_buf, + &result, &result_size); + sme_msg.type = eWMI_SME_LL_STATS_IND; + sme_msg.bodyptr = (void *)link_stats_results; + sme_msg.bodyval = 0; + qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg); + if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { + WMA_LOGP(FL("Failed to post peer stat change msg!")); + qdf_mem_free(link_stats_results); + return -EINVAL; + } + + return 0; +} + /** * wma_unified_link_peer_stats_event_handler() - peer stats event handler * @handle: wma handle @@ -1093,7 +1643,7 @@ static int wma_peer_ps_evt_handler(void *handle, u_int8_t *event, sme_msg.bodyptr = link_stats_results; sme_msg.bodyval = 0; - qdf_status = cds_mq_post_message(QDF_MODULE_ID_SME, &sme_msg); + qdf_status = scheduler_post_msg(QDF_MODULE_ID_SME, &sme_msg); if (!QDF_IS_STATUS_SUCCESS(qdf_status)) { WMA_LOGE("%s: Fail to post ps change ind msg", __func__); qdf_mem_free(link_stats_results); @@ -1209,6 +1759,10 @@ void wma_register_ll_stats_event_handler(tp_wma_handle wma_handle) WMI_PEER_STA_PS_STATECHG_EVENTID, wma_peer_ps_evt_handler, WMA_RX_SERIALIZER_CTX); + wmi_unified_register_event_handler(wma_handle->wmi_handle, + WMI_REPORT_STATS_EVENTID, + wma_ll_stats_evt_handler, + WMA_RX_SERIALIZER_CTX); return; } @@ -1432,6 +1986,164 @@ int wma_unified_link_iface_stats_event_handler(void *handle, return 0; } +/** + * wma_config_stats_ext_threshold - set threthold for MAC counters + * @wma: wma handler + * @threshold: threhold for MAC counters + * + * For each MAC layer counter, FW holds two copies. One is the current value. + * The other is the last report. Once a current counter's increment is larger + * than the threshold, FW will indicate that counter to host even if the + * monitoring timer does not expire. + * + * Return: None + */ +void wma_config_stats_ext_threshold(tp_wma_handle wma, + struct sir_ll_ext_stats_threshold *thresh) +{ + uint32_t len, tag, hdr_len; + uint8_t *buf_ptr; + wmi_buf_t buf; + wmi_pdev_set_stats_threshold_cmd_fixed_param *cmd; + wmi_chan_cca_stats_thresh *cca; + wmi_peer_signal_stats_thresh *signal; + wmi_tx_stats_thresh *tx; + wmi_rx_stats_thresh *rx; + + if (!thresh) { + WMA_LOGE(FL("Invalid threshold input.")); + return; + } + + len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param) + + sizeof(wmi_chan_cca_stats_thresh) + + sizeof(wmi_peer_signal_stats_thresh) + + sizeof(wmi_tx_stats_thresh) + + sizeof(wmi_rx_stats_thresh) + + 5 * WMI_TLV_HDR_SIZE; + buf = wmi_buf_alloc(wma->wmi_handle, len); + if (!buf) { + WMA_LOGP("%s: wmi_buf_alloc failed", __func__); + return; + } + + buf_ptr = (u_int8_t *)wmi_buf_data(buf); + tag = WMITLV_TAG_STRUC_wmi_pdev_set_stats_threshold_cmd_fixed_param; + hdr_len = WMITLV_GET_STRUCT_TLVLEN( + wmi_pdev_set_stats_threshold_cmd_fixed_param); + WMA_LOGD(FL("Setting fixed parameters. tag=%d, len=%d"), tag, hdr_len); + cmd = (wmi_pdev_set_stats_threshold_cmd_fixed_param *)buf_ptr; + WMITLV_SET_HDR(&cmd->tlv_header, tag, hdr_len); + cmd->enable_thresh = thresh->enable; + cmd->use_thresh_bitmap = thresh->enable_bitmap; + cmd->gbl_thresh = thresh->global_threshold; + cmd->cca_thresh_enable_bitmap = thresh->cca_bitmap; + cmd->signal_thresh_enable_bitmap = thresh->signal_bitmap; + cmd->tx_thresh_enable_bitmap = thresh->tx_bitmap; + cmd->rx_thresh_enable_bitmap = thresh->rx_bitmap; + len = sizeof(wmi_pdev_set_stats_threshold_cmd_fixed_param); + + tag = WMITLV_TAG_STRUC_wmi_chan_cca_stats_thresh, + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_chan_cca_stats_thresh); + cca = (wmi_chan_cca_stats_thresh *)(buf_ptr + len); + WMITLV_SET_HDR(&cca->tlv_header, tag, hdr_len); + WMA_LOGD(FL("Setting cca parameters. tag=%d, len=%d"), tag, hdr_len); + cca->idle_time = thresh->cca.idle_time; + cca->tx_time = thresh->cca.tx_time; + cca->rx_in_bss_time = thresh->cca.rx_in_bss_time; + cca->rx_out_bss_time = thresh->cca.rx_out_bss_time; + cca->rx_busy_time = thresh->cca.rx_busy_time; + cca->rx_in_bad_cond_time = thresh->cca.rx_in_bad_cond_time; + cca->tx_in_bad_cond_time = thresh->cca.tx_in_bad_cond_time; + cca->wlan_not_avail_time = thresh->cca.wlan_not_avail_time; + WMA_LOGD(FL("idle time=%d, tx_time=%d, in_bss=%d, out_bss=%d"), + cca->idle_time, cca->tx_time, + cca->rx_in_bss_time, cca->rx_out_bss_time); + WMA_LOGD(FL("rx_busy=%d, rx_bad=%d, tx_bad=%d, not_avail=%d"), + cca->rx_busy_time, cca->rx_in_bad_cond_time, + cca->tx_in_bad_cond_time, cca->wlan_not_avail_time); + len += sizeof(wmi_chan_cca_stats_thresh); + + signal = (wmi_peer_signal_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_peer_signal_stats_thresh; + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_peer_signal_stats_thresh); + WMA_LOGD(FL("Setting signal parameters. tag=%d, len=%d"), tag, hdr_len); + WMITLV_SET_HDR(&signal->tlv_header, tag, hdr_len); + signal->per_chain_snr = thresh->signal.snr; + signal->per_chain_nf = thresh->signal.nf; + WMA_LOGD(FL("snr=%d, nf=%d"), signal->per_chain_snr, + signal->per_chain_nf); + len += sizeof(wmi_peer_signal_stats_thresh); + + tx = (wmi_tx_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_tx_stats_thresh; + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_tx_stats_thresh); + WMA_LOGD(FL("Setting TX parameters. tag=%d, len=%d"), tag, len); + WMITLV_SET_HDR(&tx->tlv_header, tag, hdr_len); + tx->tx_msdu_cnt = thresh->tx.msdu; + tx->tx_mpdu_cnt = thresh->tx.mpdu; + tx->tx_ppdu_cnt = thresh->tx.ppdu; + tx->tx_bytes = thresh->tx.bytes; + tx->tx_msdu_drop_cnt = thresh->tx.msdu_drop; + tx->tx_drop_bytes = thresh->tx.byte_drop; + tx->tx_mpdu_retry_cnt = thresh->tx.mpdu_retry; + tx->tx_mpdu_fail_cnt = thresh->tx.mpdu_fail; + tx->tx_ppdu_fail_cnt = thresh->tx.ppdu_fail; + tx->tx_mpdu_aggr = thresh->tx.aggregation; + tx->tx_succ_mcs = thresh->tx.succ_mcs; + tx->tx_fail_mcs = thresh->tx.fail_mcs; + tx->tx_ppdu_delay = thresh->tx.delay; + WMA_LOGD(FL("msdu=%d, mpdu=%d, ppdu=%d, bytes=%d, msdu_drop=%d"), + tx->tx_msdu_cnt, tx->tx_mpdu_cnt, tx->tx_ppdu_cnt, + tx->tx_bytes, tx->tx_msdu_drop_cnt); + WMA_LOGD(FL("byte_drop=%d, mpdu_retry=%d, mpdu_fail=%d, ppdu_fail=%d"), + tx->tx_drop_bytes, tx->tx_mpdu_retry_cnt, + tx->tx_mpdu_fail_cnt, tx->tx_ppdu_fail_cnt); + WMA_LOGD(FL("aggr=%d, succ_mcs=%d, fail_mcs=%d, delay=%d"), + tx->tx_mpdu_aggr, tx->tx_succ_mcs, tx->tx_fail_mcs, + tx->tx_ppdu_delay); + len += sizeof(wmi_tx_stats_thresh); + + rx = (wmi_rx_stats_thresh *)(buf_ptr + len); + tag = WMITLV_TAG_STRUC_wmi_rx_stats_thresh, + hdr_len = WMITLV_GET_STRUCT_TLVLEN(wmi_rx_stats_thresh); + WMITLV_SET_HDR(&rx->tlv_header, tag, hdr_len); + WMA_LOGD(FL("Setting RX parameters. tag=%d, len=%d"), tag, hdr_len); + rx->mac_rx_mpdu_cnt = thresh->rx.mpdu; + rx->mac_rx_bytes = thresh->rx.bytes; + rx->phy_rx_ppdu_cnt = thresh->rx.ppdu; + rx->phy_rx_bytes = thresh->rx.ppdu_bytes; + rx->rx_disorder_cnt = thresh->rx.disorder; + rx->rx_mpdu_retry_cnt = thresh->rx.mpdu_retry; + rx->rx_mpdu_dup_cnt = thresh->rx.mpdu_dup; + rx->rx_mpdu_discard_cnt = thresh->rx.mpdu_discard; + rx->rx_mpdu_aggr = thresh->rx.aggregation; + rx->rx_mcs = thresh->rx.mcs; + rx->sta_ps_inds = thresh->rx.ps_inds; + rx->sta_ps_durs = thresh->rx.ps_durs; + rx->rx_probe_reqs = thresh->rx.probe_reqs; + rx->rx_oth_mgmts = thresh->rx.other_mgmt; + WMA_LOGD(FL("rx_mpdu=%d, rx_bytes=%d, rx_ppdu=%d, rx_pbytes=%d"), + rx->mac_rx_mpdu_cnt, rx->mac_rx_bytes, + rx->phy_rx_ppdu_cnt, rx->phy_rx_bytes); + WMA_LOGD(FL("disorder=%d, rx_dup=%d, rx_aggr=%d, rx_mcs=%d"), + rx->rx_disorder_cnt, rx->rx_mpdu_dup_cnt, + rx->rx_mpdu_aggr, rx->rx_mcs); + WMA_LOGD(FL("rx_ind=%d, rx_dur=%d, rx_probe=%d, rx_mgmt=%d"), + rx->sta_ps_inds, rx->sta_ps_durs, + rx->rx_probe_reqs, rx->rx_oth_mgmts); + len += sizeof(wmi_rx_stats_thresh); + + WMA_LOGA("WMA --> WMI_PDEV_SET_STATS_THRESHOLD_CMDID(0x%x), length=%d", + WMI_PDEV_SET_STATS_THRESHOLD_CMDID, len); + if (EOK != wmi_unified_cmd_send(wma->wmi_handle, + buf, len, + WMI_PDEV_SET_STATS_THRESHOLD_CMDID)) { + WMA_LOGE("Failed to send WMI_PDEV_SET_STATS_THRESHOLD_CMDID"); + wmi_buf_free(buf); + } +} + #endif /* WLAN_FEATURE_LINK_LAYER_STATS */ /**