diff --git a/dp/inc/cdp_txrx_misc.h b/dp/inc/cdp_txrx_misc.h index 461130a31e..5c209565a4 100644 --- a/dp/inc/cdp_txrx_misc.h +++ b/dp/inc/cdp_txrx_misc.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-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 @@ -747,4 +747,71 @@ static inline void cdp_pdev_reset_bundle_require_flag(ol_txrx_soc_handle soc, return soc->ops->misc_ops->pdev_reset_bundle_require_flag( soc, pdev_id); } + +/** + * cdp_txrx_ext_stats_request(): request dp tx and rx extended stats + * @soc: soc handle + * @pdev_id: pdev id + * @req: stats request structure to fill + * + * return: status + */ +static inline QDF_STATUS +cdp_txrx_ext_stats_request(ol_txrx_soc_handle soc, uint8_t pdev_id, + struct cdp_txrx_ext_stats *req) +{ + if (!soc || !soc->ops || !soc->ops->misc_ops || !req) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + return QDF_STATUS_E_INVAL; + } + + if (soc->ops->misc_ops->txrx_ext_stats_request) + return soc->ops->misc_ops->txrx_ext_stats_request(soc, pdev_id, + req); + + return QDF_STATUS_SUCCESS; +} + +/** + * cdp_request_rx_hw_stats(): request rx hw stats + * @soc: soc handle + * @vdev_id: vdev id + * + * return: none + */ +static inline void +cdp_request_rx_hw_stats(ol_txrx_soc_handle soc, uint8_t vdev_id) +{ + if (!soc || !soc->ops || !soc->ops->misc_ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + return; + } + + if (soc->ops->misc_ops->request_rx_hw_stats) + soc->ops->misc_ops->request_rx_hw_stats(soc, vdev_id); +} + +/** + * cdp_wait_for_ext_rx_stats(): wait for reo command status for stats + * @soc: soc handle + * + * return: status + */ +static inline QDF_STATUS +cdp_wait_for_ext_rx_stats(ol_txrx_soc_handle soc) +{ + if (!soc || !soc->ops || !soc->ops->misc_ops) { + QDF_TRACE(QDF_MODULE_ID_CDP, QDF_TRACE_LEVEL_DEBUG, + "%s: Invalid Instance:", __func__); + return QDF_STATUS_E_INVAL; + } + + if (soc->ops->misc_ops->wait_for_ext_rx_stats) + return soc->ops->misc_ops->wait_for_ext_rx_stats(soc); + + return QDF_STATUS_SUCCESS; +} + #endif /* _CDP_TXRX_MISC_H_ */ diff --git a/dp/inc/cdp_txrx_mob_def.h b/dp/inc/cdp_txrx_mob_def.h index 2550bb82e8..e91753bb72 100644 --- a/dp/inc/cdp_txrx_mob_def.h +++ b/dp/inc/cdp_txrx_mob_def.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2016-2019 The Linux Foundation. All rights reserved. + * Copyright (c) 2016-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 @@ -471,4 +471,22 @@ struct ol_rx_inv_peer_params { uint8_t ta[QDF_MAC_ADDR_SIZE]; }; +/** + * cdp_txrx_ext_stats: dp extended stats + * tx_msdu_enqueue: tx msdu queued to hw + * tx_msdu_overflow: tx msdu overflow + * rx_mpdu_received: rx mpdu processed by hw + * rx_mpdu_delivered: rx mpdu received from hw + * rx_mpdu_error: rx mpdu error count + * rx_mpdu_missed: rx mpdu missed by hw + */ +struct cdp_txrx_ext_stats { + uint32_t tx_msdu_enqueue; + uint32_t tx_msdu_overflow; + uint32_t rx_mpdu_received; + uint32_t rx_mpdu_delivered; + uint32_t rx_mpdu_error; + uint32_t rx_mpdu_missed; +}; + #endif /* __CDP_TXRX_MOB_DEF_H */ diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index 372d5dcde4..22346cc58b 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -1238,6 +1238,11 @@ struct cdp_misc_ops { uint32_t low_th); void (*pdev_reset_bundle_require_flag)(struct cdp_soc_t *soc_hdl, uint8_t pdev_id); + QDF_STATUS (*txrx_ext_stats_request)(struct cdp_soc_t *soc_hdl, + uint8_t pdev_id, + struct cdp_txrx_ext_stats *req); + void (*request_rx_hw_stats)(struct cdp_soc_t *soc_hdl, uint8_t vdev_id); + QDF_STATUS (*wait_for_ext_rx_stats)(struct cdp_soc_t *soc_hdl); }; /** diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 769c4f9546..7a969ac481 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -2807,6 +2807,17 @@ static void dp_enable_verbose_debug(struct dp_soc *soc) } #endif +#ifdef WLAN_FEATURE_STATS_EXT +static inline void dp_create_ext_stats_event(struct dp_soc *soc) +{ + qdf_event_create(&soc->rx_hw_stats_event); +} +#else +static inline void dp_create_ext_stats_event(struct dp_soc *soc) +{ +} +#endif + /* * dp_soc_cmn_setup() - Common SoC level initializion * @soc: Datapath SOC handle @@ -3055,6 +3066,7 @@ static int dp_soc_cmn_setup(struct dp_soc *soc) wlan_cfg_get_defrag_timeout_check(soc_cfg_ctx); qdf_spinlock_create(&soc->rx.defrag.defrag_lock); + dp_create_ext_stats_event(soc); out: /* * set the fragment destination ring @@ -5302,6 +5314,26 @@ static inline void dp_peer_rx_bufq_resources_init(struct dp_peer *peer) } #endif +#ifdef WLAN_FEATURE_STATS_EXT +/* + * dp_set_ignore_reo_status_cb() - set ignore reo status cb flag + * @soc: dp soc handle + * @flag: flag to set or reset + * + * Return: None + */ +static inline void dp_set_ignore_reo_status_cb(struct dp_soc *soc, + bool flag) +{ + soc->ignore_reo_status_cb = flag; +} +#else +static inline void dp_set_ignore_reo_status_cb(struct dp_soc *soc, + bool flag) +{ +} +#endif + /* * dp_peer_create_wifi3() - attach txrx peer * @soc_hdl: Datapath soc handle @@ -5458,6 +5490,12 @@ static void *dp_peer_create_wifi3(struct cdp_soc_t *soc_hdl, uint8_t vdev_id, vdev->vap_self_peer = peer; } + if (wlan_op_mode_sta == vdev->opmode && + qdf_mem_cmp(peer->mac_addr.raw, vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE) != 0) { + dp_set_ignore_reo_status_cb(soc, false); + } + for (i = 0; i < DP_MAX_TIDS; i++) qdf_spinlock_create(&peer->rx_tid[i].tid_lock); @@ -6244,6 +6282,12 @@ static QDF_STATUS dp_peer_delete_wifi3(struct cdp_soc_t *soc, uint8_t vdev_id, qdf_spinlock_destroy(&peer->peer_info_lock); dp_peer_multipass_list_remove(peer); + if (wlan_op_mode_sta == peer->vdev->opmode && + qdf_mem_cmp(peer->mac_addr.raw, peer->vdev->mac_addr.raw, + QDF_MAC_ADDR_SIZE) != 0) { + dp_set_ignore_reo_status_cb(peer->vdev->pdev->soc, true); + } + /* * Remove the reference added during peer_attach. * The peer will still be left allocated until the @@ -9983,6 +10027,125 @@ dp_txrx_post_data_stall_event(struct cdp_soc_t *soc_hdl, } #endif /* WLAN_SUPPORT_DATA_STALL */ +#ifdef WLAN_FEATURE_STATS_EXT +/* rx hw stats event wait timeout in ms */ +#define DP_REO_STATUS_STATS_TIMEOUT 1000 +/** + * dp_txrx_ext_stats_request - request dp txrx extended stats request + * @soc_hdl: soc handle + * @pdev_id: pdev id + * @req: stats request + * + * Return: QDF_STATUS + */ +static QDF_STATUS +dp_txrx_ext_stats_request(struct cdp_soc_t *soc_hdl, uint8_t pdev_id, + struct cdp_txrx_ext_stats *req) +{ + struct dp_soc *soc = (struct dp_soc *)soc_hdl; + struct dp_pdev *pdev = dp_get_pdev_from_soc_pdev_id_wifi3(soc, pdev_id); + + if (!pdev) { + dp_err("pdev is null"); + return QDF_STATUS_E_INVAL; + } + + dp_aggregate_pdev_stats(pdev); + + req->tx_msdu_enqueue = pdev->stats.tx_i.processed.num; + req->tx_msdu_overflow = pdev->stats.tx_i.dropped.ring_full; + req->rx_mpdu_received = soc->ext_stats.rx_mpdu_received; + req->rx_mpdu_delivered = soc->ext_stats.rx_mpdu_received; + req->rx_mpdu_missed = soc->ext_stats.rx_mpdu_missed; + req->rx_mpdu_error = soc->stats.rx.err_ring_pkts - + soc->stats.rx.rx_frags; + + return QDF_STATUS_SUCCESS; +} + +/** + * dp_rx_hw_stats_cb - request rx hw stats response callback + * @soc: soc handle + * @cb_ctxt: callback context + * @reo_status: reo command response status + * + * Return: None + */ +static void dp_rx_hw_stats_cb(struct dp_soc *soc, void *cb_ctxt, + union hal_reo_status *reo_status) +{ + struct dp_rx_tid *rx_tid = (struct dp_rx_tid *)cb_ctxt; + struct hal_reo_queue_status *queue_status = &reo_status->queue_status; + + if (soc->ignore_reo_status_cb) { + qdf_event_set(&soc->rx_hw_stats_event); + return; + } + + if (queue_status->header.status != HAL_REO_CMD_SUCCESS) { + dp_info("REO stats failure %d for TID %d", + queue_status->header.status, rx_tid->tid); + return; + } + + soc->ext_stats.rx_mpdu_received += queue_status->mpdu_frms_cnt; + soc->ext_stats.rx_mpdu_missed += queue_status->late_recv_mpdu_cnt; + + if (rx_tid->tid == (DP_MAX_TIDS - 1)) + qdf_event_set(&soc->rx_hw_stats_event); +} + +/** + * dp_request_rx_hw_stats - request rx hardware stats + * @soc_hdl: soc handle + * @vdev_id: vdev id + * + * Return: None + */ +static void +dp_request_rx_hw_stats(struct cdp_soc_t *soc_hdl, uint8_t vdev_id) +{ + struct dp_soc *soc = (struct dp_soc *)soc_hdl; + struct dp_vdev *vdev = dp_get_vdev_from_soc_vdev_id_wifi3(soc, vdev_id); + struct dp_peer *peer; + + if (!vdev) { + dp_err("vdev is null"); + qdf_event_set(&soc->rx_hw_stats_event); + return; + } + + peer = vdev->vap_bss_peer; + + if (!peer || peer->delete_in_progress) { + dp_err("Peer deletion in progress"); + qdf_event_set(&soc->rx_hw_stats_event); + return; + } + + qdf_event_reset(&soc->rx_hw_stats_event); + dp_peer_rxtid_stats(peer, dp_rx_hw_stats_cb, NULL); +} + +/** + * dp_wait_for_ext_rx_stats - wait for rx reo status for rx stats + * @soc_hdl: cdp opaque soc handle + * + * Return: status + */ +static QDF_STATUS +dp_wait_for_ext_rx_stats(struct cdp_soc_t *soc_hdl) +{ + struct dp_soc *soc = (struct dp_soc *)soc_hdl; + QDF_STATUS status; + + status = qdf_wait_single_event(&soc->rx_hw_stats_event, + DP_REO_STATUS_STATS_TIMEOUT); + + return status; +} +#endif /* WLAN_FEATURE_STATS_EXT */ + #ifdef DP_PEER_EXTENDED_API static struct cdp_misc_ops dp_ops_misc = { #ifdef FEATURE_WLAN_TDLS @@ -10002,6 +10165,12 @@ static struct cdp_misc_ops dp_ops_misc = { .txrx_data_stall_cb_deregister = dp_deregister_data_stall_detect_cb, .txrx_post_data_stall_event = dp_txrx_post_data_stall_event, #endif + +#ifdef WLAN_FEATURE_STATS_EXT + .txrx_ext_stats_request = dp_txrx_ext_stats_request, + .request_rx_hw_stats = dp_request_rx_hw_stats, + .wait_for_ext_rx_stats = dp_wait_for_ext_rx_stats, +#endif }; #endif diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 9ec74261b3..37c3e07cbb 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1163,6 +1163,17 @@ struct dp_soc { qdf_atomic_t ipa_pipes_enabled; #endif +#ifdef WLAN_FEATURE_STATS_EXT + struct { + uint32_t rx_mpdu_received; + uint32_t rx_mpdu_missed; + } ext_stats; + qdf_event_t rx_hw_stats_event; + + /* Ignore reo command queue status during peer delete */ + bool ignore_reo_status_cb; +#endif + /* Smart monitor capability for HKv2 */ uint8_t hw_nac_monitor_support; /* Flag to indicate if HTT v2 is enabled*/