From cfbb8952fffd32d4531a18f93b237cf472c863b2 Mon Sep 17 00:00:00 2001 From: Soumya Bhat Date: Tue, 3 Oct 2017 15:04:09 +0530 Subject: [PATCH] qcacmn: Tx packet capture Add support to send MSDU, mgmt. and ctrl payload along with metadata to upper layer callback FR 42132 Change-Id: Ie751322c7c15419ea908538e9e8687b64693fcfa CRs-Fixed:2068486 --- dp/inc/cdp_txrx_cmn_struct.h | 9 ++++++ dp/inc/cdp_txrx_ctrl.h | 10 +++++++ dp/inc/cdp_txrx_ops.h | 3 ++ dp/wifi3.0/dp_htt.c | 44 +++++++++++++++++++++++++++- dp/wifi3.0/dp_main.c | 49 +++++++++++++++++++++++++++++++ dp/wifi3.0/dp_tx.c | 57 ++++++++++++++++++++++++++++++++++++ dp/wifi3.0/dp_types.h | 2 ++ 7 files changed, 173 insertions(+), 1 deletion(-) diff --git a/dp/inc/cdp_txrx_cmn_struct.h b/dp/inc/cdp_txrx_cmn_struct.h index 36be353f60..477b8d120f 100644 --- a/dp/inc/cdp_txrx_cmn_struct.h +++ b/dp/inc/cdp_txrx_cmn_struct.h @@ -531,6 +531,15 @@ struct cdp_soc_t { struct ol_if_ops *ol_ops; }; +/* + * cdp_pdev_param_type: different types of parameters + * to set values in pdev + * @CDP_ENABLE_TX_CAPTURE: Enable Tx capture feature + */ +enum cdp_pdev_param_type { + CDP_CONFIG_TX_CAPTURE, +}; + /* * cdp_vdev_param_type: different types of parameters * to set values in vdev diff --git a/dp/inc/cdp_txrx_ctrl.h b/dp/inc/cdp_txrx_ctrl.h index 3371c20f19..5572b0d860 100644 --- a/dp/inc/cdp_txrx_ctrl.h +++ b/dp/inc/cdp_txrx_ctrl.h @@ -389,6 +389,16 @@ cdp_peer_set_nawds(ol_txrx_soc_handle soc, return; } +static inline void cdp_txrx_set_pdev_param(ol_txrx_soc_handle soc, + struct cdp_pdev *pdev, enum cdp_pdev_param_type type, + uint8_t val) +{ + if (soc->ops->ctrl_ops->txrx_set_pdev_param) + return soc->ops->ctrl_ops->txrx_set_pdev_param + (pdev, type, val); + +} + /** * @brief Subscribe to a specified WDI event. * @details diff --git a/dp/inc/cdp_txrx_ops.h b/dp/inc/cdp_txrx_ops.h index b028b19675..f6bc93a093 100644 --- a/dp/inc/cdp_txrx_ops.h +++ b/dp/inc/cdp_txrx_ops.h @@ -415,6 +415,9 @@ struct cdp_ctrl_ops { void (*txrx_update_mgmt_txpow_vdev)(struct cdp_vdev *vdev, uint8_t subtype, uint8_t tx_power); + + void (*txrx_set_pdev_param)(struct cdp_pdev *pdev, + enum cdp_pdev_param_type type, uint8_t val); }; struct cdp_me_ops { diff --git a/dp/wifi3.0/dp_htt.c b/dp/wifi3.0/dp_htt.c index 12266bca46..e641bc5847 100644 --- a/dp/wifi3.0/dp_htt.c +++ b/dp/wifi3.0/dp_htt.c @@ -44,6 +44,8 @@ do { \ htt_htc_misc_pkt_list_add(soc, pkt); \ } while (0) +#define HTT_MGMT_CTRL_TLV_RESERVERD_LEN 12 + /* * dp_tx_stats_update() - Update per-peer statistics * @soc: Datapath soc handle @@ -1789,6 +1791,42 @@ static void dp_process_ppdu_stats_user_common_array_tlv(struct dp_pdev *pdev, HTT_PPDU_STATS_ARRAY_ITEM_TLV_TX_DUR_GET(*tag_buf); } +/* + * dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv: Process + * htt_ppdu_stats_tx_mgmtctrl_payload_tlv + * @pdev: DP PDEV handle + * @tag_buf: buffer containing the htt_ppdu_stats_tx_mgmtctrl_payload_tlv + * @length: tlv_length + * + * return:void + */ +static void dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv( + struct dp_pdev *pdev, uint32_t *tag_buf, uint32_t length) +{ + htt_ppdu_stats_tx_mgmtctrl_payload_tlv *dp_stats_buf = + (htt_ppdu_stats_tx_mgmtctrl_payload_tlv *)tag_buf; + + qdf_nbuf_t nbuf = NULL; + + uint32_t payload_size = length - HTT_MGMT_CTRL_TLV_RESERVERD_LEN; + + nbuf = qdf_nbuf_alloc(pdev->soc->osdev, payload_size, 0, 4, true); + + if (!nbuf) { + QDF_TRACE(QDF_MODULE_ID_TXRX, QDF_TRACE_LEVEL_ERROR, + "Nbuf Allocation failed for Mgmt. payload"); + qdf_assert(0); + return; + } + + qdf_nbuf_put_tail(nbuf, payload_size); + qdf_mem_copy(qdf_nbuf_data(nbuf), dp_stats_buf->payload, payload_size); + + dp_wdi_event_handler(WDI_EVENT_TX_MGMT_CTRL, pdev->soc, + nbuf, HTT_INVALID_PEER, + WDI_NO_VAL, pdev->pdev_id); +} + /** * dp_process_ppdu_tag(): Function to process the PPDU TLVs * @soc: DP Physical device (radio) handle @@ -1838,6 +1876,10 @@ static void dp_process_ppdu_tag(struct dp_pdev *pdev, uint32_t *tag_buf, dp_process_ppdu_stats_user_common_array_tlv(pdev, tag_buf); break; + case HTT_PPDU_STATS_TX_MGMTCTRL_PAYLOAD_TLV: + dp_process_ppdu_stats_tx_mgmtctrl_payload_tlv(pdev, + tag_buf, tlv_len); + break; default: break; } @@ -1908,7 +1950,7 @@ static void dp_txrx_ppdu_stats_handler(struct dp_soc *soc, int status; int i; - if (!pdev->enhanced_stats_en) + if (!pdev->enhanced_stats_en && !pdev->tx_sniffer_enable) return; if (!pdev->tx_ppdu_info.buf) { diff --git a/dp/wifi3.0/dp_main.c b/dp/wifi3.0/dp_main.c index 3ca1cca359..09306b95da 100644 --- a/dp/wifi3.0/dp_main.c +++ b/dp/wifi3.0/dp_main.c @@ -4795,6 +4795,30 @@ dp_ppdu_ring_cfg(struct dp_pdev *pdev) RX_BUFFER_SIZE, &htt_tlv_filter); } +/* + * dp_config_tx_capture()- API to enable/disable tx capture + * @pdev_handle: DP_PDEV handle + * @val: user provided value + * + * Return: void + */ +static void +dp_config_tx_capture(struct cdp_pdev *pdev_handle, int val) +{ + struct dp_pdev *pdev = (struct dp_pdev *)pdev_handle; + + if (val) { + pdev->tx_sniffer_enable = 1; + dp_h2t_cfg_stats_msg_send(pdev, 0xffff); + } else { + pdev->tx_sniffer_enable = 0; + + if (!pdev->enhanced_stats_en) + dp_h2t_cfg_stats_msg_send(pdev, 0); + } + +} + /* * dp_enable_enhanced_stats()- API to enable enhanced statistcs * @pdev_handle: DP_PDEV handle @@ -4821,7 +4845,11 @@ static void dp_disable_enhanced_stats(struct cdp_pdev *pdev_handle) { struct dp_pdev *pdev = (struct dp_pdev *)pdev_handle; + pdev->enhanced_stats_en = 0; + + if (!pdev->tx_sniffer_enable) + dp_h2t_cfg_stats_msg_send(pdev, 0); } /* @@ -4866,6 +4894,26 @@ dp_get_fw_peer_stats(struct cdp_pdev *pdev_handle, uint8_t *mac_addr, } +/* + * dp_set_pdev_param: function to set parameters in pdev + * @pdev_handle: DP pdev handle + * @param: parameter type to be set + * @val: value of parameter to be set + * + * return: void + */ +static void dp_set_pdev_param(struct cdp_pdev *pdev_handle, + enum cdp_pdev_param_type param, uint8_t val) +{ + switch (param) { + case CDP_CONFIG_TX_CAPTURE: + dp_config_tx_capture(pdev_handle, val); + break; + default: + break; + } +} + /* * dp_set_vdev_param: function to set parameters in vdev * @param: parameter type to be set @@ -5374,6 +5422,7 @@ static struct cdp_ctrl_ops dp_ops_ctrl = { /* TODO: Add other functions */ .txrx_wdi_event_sub = dp_wdi_event_sub, .txrx_wdi_event_unsub = dp_wdi_event_unsub, + .txrx_set_pdev_param = dp_set_pdev_param, }; static struct cdp_me_ops dp_ops_me = { diff --git a/dp/wifi3.0/dp_tx.c b/dp/wifi3.0/dp_tx.c index bcb372355a..c70bea2cb1 100644 --- a/dp/wifi3.0/dp_tx.c +++ b/dp/wifi3.0/dp_tx.c @@ -1731,6 +1731,56 @@ static void dp_tx_inspect_handler(struct dp_tx_desc_s *tx_desc, uint8_t *status) dp_tx_desc_release(tx_desc, tx_desc->pool_id); } +#ifdef FEATURE_PERPKT_INFO +static QDF_STATUS +dp_send_compl_to_stack(struct dp_soc *soc, struct dp_tx_desc_s *desc, + uint16_t peer_id, uint16_t ppdu_id) +{ + struct tx_capture_hdr *ppdu_hdr; + struct ethhdr *eh; + struct dp_peer *peer = NULL; + qdf_nbuf_t netbuf = desc->nbuf; + + if (!desc->pdev->tx_sniffer_enable) + return QDF_STATUS_E_NOSUPPORT; + + eh = (struct ethhdr *)(netbuf->data); + peer = (peer_id == HTT_INVALID_PEER) ? NULL : + dp_peer_find_by_id(soc, peer_id); + + if (!peer) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("Peer Invalid")); + return QDF_STATUS_E_INVAL; + } + + if (!qdf_nbuf_push_head(netbuf, sizeof(struct tx_capture_hdr))) { + QDF_TRACE(QDF_MODULE_ID_DP, QDF_TRACE_LEVEL_ERROR, + FL("No headroom")); + return QDF_STATUS_E_NOMEM; + } + + ppdu_hdr = (struct tx_capture_hdr *)qdf_nbuf_data(netbuf); + qdf_mem_copy(ppdu_hdr->ta, (eh->h_dest), IEEE80211_ADDR_LEN); + ppdu_hdr->ppdu_id = ppdu_id; + qdf_mem_copy(ppdu_hdr->ra, peer->mac_addr.raw, + IEEE80211_ADDR_LEN); + + dp_wdi_event_handler(WDI_EVENT_TX_DATA, soc, + netbuf, peer_id, + WDI_NO_VAL, desc->pdev->pdev_id); + + return QDF_STATUS_SUCCESS; +} +#else +static QDF_STATUS +dp_send_compl_to_stack(struct dp_soc *soc, struct dp_tx_desc_s *desc, + uint16_t peer_id, uint16_t ppdu_id) +{ + return QDF_STATUS_E_NOSUPPORT; +} +#endif + /** * dp_tx_comp_free_buf() - Free nbuf associated with the Tx Descriptor * @soc: Soc handle @@ -1743,6 +1793,10 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, { struct dp_vdev *vdev = desc->vdev; qdf_nbuf_t nbuf = desc->nbuf; + struct hal_tx_completion_status ts = {0}; + + if (desc) + hal_tx_comp_get_status(&desc->comp, &ts); /* If it is TDLS mgmt, don't unmap or free the frame */ if (desc->flags & DP_TX_DESC_FLAG_TDLS_FRAME) @@ -1769,6 +1823,9 @@ static inline void dp_tx_comp_free_buf(struct dp_soc *soc, qdf_nbuf_unmap(soc->osdev, nbuf, QDF_DMA_TO_DEVICE); + if (dp_send_compl_to_stack(soc, desc, ts.peer_id, ts.ppdu_id)) + return; + if (!vdev->mesh_vdev) { qdf_nbuf_free(nbuf); } else { diff --git a/dp/wifi3.0/dp_types.h b/dp/wifi3.0/dp_types.h index 70e221ac68..fb7460ed47 100644 --- a/dp/wifi3.0/dp_types.h +++ b/dp/wifi3.0/dp_types.h @@ -1046,6 +1046,8 @@ struct dp_pdev { uint8_t last_user; qdf_nbuf_t buf; } tx_ppdu_info; + + bool tx_sniffer_enable; }; struct dp_peer;