diff --git a/core/dp/htt/htt_rx.c b/core/dp/htt/htt_rx.c index 347e59a5f0..0bde4d4d53 100644 --- a/core/dp/htt/htt_rx.c +++ b/core/dp/htt/htt_rx.c @@ -60,6 +60,7 @@ #include #include #endif +#include #ifdef HTT_DEBUG_DATA #define HTT_PKT_DUMP(x) x @@ -1996,6 +1997,7 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, uint8_t offload_ind, frag_ind; uint8_t peer_id; struct htt_host_rx_desc_base *rx_desc; + enum rx_pkt_fate status = RX_PKT_FATE_SUCCESS; HTT_ASSERT1(htt_rx_in_order_ring_elems(pdev) != 0); @@ -2084,6 +2086,15 @@ htt_rx_amsdu_rx_in_order_pop_ll(htt_pdev_handle pdev, msdu_count--; + /* calling callback function for packet logging */ + if (pdev->rx_pkt_dump_cb) { + if (qdf_unlikely((*((u_int8_t *) + &rx_desc->fw_desc.u.val)) & + FW_RX_DESC_ANY_ERR_M)) + status = RX_PKT_FATE_FW_DROP_INVALID; + pdev->rx_pkt_dump_cb(msdu, peer_id, status); + } + if (qdf_unlikely((*((u_int8_t *) &rx_desc->fw_desc.u.val)) & FW_RX_DESC_ANY_ERR_M)) { uint8_t tid = @@ -3537,3 +3548,51 @@ int htt_rx_ipa_uc_detach(struct htt_pdev_t *pdev) return 0; } #endif /* IPA_OFFLOAD */ + +/** + * htt_register_rx_pkt_dump_callback() - registers callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * @callback: callback to get rx pkt status and + * call callback to do rx packet dump + * + * This function is used to register the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb callback) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback register unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = callback; +} + +/** + * htt_deregister_rx_pkt_dump_callback() - deregisters callback to + * get rx pkt status and call callback to do rx packet dump + * + * @pdev: htt pdev handle + * + * This function is used to deregister the callback to get + * rx pkt status and call callback to do rx packet dump + * + * Return: None + * + */ +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev) +{ + if (!pdev) { + qdf_print("%s: htt pdev is NULL, rx packet status callback deregister unsuccessful\n", + __func__); + return; + } + pdev->rx_pkt_dump_cb = NULL; +} + diff --git a/core/dp/htt/htt_types.h b/core/dp/htt/htt_types.h index 0bd12e6a1e..cb4e885d55 100644 --- a/core/dp/htt/htt_types.h +++ b/core/dp/htt/htt_types.h @@ -35,6 +35,7 @@ #include /* qdf_atomic_inc */ #include /* qdf_nbuf_t */ #include /* HTC_PACKET */ +#include #define DEBUG_DMA_DONE @@ -413,6 +414,10 @@ struct htt_pdev_t { qdf_spinlock_t rx_buff_list_lock; int rx_buff_index; #endif + + /* callback function for packetdump */ + tp_rx_pkt_dump_cb rx_pkt_dump_cb; + struct mon_channel mon_ch_info; }; diff --git a/core/dp/ol/inc/ol_htt_api.h b/core/dp/ol/inc/ol_htt_api.h index 9f6a0233b6..b3eb6cfed2 100644 --- a/core/dp/ol/inc/ol_htt_api.h +++ b/core/dp/ol/inc/ol_htt_api.h @@ -385,5 +385,11 @@ static inline void htt_clear_bundle_stats(struct htt_pdev_t *pdev) #endif void htt_mark_first_wakeup_packet(htt_pdev_handle pdev, uint8_t value); +typedef void (*tp_rx_pkt_dump_cb)(qdf_nbuf_t msdu, uint8_t peer_id, + uint8_t status); +void htt_register_rx_pkt_dump_callback(struct htt_pdev_t *pdev, + tp_rx_pkt_dump_cb ol_rx_pkt_dump_call); +void htt_deregister_rx_pkt_dump_callback(struct htt_pdev_t *pdev); +void ol_rx_pkt_dump_call(qdf_nbuf_t msdu, uint8_t peer_id, uint8_t status); #endif /* _OL_HTT_API__H_ */ diff --git a/core/dp/ol/inc/ol_txrx_api.h b/core/dp/ol/inc/ol_txrx_api.h index 7aeb40c218..b0d56ee1df 100644 --- a/core/dp/ol/inc/ol_txrx_api.h +++ b/core/dp/ol/inc/ol_txrx_api.h @@ -60,4 +60,10 @@ enum ol_sec_type { ol_sec_type_types }; +typedef void (*tp_ol_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb); +void ol_deregister_packetdump_callback(void); + #endif /* _OL_TXRX_API__H_ */ diff --git a/core/dp/txrx/ol_rx.c b/core/dp/txrx/ol_rx.c index 31ce73b72b..6fc3784aa0 100644 --- a/core/dp/txrx/ol_rx.c +++ b/core/dp/txrx/ol_rx.c @@ -58,6 +58,7 @@ #include #include #include +#include "pktlog_ac_fmt.h" #include @@ -1420,6 +1421,51 @@ ol_rx_in_order_indication_handler(ol_txrx_pdev_handle pdev, peer->rx_opt_proc(vdev, peer, tid, head_msdu); } +/** + * ol_rx_pkt_dump_call() - updates status and + * calls packetdump callback to log rx packet + * + * @msdu: rx packet + * @peer_id: peer id + * @status: status of rx packet + * + * This function is used to update the status of rx packet + * and then calls packetdump callback to log that packet. + * + * Return: None + * + */ +void ol_rx_pkt_dump_call( + qdf_nbuf_t msdu, + uint8_t peer_id, + uint8_t status) +{ + v_CONTEXT_t vos_context; + ol_txrx_pdev_handle pdev; + struct ol_txrx_peer_t *peer = NULL; + + vos_context = cds_get_global_context(); + pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + if (pdev->ol_rx_packetdump_cb) { + peer = ol_txrx_peer_find_by_id(pdev, peer_id); + if (!peer) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: peer with peer id %d is NULL", __func__, + peer_id); + return; + } + pdev->ol_rx_packetdump_cb(msdu, status, peer->vdev->vdev_id, + RX_DATA_PKT); + } +} + /* the msdu_list passed here must be NULL terminated */ void ol_rx_in_order_deliver(struct ol_txrx_vdev_t *vdev, diff --git a/core/dp/txrx/ol_tx_desc.c b/core/dp/txrx/ol_tx_desc.c index 439df76f6e..8905383a6e 100644 --- a/core/dp/txrx/ol_tx_desc.c +++ b/core/dp/txrx/ol_tx_desc.c @@ -92,8 +92,6 @@ static inline void ol_tx_desc_reset_timestamp(struct ol_tx_desc_t *tx_desc) } #endif -#ifdef CONFIG_HL_SUPPORT - /** * ol_tx_desc_vdev_update() - vedv assign. * @tx_desc: tx descriptor pointer @@ -107,15 +105,6 @@ ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, { tx_desc->vdev = vdev; } -#else - -static inline void -ol_tx_desc_vdev_update(struct ol_tx_desc_t *tx_desc, - struct ol_txrx_vdev_t *vdev) -{ - return; -} -#endif #ifdef CONFIG_PER_VDEV_TX_DESC_POOL @@ -223,6 +212,7 @@ struct ol_tx_desc_t *ol_tx_desc_alloc(struct ol_txrx_pdev_t *pdev, } ol_tx_desc_sanity_checks(pdev, tx_desc); ol_tx_desc_compute_delay(tx_desc); + ol_tx_desc_vdev_update(tx_desc, vdev); qdf_atomic_inc(&tx_desc->ref_cnt); } else { pool->pkt_drop_no_desc++; diff --git a/core/dp/txrx/ol_tx_send.c b/core/dp/txrx/ol_tx_send.c index 2ca1a8d7fa..58b40c9228 100644 --- a/core/dp/txrx/ol_tx_send.c +++ b/core/dp/txrx/ol_tx_send.c @@ -60,7 +60,7 @@ #endif #include #include - +#include #ifdef TX_CREDIT_RECLAIM_SUPPORT @@ -569,6 +569,13 @@ ol_tx_completion_handler(ol_txrx_pdev_handle pdev, tx_desc->status = status; netbuf = tx_desc->netbuf; QDF_NBUF_UPDATE_TX_PKT_COUNT(netbuf, QDF_NBUF_TX_PKT_FREE); + + if (tx_desc->pkt_type != OL_TX_FRM_TSO) { + if (pdev->ol_tx_packetdump_cb) + pdev->ol_tx_packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_DATA_PKT); + } + DPTRACE(qdf_dp_trace_ptr(netbuf, QDF_DP_TRACE_FREE_PACKET_PTR_RECORD, qdf_nbuf_data_addr(netbuf), @@ -791,6 +798,10 @@ ol_tx_single_completion_handler(ol_txrx_pdev_handle pdev, /* Do one shot statistics */ TXRX_STATS_UPDATE_TX_STATS(pdev, status, 1, qdf_nbuf_len(netbuf)); + if (pdev->ol_tx_packetdump_cb) + pdev->ol_tx_packetdump_cb(netbuf, status, + tx_desc->vdev->vdev_id, TX_MGMT_PKT); + if (OL_TX_DESC_NO_REFS(tx_desc)) { ol_tx_desc_frame_free_nonstd(pdev, tx_desc, status != htt_tx_status_ok); @@ -1204,3 +1215,57 @@ ol_tx_delay_compute(struct ol_txrx_pdev_t *pdev, } #endif /* QCA_COMPUTE_TX_DELAY */ + +/** + * ol_register_packetdump_callback() - registers + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler. + * + * @ol_tx_packetdump_cb: tx packetdump cb + * @ol_rx_packetdump_cb: rx packetdump cb + * + * This function is used to register tx data pkt, tx mgmt. + * pkt and rx data pkt dump callback + * + * Return: None + * + */ +void ol_register_packetdump_callback(tp_ol_packetdump_cb ol_tx_packetdump_cb, + tp_ol_packetdump_cb ol_rx_packetdump_cb) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = ol_tx_packetdump_cb; + pdev->ol_rx_packetdump_cb = ol_rx_packetdump_cb; +} + +/** + * ol_deregister_packetdump_callback() - deregidters + * tx data packet, tx mgmt. packet and rx data packet + * dump callback handler + * + * This function is used to deregidter tx data pkt., + * tx mgmt. pkt and rx data pkt. dump callback + * + * Return: None + * + */ +void ol_deregister_packetdump_callback(void) +{ + ol_txrx_pdev_handle pdev = cds_get_context(QDF_MODULE_ID_TXRX); + + if (!pdev) { + TXRX_PRINT(TXRX_PRINT_LEVEL_ERR, + "%s: pdev is NULL", __func__); + return; + } + + pdev->ol_tx_packetdump_cb = NULL; + pdev->ol_rx_packetdump_cb = NULL; +} diff --git a/core/dp/txrx/ol_txrx.c b/core/dp/txrx/ol_txrx.c index d8dfacf191..2d1ef121a4 100644 --- a/core/dp/txrx/ol_txrx.c +++ b/core/dp/txrx/ol_txrx.c @@ -1087,6 +1087,8 @@ ol_txrx_pdev_attach(ol_txrx_soc_handle soc, void *pctrl_pdev, if (!pdev->htt_pdev) goto fail3; + htt_register_rx_pkt_dump_callback(pdev->htt_pdev, + ol_rx_pkt_dump_call); return pdev; fail3: @@ -1734,6 +1736,7 @@ void ol_txrx_pdev_detach(void *ppdev, int force) htt_tx_desc_free(pdev->htt_pdev, htt_tx_desc); } + htt_deregister_rx_pkt_dump_callback(pdev->htt_pdev); ol_tx_deregister_flow_control(pdev); /* Stop the communication between HTT and target at first */ htt_detach_target(pdev->htt_pdev); diff --git a/core/dp/txrx/ol_txrx_types.h b/core/dp/txrx/ol_txrx_types.h index 66f8a0f61c..0a62ba308b 100644 --- a/core/dp/txrx/ol_txrx_types.h +++ b/core/dp/txrx/ol_txrx_types.h @@ -184,9 +184,9 @@ struct ol_tx_desc_t { * This field is filled in with the ol_tx_frm_type enum. */ uint8_t pkt_type; -#if defined(CONFIG_HL_SUPPORT) + struct ol_txrx_vdev_t *vdev; -#endif + void *txq; #ifdef QCA_SUPPORT_SW_TXRX_ENCAP @@ -645,6 +645,10 @@ struct ol_txrx_pdev_t { } callbacks[OL_TXRX_MGMT_NUM_TYPES]; } tx_mgmt; + /* packetdump callback functions */ + tp_ol_packetdump_cb ol_tx_packetdump_cb; + tp_ol_packetdump_cb ol_rx_packetdump_cb; + struct { uint16_t pool_size; uint16_t num_free; diff --git a/core/hdd/src/wlan_hdd_assoc.c b/core/hdd/src/wlan_hdd_assoc.c index 1f7a06e874..f6266c3bf3 100644 --- a/core/hdd/src/wlan_hdd_assoc.c +++ b/core/hdd/src/wlan_hdd_assoc.c @@ -62,6 +62,7 @@ #include #include #include +#include /* These are needed to recognize WPA and RSN suite types */ #define HDD_WPA_OUI_SIZE 4 @@ -1538,6 +1539,8 @@ static QDF_STATUS hdd_dis_connect_handler(hdd_adapter_t *pAdapter, hdd_clear_roam_profile_ie(pAdapter); hdd_wmm_init(pAdapter); + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); /* indicate 'disconnect' status to wpa_supplicant... */ hdd_send_association_event(dev, pRoamInfo); @@ -2815,6 +2818,9 @@ static QDF_STATUS hdd_association_completion_handler(hdd_adapter_t *pAdapter, MAC_ADDR_ARRAY(pWextState->req_bssId.bytes), roamResult, roamStatus); + hdd_err("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + /* inform association failure event to nl80211 */ if (eCSR_ROAM_RESULT_ASSOC_FAIL_CON_CHANNEL == roamResult) { diff --git a/core/hdd/src/wlan_hdd_power.c b/core/hdd/src/wlan_hdd_power.c index a49a3377ce..caf6e90fa5 100644 --- a/core/hdd/src/wlan_hdd_power.c +++ b/core/hdd/src/wlan_hdd_power.c @@ -76,6 +76,7 @@ #include "cdp_txrx_flow_ctrl_v2.h" #include "pld_common.h" #include "wlan_hdd_driver_ops.h" +#include /* Preprocessor definitions and constants */ #define HDD_SSR_BRING_UP_TIME 30000 @@ -1460,6 +1461,10 @@ QDF_STATUS hdd_wlan_shutdown(void) } cds_clear_concurrent_session_count(); + + hdd_info("Invoking packetdump deregistration API"); + wlan_deregister_txrx_packetdump(); + hdd_cleanup_scan_queue(pHddCtx); hdd_ipa_uc_ssr_deinit(); hdd_reset_all_adapters(pHddCtx); diff --git a/core/sme/inc/csr_api.h b/core/sme/inc/csr_api.h index bd3efff03c..8eacac835a 100644 --- a/core/sme/inc/csr_api.h +++ b/core/sme/inc/csr_api.h @@ -1757,5 +1757,6 @@ static inline void csr_roam_fill_tdls_info(tpAniSirGlobal mac_ctx, tCsrRoamInfo tpSirSmeJoinRsp join_rsp) {} #endif +void csr_packetdump_timer_stop(void); #endif diff --git a/core/sme/inc/csr_internal.h b/core/sme/inc/csr_internal.h index c7db8fe155..200c0d4348 100644 --- a/core/sme/inc/csr_internal.h +++ b/core/sme/inc/csr_internal.h @@ -1048,6 +1048,7 @@ typedef struct tagCsrRoamStruct { uint32_t deauthRspStatus; uint8_t *pReassocResp; /* reassociation response from new AP */ uint16_t reassocRespLen; /* length of reassociation response */ + qdf_mc_timer_t packetdump_timer; } tCsrRoamStruct; #define GET_NEXT_ROAM_ID(pRoamStruct) (((pRoamStruct)->nextRoamId + 1 == 0) ? \ diff --git a/core/sme/src/csr/csr_api_roam.c b/core/sme/src/csr/csr_api_roam.c index b161c38513..7ee14b2e21 100644 --- a/core/sme/src/csr/csr_api_roam.c +++ b/core/sme/src/csr/csr_api_roam.c @@ -57,6 +57,7 @@ #include "cds_concurrency.h" #include "sme_nan_datapath.h" #include "pld_common.h" +#include #define MAX_PWR_FCC_CHAN_12 8 #define MAX_PWR_FCC_CHAN_13 2 @@ -85,6 +86,10 @@ #define MAX_CB_VALUE_IN_INI (2) #define MAX_SOCIAL_CHANNELS 3 + +/* packet dump timer duration of 60 secs */ +#define PKT_DUMP_TIMER_DURATION 60 + /* Choose the largest possible value that can be accomodates in 8 bit signed */ /* variable. */ #define SNR_HACK_BMPS (127) @@ -993,6 +998,58 @@ void csr_set_global_cfgs(tpAniSirGlobal pMac) csr_set_default_dot11_mode(pMac); } +/** + * csr_packetdump_timer_handler() - packet dump timer + * handler + * @pv: user data + * + * This function is used to handle packet dump timer + * + * Return: None + * + */ +static void csr_packetdump_timer_handler(void *pv) +{ + QDF_TRACE(QDF_MODULE_ID_SME, QDF_TRACE_LEVEL_INFO, + "%s Invoking packetdump deregistration API", __func__); + wlan_deregister_txrx_packetdump(); +} + +/** + * csr_packetdump_timer_stop() - stops packet dump timer + * + * This function is used to stop packet dump timer + * + * Return: None + * + */ +void csr_packetdump_timer_stop(void) +{ + QDF_STATUS status; + tHalHandle hal; + tpAniSirGlobal mac; + v_CONTEXT_t vos_ctx_ptr; + + /* get the global voss context */ + vos_ctx_ptr = cds_get_global_context(); + if (vos_ctx_ptr == NULL) { + QDF_ASSERT(0); + return; + } + + hal = cds_get_context(QDF_MODULE_ID_SME); + if (hal == NULL) { + QDF_ASSERT(0); + return; + } + + mac = PMAC_STRUCT(hal); + status = qdf_mc_timer_stop(&mac->roam.packetdump_timer); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(mac, LOGE, FL("cannot stop packetdump timer")); + } +} + QDF_STATUS csr_roam_open(tpAniSirGlobal pMac) { QDF_STATUS status = QDF_STATUS_SUCCESS; @@ -1019,6 +1076,14 @@ QDF_STATUS csr_roam_open(tpAniSirGlobal pMac) ("cannot allocate memory for WaitForKey time out timer")); break; } + status = qdf_mc_timer_init(&pMac->roam.packetdump_timer, + QDF_TIMER_TYPE_SW, csr_packetdump_timer_handler, + pMac); + if (!QDF_IS_STATUS_SUCCESS(status)) { + sms_log(pMac, LOGE, + FL("cannot allocate memory for packetdump timer")); + break; + } status = qdf_mc_timer_init(&pMac->roam.tlStatsReqInfo.hTlStatsTimer, QDF_TIMER_TYPE_SW, @@ -1043,6 +1108,8 @@ QDF_STATUS csr_roam_close(tpAniSirGlobal pMac) qdf_mc_timer_destroy(&pMac->roam.hTimerWaitForKey); qdf_mc_timer_stop(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); qdf_mc_timer_destroy(&pMac->roam.tlStatsReqInfo.hTlStatsTimer); + qdf_mc_timer_stop(&pMac->roam.packetdump_timer); + qdf_mc_timer_destroy(&pMac->roam.packetdump_timer); return QDF_STATUS_SUCCESS; } @@ -13787,6 +13854,7 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, uint8_t ese_config = 0; tpCsrNeighborRoamControlInfo neigh_roam_info; uint32_t value = 0, value1 = 0; + QDF_STATUS packetdump_timer_status; if (!pSession) { sms_log(pMac, LOGE, FL(" session %d not found "), sessionId); @@ -14439,6 +14507,25 @@ QDF_STATUS csr_send_join_req_msg(tpAniSirGlobal pMac, uint32_t sessionId, csr_join_req = NULL; break; } else { + if (pProfile->csrPersona == QDF_STA_MODE) { + sms_log(pMac, LOG1, + FL(" Invoking packetdump register API")); + wlan_register_txrx_packetdump(); + packetdump_timer_status = + qdf_mc_timer_start( + &pMac->roam.packetdump_timer, + (PKT_DUMP_TIMER_DURATION * + QDF_MC_TIMER_TO_SEC_UNIT)/ + QDF_MC_TIMER_TO_MS_UNIT); + if (!QDF_IS_STATUS_SUCCESS( + packetdump_timer_status)) { + sms_log(pMac, LOGE, + FL("cannot start packetdump timer")); + sms_log(pMac, LOGE, + FL("packetdump_timer_status: %d"), + packetdump_timer_status); + } + } #ifndef WLAN_MDM_CODE_REDUCTION_OPT if (eWNI_SME_JOIN_REQ == messageType) { /* Notify QoS module that join happening */ diff --git a/core/utils/logging/inc/wlan_logging_sock_svc.h b/core/utils/logging/inc/wlan_logging_sock_svc.h index 1edb42cea6..af85ab6943 100644 --- a/core/utils/logging/inc/wlan_logging_sock_svc.h +++ b/core/utils/logging/inc/wlan_logging_sock_svc.h @@ -80,4 +80,7 @@ static inline void wlan_report_log_completion(uint32_t is_fatal, void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data); +void wlan_deregister_txrx_packetdump(void); +void wlan_register_txrx_packetdump(void); + #endif /* WLAN_LOGGING_SOCK_SVC_H */ diff --git a/core/utils/logging/src/wlan_logging_sock_svc.c b/core/utils/logging/src/wlan_logging_sock_svc.c index 5d038826fc..b353fcf771 100644 --- a/core/utils/logging/src/wlan_logging_sock_svc.c +++ b/core/utils/logging/src/wlan_logging_sock_svc.c @@ -37,10 +37,39 @@ #include #include #include -#include "pktlog_ac.h" #include #include "cds_utils.h" #include "host_diag_core_log.h" +#include "wma.h" +#include "ol_txrx_api.h" +#include "csr_api.h" +#include "wlan_hdd_main.h" +#include "pktlog_ac.h" + +#define MAX_NUM_PKT_LOG 32 + +/** + * struct tx_status - tx status + * @tx_status_ok: successfully sent + acked + * @tx_status_discard: discard - not sent (congestion control) + * @tx_status_no_ack: no_ack - sent, but no ack + * @tx_status_download_fail: download_fail - + * the host could not deliver the tx frame to the target + * @tx_status_peer_del: peer_del - tx completion for + * alreay deleted peer used for HL case + * + * This enum has tx status types + */ +enum tx_status { + tx_status_ok, + tx_status_discard, + tx_status_no_ack, + tx_status_download_fail, + tx_status_peer_del, +}; + +static uint8_t gtx_count; +static uint8_t grx_count; #define LOGGING_TRACE(level, args ...) \ QDF_TRACE(QDF_MODULE_ID_HDD, level, ## args) @@ -1194,12 +1223,7 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) } pkt_stats_dump = (struct packet_dump *)pkt_dump; - if (pkt_stats_dump) - total_stats_len = sizeof(struct ath_pktlog_hdr) + - pktlog_hdr->size + - sizeof(struct packet_dump); - else - total_stats_len = sizeof(struct ath_pktlog_hdr) + + total_stats_len = sizeof(struct ath_pktlog_hdr) + pktlog_hdr->size; spin_lock_irqsave(&gwlan_logging.pkt_stats_lock, flags); @@ -1224,16 +1248,24 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) pktlog_hdr, sizeof(struct ath_pktlog_hdr)); - if (pkt_stats_dump) + if (pkt_stats_dump) { qdf_mem_copy(skb_put(ptr, sizeof(struct packet_dump)), pkt_stats_dump, sizeof(struct packet_dump)); + pktlog_hdr->size -= sizeof(struct packet_dump); + } - qdf_mem_copy(skb_put(ptr, + if (data) + qdf_mem_copy(skb_put(ptr, pktlog_hdr->size), data, pktlog_hdr->size); + if (pkt_stats_dump->type == STOP_MONITOR) { + wake_up_thread = true; + wlan_get_pkt_stats_free_node(); + } + spin_unlock_irqrestore(&gwlan_logging.pkt_stats_lock, flags); /* Wakeup logger thread */ @@ -1243,4 +1275,240 @@ void wlan_pkt_stats_to_logger_thread(void *pl_hdr, void *pkt_dump, void *data) } } +/** + * driver_hal_status_map() - maps driver to hal + * status + * @status: status to be mapped + * + * This function is used to map driver to hal status + * + * Return: None + * + */ +static void driver_hal_status_map(uint8_t *status) +{ + switch (*status) { + case tx_status_ok: + *status = TX_PKT_FATE_ACKED; + break; + case tx_status_discard: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + case tx_status_no_ack: + *status = TX_PKT_FATE_SENT; + break; + case tx_status_download_fail: + *status = TX_PKT_FATE_FW_QUEUED; + break; + default: + *status = TX_PKT_FATE_DRV_DROP_OTHER; + break; + } +} + + +/* + * send_packetdump() - send packet dump + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: type of packet + * + * This function is used to send packet dump to HAL layer + * using wlan_pkt_stats_to_logger_thread + * + * Return: None + * + */ +static void send_packetdump(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + hdd_context_t *hdd_ctx; + hdd_adapter_t *adapter; + v_CONTEXT_t vos_ctx; + + vos_ctx = cds_get_global_context(); + if (!vos_ctx) + return; + + hdd_ctx = (hdd_context_t *)cds_get_context(QDF_MODULE_ID_HDD); + if (!hdd_ctx) + return; + + adapter = hdd_get_adapter_by_vdev(hdd_ctx, vdev_id); + if (!adapter) + return; + + /* Send packet dump only for STA interface */ + if (adapter->device_mode != QDF_STA_MODE) + return; + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr) + netbuf->len; + + pd_hdr.status = status; + pd_hdr.type = type; + pd_hdr.driver_ts = qdf_get_monotonic_boottime(); + + if ((type == TX_MGMT_PKT) || (type == TX_DATA_PKT)) + gtx_count++; + else if ((type == RX_MGMT_PKT) || (type == RX_DATA_PKT)) + grx_count++; + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, netbuf->data); +} + + +/* + * send_packetdump_monitor() - sends start/stop packet dump indication + * @type: type of packet + * + * This function is used to indicate HAL layer to start/stop monitoring + * of packets + * + * Return: None + * + */ +static void send_packetdump_monitor(uint8_t type) +{ + struct ath_pktlog_hdr pktlog_hdr = {0}; + struct packet_dump pd_hdr = {0}; + + pktlog_hdr.log_type = PKTLOG_TYPE_PKT_DUMP; + pktlog_hdr.size = sizeof(pd_hdr); + + pd_hdr.type = type; + + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "fate Tx-Rx %s: type: %d", __func__, type); + + wlan_pkt_stats_to_logger_thread(&pktlog_hdr, &pd_hdr, NULL); +} + +/** + * wlan_deregister_txrx_packetdump() - tx/rx packet dump + * deregistration + * + * This function is used to deregister tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_deregister_txrx_packetdump(void) +{ + if (gtx_count || grx_count) { + ol_deregister_packetdump_callback(); + wma_deregister_packetdump_callback(); + send_packetdump_monitor(STOP_MONITOR); + csr_packetdump_timer_stop(); + + gtx_count = 0; + grx_count = 0; + } else + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s: deregistered packetdump already", __func__); +} + +/* + * check_txrx_packetdump_count() - function to check + * tx/rx packet dump global counts + * + * This function is used to check global counts of tx/rx + * packet dump functionality. + * + * Return: 1 if either gtx_count or grx_count reached 32 + * 0 otherwise + * + */ +static bool check_txrx_packetdump_count(void) +{ + if (gtx_count == MAX_NUM_PKT_LOG || + grx_count == MAX_NUM_PKT_LOG) { + LOGGING_TRACE(QDF_TRACE_LEVEL_INFO, + "%s gtx_count: %d grx_count: %d deregister packetdump", + __func__, gtx_count, grx_count); + wlan_deregister_txrx_packetdump(); + return 1; + } + return 0; +} + +/* + * tx_packetdump_cb() - tx packet dump callback + * @netbuf: netbuf + * @status: status of tx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send tx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void tx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + driver_hal_status_map(&status); + send_packetdump(netbuf, status, vdev_id, type); +} + + +/* + * rx_packetdump_cb() - rx packet dump callback + * @netbuf: netbuf + * @status: status of rx packet + * @vdev_id: virtual device id + * @type: packet type + * + * This function is used to send rx packet dump to HAL layer + * and deregister packet dump callbacks + * + * Return: None + * + */ +static void rx_packetdump_cb(qdf_nbuf_t netbuf, uint8_t status, + uint8_t vdev_id, uint8_t type) +{ + bool temp; + + temp = check_txrx_packetdump_count(); + if (temp) + return; + + send_packetdump(netbuf, status, vdev_id, type); +} + + +/** + * wlan_register_txrx_packetdump() - tx/rx packet dump + * registration + * + * This function is used to register tx/rx packet dump callbacks + * with ol, pe and htt layers + * + * Return: None + * + */ +void wlan_register_txrx_packetdump(void) +{ + ol_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + wma_register_packetdump_callback(tx_packetdump_cb, + rx_packetdump_cb); + send_packetdump_monitor(START_MONITOR); + + gtx_count = 0; + grx_count = 0; +} + #endif /* WLAN_LOGGING_SOCK_SVC_ENABLE */ diff --git a/core/wma/inc/wma.h b/core/wma/inc/wma.h index 3284456201..463d4cc4a9 100644 --- a/core/wma/inc/wma.h +++ b/core/wma/inc/wma.h @@ -509,6 +509,9 @@ typedef void (*encrypt_decrypt_cb)(struct sir_encrypt_decrypt_rsp_params *encrypt_decrypt_rsp_params); +typedef void (*tp_wma_packetdump_cb)(qdf_nbuf_t netbuf, + uint8_t status, uint8_t vdev_id, uint8_t type); + /** * enum t_wma_drv_type - wma driver type * @WMA_DRIVER_TYPE_PRODUCTION: production driver type @@ -1188,6 +1191,7 @@ struct wmi_desc_t { pWMAAckFnTxComp ota_post_proc_cb; qdf_nbuf_t nbuf; uint32_t desc_id; + uint8_t vdev_id; }; /** @@ -1600,6 +1604,8 @@ typedef struct { cds_msg_t *msg); bool fw_timeout_crash; bool sub_20_support; + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb; + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb; tSirLLStatsResults *link_stats_results; } t_wma_handle, *tp_wma_handle; @@ -2322,6 +2328,10 @@ QDF_STATUS wma_start_oem_data_req(tp_wma_handle wma_handle, QDF_STATUS wma_enable_disable_caevent_ind(tp_wma_handle wma_handle, uint8_t val); +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb); +void wma_deregister_packetdump_callback(void); void wma_update_sta_inactivity_timeout(tp_wma_handle wma, struct sme_sta_inactivity_timeout *sta_inactivity_timer); void wma_peer_set_default_routing(void *scn_handle, uint8_t *peer_macaddr, diff --git a/core/wma/src/wma_data.c b/core/wma/src/wma_data.c index cdd44a34e8..e2ae1641e4 100644 --- a/core/wma/src/wma_data.c +++ b/core/wma/src/wma_data.c @@ -2835,6 +2835,7 @@ QDF_STATUS wma_tx_packet(void *wma_context, void *tx_frame, uint16_t frmLen, status = QDF_STATUS_E_FAILURE; } else { mgmt_param.desc_id = wmi_desc->desc_id; + wmi_desc->vdev_id = vdev_id; status = wmi_mgmt_unified_cmd_send( wma_handle->wmi_handle, &mgmt_param); diff --git a/core/wma/src/wma_mgmt.c b/core/wma/src/wma_mgmt.c index d3bf3c3042..317cb24ca5 100644 --- a/core/wma/src/wma_mgmt.c +++ b/core/wma/src/wma_mgmt.c @@ -2508,6 +2508,11 @@ static int wma_process_mgmt_tx_completion(tp_wma_handle wma_handle, if (wmi_desc->nbuf) qdf_nbuf_unmap_single(wma_handle->qdf_dev, wmi_desc->nbuf, QDF_DMA_TO_DEVICE); + + if (wma_handle->wma_mgmt_tx_packetdump_cb) + wma_handle->wma_mgmt_tx_packetdump_cb(wmi_desc->nbuf, + QDF_STATUS_SUCCESS, wmi_desc->vdev_id, TX_MGMT_PKT); + if (wmi_desc->tx_cmpl_cb) wmi_desc->tx_cmpl_cb(wma_handle->mac_context, wmi_desc->nbuf, 1); @@ -3323,6 +3328,13 @@ static int wma_mgmt_rx_process(void *handle, uint8_t *data, return -EINVAL; } + if ((mgt_type == IEEE80211_FC0_TYPE_MGT && + mgt_subtype != IEEE80211_FC0_SUBTYPE_BEACON) && + wma_handle->wma_mgmt_rx_packetdump_cb) + wma_handle->wma_mgmt_rx_packetdump_cb(rx_pkt->pkt_buf, + QDF_STATUS_SUCCESS, rx_pkt->pkt_meta.sessionId, + RX_MGMT_PKT); + wma_handle->mgmt_rx(wma_handle, rx_pkt); return 0; } @@ -3420,3 +3432,51 @@ QDF_STATUS wma_register_mgmt_frm_client( return QDF_STATUS_SUCCESS; } + +/** + * wma_register_packetdump_callback() - stores tx and rx mgmt packet dump + * callback handler + * @wma_mgmt_tx_packetdump_cb: tx mgmt packetdump cb + * @wma_mgmt_rx_packetdump_cb: rx mgmt packetdump cb + * + * This function is used to store tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_register_packetdump_callback( + tp_wma_packetdump_cb wma_mgmt_tx_packetdump_cb, + tp_wma_packetdump_cb wma_mgmt_rx_packetdump_cb) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = wma_mgmt_tx_packetdump_cb; + wma_handle->wma_mgmt_rx_packetdump_cb = wma_mgmt_rx_packetdump_cb; +} + +/** + * wma_deregister_packetdump_callback() - removes tx and rx mgmt packet dump + * callback handler + * + * This function is used to remove tx and rx mgmt. packet dump callback + * + * Return: None + * + */ +void wma_deregister_packetdump_callback(void) +{ + tp_wma_handle wma_handle = cds_get_context(QDF_MODULE_ID_WMA); + + if (!wma_handle) { + WMA_LOGE("wma handle is NULL"); + return; + } + + wma_handle->wma_mgmt_tx_packetdump_cb = NULL; + wma_handle->wma_mgmt_rx_packetdump_cb = NULL; +} diff --git a/uapi/linux/pktlog_ac_fmt.h b/uapi/linux/pktlog_ac_fmt.h index c8782fd03f..46dc10a8a5 100644 --- a/uapi/linux/pktlog_ac_fmt.h +++ b/uapi/linux/pktlog_ac_fmt.h @@ -70,6 +70,26 @@ struct ath_pktlog_hdr { #endif } __ATTRIB_PACK; +/** + * enum pkt_type - packet type + * @START_MONITOR: indicates parser to start packetdump parsing + * @STOP_MONITOR: indicates parser to stop packetdump parsing + * @TX_MGMT_PKT: TX management Packet + * @TX_DATA_PKT: TX data Packet + * @RX_MGMT_PKT: RX management Packet + * @RX_DATA_PKT: RX data Packet + * + * This enum has packet types + */ +enum pkt_type { + START_MONITOR = 1, + STOP_MONITOR, + TX_MGMT_PKT, + TX_DATA_PKT, + RX_MGMT_PKT, + RX_DATA_PKT, +}; + #define ATH_PKTLOG_HDR_FLAGS_MASK 0xffff #define ATH_PKTLOG_HDR_FLAGS_SHIFT 0 #define ATH_PKTLOG_HDR_FLAGS_OFFSET 0 @@ -127,17 +147,18 @@ enum { /* Types of packet log events */ -#define PKTLOG_TYPE_TX_CTRL 1 -#define PKTLOG_TYPE_TX_STAT 2 -#define PKTLOG_TYPE_TX_MSDU_ID 3 -#define PKTLOG_TYPE_TX_FRM_HDR 4 -#define PKTLOG_TYPE_RX_STAT 5 -#define PKTLOG_TYPE_RC_FIND 6 -#define PKTLOG_TYPE_RC_UPDATE 7 +#define PKTLOG_TYPE_TX_CTRL 1 +#define PKTLOG_TYPE_TX_STAT 2 +#define PKTLOG_TYPE_TX_MSDU_ID 3 +#define PKTLOG_TYPE_TX_FRM_HDR 4 +#define PKTLOG_TYPE_RX_STAT 5 +#define PKTLOG_TYPE_RC_FIND 6 +#define PKTLOG_TYPE_RC_UPDATE 7 #define PKTLOG_TYPE_TX_VIRT_ADDR 8 #define PKTLOG_TYPE_SMART_ANTENNA 9 #define PKTLOG_TYPE_SW_EVENT 10 -#define PKTLOG_TYPE_MAX 11 +#define PKTLOG_TYPE_PKT_DUMP 11 +#define PKTLOG_TYPE_MAX 12 #define PKTLOG_MAX_TXCTL_WORDS 57 /* +2 words for bitmap */ #define PKTLOG_MAX_TXSTATUS_WORDS 32 @@ -287,5 +308,82 @@ struct ath_pktlog_buf { sizeof(struct ath_pktlog_hdr)) ? _rd_offset : 0; \ } while(0) +/** + * enum tx_pkt_fate - tx packet fate + * @TX_PKT_FATE_ACKED: Sent over air and ACKed + * @TX_PKT_FATE_SENT: Sent over air but not ACKed. + * @TX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent over air + * @TX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware as invalid. + * E.g. bad source address, bad checksum, or invalid for current state. + * @TX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware due + * to lack of buffer space + * @TX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware for any other + * reason. Includes frames that were sent by driver to firmware, but + * unaccounted for by firmware. + * @TX_PKT_FATE_DRV_QUEUED: Queued within driver, not yet sent to firmware. + * @TX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. bad source address, or invalid for current state. + * @TX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver due to lack of buffer space + * @TX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * E.g. out of buffers. + * + * This enum has packet fate types + */ + +enum tx_pkt_fate { + TX_PKT_FATE_ACKED, + TX_PKT_FATE_SENT, + TX_PKT_FATE_FW_QUEUED, + TX_PKT_FATE_FW_DROP_INVALID, + TX_PKT_FATE_FW_DROP_NOBUFS, + TX_PKT_FATE_FW_DROP_OTHER, + TX_PKT_FATE_DRV_QUEUED, + TX_PKT_FATE_DRV_DROP_INVALID, + TX_PKT_FATE_DRV_DROP_NOBUFS, + TX_PKT_FATE_DRV_DROP_OTHER, +}; + +/** + * enum rx_pkt_fate - rx packet fate + * @RX_PKT_FATE_SUCCESS: Valid and delivered to + * network stack (e.g., netif_rx()). + * @RX_PKT_FATE_FW_QUEUED: Queued within firmware, + * but not yet sent to driver. + * @RX_PKT_FATE_FW_DROP_FILTER: Dropped by firmware + * due to host-programmable filters. + * @RX_PKT_FATE_FW_DROP_INVALID: Dropped by firmware + * as invalid. E.g. bad checksum, decrypt failed, or invalid for current state. + * @RX_PKT_FATE_FW_DROP_NOBUFS: Dropped by firmware + * due to lack of buffer space. + * @RX_PKT_FATE_FW_DROP_OTHER: Dropped by firmware + * for any other reason. + * @RX_PKT_FATE_DRV_QUEUED: Queued within driver, + * not yet delivered to network stack. + * @RX_PKT_FATE_DRV_DROP_FILTER: Dropped by driver + * due to filter rules. + * @RX_PKT_FATE_DRV_DROP_INVALID: Dropped by driver as invalid. + * E.g. not permitted in current state. + * @RX_PKT_FATE_DRV_DROP_NOBUFS: Dropped by driver + * due to lack of buffer space. + * @RX_PKT_FATE_DRV_DROP_OTHER: Dropped by driver for any other reason. + * + * This enum has packet fate types + */ + +enum rx_pkt_fate { + RX_PKT_FATE_SUCCESS, + RX_PKT_FATE_FW_QUEUED, + RX_PKT_FATE_FW_DROP_FILTER, + RX_PKT_FATE_FW_DROP_INVALID, + RX_PKT_FATE_FW_DROP_NOBUFS, + RX_PKT_FATE_FW_DROP_OTHER, + RX_PKT_FATE_DRV_QUEUED, + RX_PKT_FATE_DRV_DROP_FILTER, + RX_PKT_FATE_DRV_DROP_INVALID, + RX_PKT_FATE_DRV_DROP_NOBUFS, + RX_PKT_FATE_DRV_DROP_OTHER, +}; + #endif /* _PKTLOG_FMT_H_ */ #endif /* REMOVE_PKT_LOG */