diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c index b9ce5a1e9b68..56ef97569e46 100644 --- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c +++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_api.c @@ -163,6 +163,24 @@ QDF_STATUS direct_buf_rx_target_attach(struct wlan_objmgr_psoc *psoc, return QDF_STATUS_SUCCESS; } +#ifdef DIRECT_BUF_RX_DEBUG +static inline void +target_if_direct_buf_rx_debug_register_tx_ops( + struct wlan_lmac_if_tx_ops *tx_ops) +{ + tx_ops->dbr_tx_ops.direct_buf_rx_start_ring_debug = + target_if_dbr_start_ring_debug; + tx_ops->dbr_tx_ops.direct_buf_rx_stop_ring_debug = + target_if_dbr_stop_ring_debug; +} +#else +static inline void +target_if_direct_buf_rx_debug_register_tx_ops( + struct wlan_lmac_if_tx_ops *tx_ops) +{ +} +#endif /* DIRECT_BUF_RX_DEBUG */ + void target_if_direct_buf_rx_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) { tx_ops->dbr_tx_ops.direct_buf_rx_module_register = @@ -177,5 +195,6 @@ void target_if_direct_buf_rx_register_tx_ops(struct wlan_lmac_if_tx_ops *tx_ops) target_if_direct_buf_rx_print_ring_stat; tx_ops->dbr_tx_ops.direct_buf_rx_get_ring_params = target_if_direct_buf_rx_get_ring_params; + target_if_direct_buf_rx_debug_register_tx_ops(tx_ops); } qdf_export_symbol(target_if_direct_buf_rx_register_tx_ops); diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c index b97807e5fb47..091aa3daa1dc 100644 --- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c +++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.c @@ -119,6 +119,69 @@ static QDF_STATUS populate_dbr_cap_mod_param(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_SUCCESS; } +#ifdef DIRECT_BUF_RX_DEBUG +static inline struct direct_buf_rx_module_debug *target_if_get_dbr_mod_debug( + struct wlan_objmgr_pdev *pdev, + uint8_t mod_id) +{ + struct direct_buf_rx_pdev_obj *dbr_pdev_obj; + + if (!pdev) { + direct_buf_rx_err("pdev is null"); + return NULL; + } + + if (mod_id >= DBR_MODULE_MAX) { + direct_buf_rx_err("Invalid module id"); + return NULL; + } + + dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); + return NULL; + } + + if (!dbr_pdev_obj->dbr_mod_debug) { + direct_buf_rx_err("dbr_pdev_obj->dbr_mod_debug is NULL"); + return NULL; + } + + if (mod_id >= dbr_pdev_obj->num_modules) { + direct_buf_rx_err("Module %d not supported in target", mod_id); + return NULL; + } + return &dbr_pdev_obj->dbr_mod_debug[mod_id]; +} +#endif + +#ifdef DIRECT_BUF_RX_DEBUG +static inline QDF_STATUS target_if_direct_buf_rx_alloc_mod_debug( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); + return QDF_STATUS_E_FAILURE; + } + /* Allocate the debug data structure for each module */ + dbr_pdev_obj->dbr_mod_debug = qdf_mem_malloc( + dbr_pdev_obj->num_modules * + sizeof(struct direct_buf_rx_module_debug)); + + if (!dbr_pdev_obj->dbr_mod_debug) + return QDF_STATUS_E_NOMEM; + + return QDF_STATUS_SUCCESS; +} +#else +static inline QDF_STATUS target_if_direct_buf_rx_alloc_mod_debug( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* DIRECT_BUF_RX_DEBUG */ QDF_STATUS target_if_direct_buf_rx_pdev_create_handler( struct wlan_objmgr_pdev *pdev, void *data) @@ -176,17 +239,49 @@ QDF_STATUS target_if_direct_buf_rx_pdev_create_handler( sizeof(struct direct_buf_rx_module_param)); if (!dbr_pdev_obj->dbr_mod_param) { - direct_buf_rx_err("alloc dbr mod param fail"); - wlan_objmgr_pdev_component_obj_detach(pdev, - WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, - dbr_pdev_obj); - qdf_mem_free(dbr_pdev_obj); - return QDF_STATUS_E_NOMEM; + direct_buf_rx_err("alloc dbr mod param fail"); + goto dbr_mod_param_fail; } + if (target_if_direct_buf_rx_alloc_mod_debug(dbr_pdev_obj) != + QDF_STATUS_SUCCESS) + goto dbr_mod_debug_fail; + return QDF_STATUS_SUCCESS; + +dbr_mod_debug_fail: + qdf_mem_free(dbr_pdev_obj->dbr_mod_param); + +dbr_mod_param_fail: + wlan_objmgr_pdev_component_obj_detach( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, + dbr_pdev_obj); + qdf_mem_free(dbr_pdev_obj); + + return QDF_STATUS_E_NOMEM; } +#ifdef DIRECT_BUF_RX_DEBUG +static inline void target_if_direct_buf_rx_free_mod_debug( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); + return; + } + /* Free the debug data structures of all modules */ + if (dbr_pdev_obj->dbr_mod_debug) { + qdf_mem_free(dbr_pdev_obj->dbr_mod_debug); + dbr_pdev_obj->dbr_mod_debug = NULL; + } +} +#else +static inline void target_if_direct_buf_rx_free_mod_debug( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ +} +#endif /* DIRECT_BUF_RX_DEBUG */ + QDF_STATUS target_if_direct_buf_rx_pdev_destroy_handler( struct wlan_objmgr_pdev *pdev, void *data) { @@ -209,11 +304,18 @@ QDF_STATUS target_if_direct_buf_rx_pdev_destroy_handler( num_modules = dbr_pdev_obj->num_modules; for (mod_idx = 0; mod_idx < num_modules; mod_idx++) { + /* + * If the module didn't stop the ring debug by this time, + * it will result in memory leak of its ring debug entries. + * So, stop the ring debug + */ + target_if_dbr_stop_ring_debug(pdev, mod_idx); for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) target_if_deinit_dbr_ring(pdev, dbr_pdev_obj, mod_idx, srng_id); } + target_if_direct_buf_rx_free_mod_debug(dbr_pdev_obj); qdf_mem_free(dbr_pdev_obj->dbr_mod_param); dbr_pdev_obj->dbr_mod_param = NULL; @@ -299,6 +401,92 @@ QDF_STATUS target_if_direct_buf_rx_psoc_destroy_handler( return status; } +#ifdef DIRECT_BUF_RX_DEBUG +QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id) +{ + struct direct_buf_rx_module_debug *mod_debug; + struct direct_buf_rx_ring_debug *ring_debug; + uint8_t srng_id; + + mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + if (!mod_debug) + return QDF_STATUS_E_INVAL; + + for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) { + ring_debug = &mod_debug->dbr_ring_debug[srng_id]; + + qdf_mem_free(ring_debug->entries); + ring_debug->entries = NULL; + ring_debug->ring_debug_idx = 0; + ring_debug->num_ring_debug_entries = 0; + direct_buf_rx_info("DBR ring debug for module %d srng %d is now stopped", + mod_id, srng_id); + } + + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_dbr_start_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id, + uint32_t num_ring_debug_entries) +{ + struct direct_buf_rx_module_debug *mod_debug; + struct direct_buf_rx_ring_debug *ring_debug; + uint8_t srng_id; + + mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + + if (!mod_debug) + return QDF_STATUS_E_INVAL; + + if (num_ring_debug_entries > DIRECT_BUF_RX_MAX_RING_DEBUG_ENTRIES) { + direct_buf_rx_err("Requested number of ring debug entries(%d) exceed the maximum entries allowed(%d)", + num_ring_debug_entries, + DIRECT_BUF_RX_MAX_RING_DEBUG_ENTRIES); + + return QDF_STATUS_E_FAILURE; + } + + for (srng_id = 0; srng_id < DBR_SRNG_NUM; srng_id++) { + ring_debug = &mod_debug->dbr_ring_debug[srng_id]; + + if (ring_debug->entries) { + direct_buf_rx_err("DBR ring debug for module %d srng %d was already enabled", + mod_id, mod_debug); + return QDF_STATUS_E_FAILURE; + } + + ring_debug->entries = qdf_mem_malloc( + num_ring_debug_entries * + sizeof(*ring_debug->entries)); + + if (!ring_debug->entries) + return QDF_STATUS_E_NOMEM; + + ring_debug->ring_debug_idx = 0; + ring_debug->num_ring_debug_entries = num_ring_debug_entries; + + direct_buf_rx_info("DBR ring debug for module %d srng %d is now started", + mod_id, srng_id); + } + return QDF_STATUS_SUCCESS; +} +#else +QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id) +{ + return QDF_STATUS_SUCCESS; +} + +QDF_STATUS target_if_dbr_start_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id, + uint32_t num_ring_debug_entries) +{ + return QDF_STATUS_SUCCESS; +} +#endif /* DIRECT_BUF_RX_DEBUG */ + static QDF_STATUS target_if_dbr_replenish_ring(struct wlan_objmgr_pdev *pdev, struct direct_buf_rx_module_param *mod_param, void *aligned_vaddr, uint32_t cookie) @@ -965,6 +1153,89 @@ dbr_get_pdev_and_srng_id(struct wlan_objmgr_psoc *psoc, uint8_t pdev_id, } #endif +#ifdef DIRECT_BUF_RX_DEBUG +/** + * target_if_dbr_add_ring_debug_entry() - Add a DBR ring debug entry + * @pdev: pointer to pdev object + * @mod_id: Module ID + * @event: ring debug event + * + * Log the given event, head and tail pointers of DBR ring of the given module + * into its ring debug data structure. + * Also, log the timestamp at the time of logging. + */ +static void target_if_dbr_add_ring_debug_entry( + struct wlan_objmgr_pdev *pdev, + uint32_t mod_id, + enum DBR_RING_DEBUG_EVENT event, + uint8_t srng_id) +{ + struct wlan_objmgr_psoc *psoc; + void *hal_soc, *srng; + uint32_t hp = 0, tp = 0; + struct direct_buf_rx_psoc_obj *dbr_psoc_obj; + struct direct_buf_rx_pdev_obj *dbr_pdev_obj; + struct direct_buf_rx_ring_cfg *dbr_ring_cfg; + struct direct_buf_rx_module_debug *mod_debug; + struct direct_buf_rx_module_param *mod_param; + struct direct_buf_rx_ring_debug *ring_debug; + struct direct_buf_rx_ring_debug_entry *entry; + + mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + + if (!mod_debug) + return; + + psoc = wlan_pdev_get_psoc(pdev); + + dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + dbr_psoc_obj = wlan_objmgr_psoc_get_comp_private_obj( + psoc, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + mod_param = &dbr_pdev_obj->dbr_mod_param[mod_id][srng_id]; + if (!mod_param) { + direct_buf_rx_err("dir buf rx module param is null"); + return; + } + + hal_soc = dbr_psoc_obj->hal_soc; + dbr_ring_cfg = mod_param->dbr_ring_cfg; + srng = dbr_ring_cfg->srng; + ring_debug = &mod_debug->dbr_ring_debug[srng_id]; + + if (ring_debug->entries) { + if (hal_srng_access_start(hal_soc, srng)) { + direct_buf_rx_err("module %d - HAL srng access failed", + mod_id); + return; + } + hal_get_sw_hptp(hal_soc, srng, &tp, &hp); + hal_srng_access_end(hal_soc, srng); + entry = &ring_debug->entries[ring_debug->ring_debug_idx]; + + entry->head_idx = hp; + entry->tail_idx = tp; + entry->timestamp = qdf_get_log_timestamp(); + entry->event = event; + + ring_debug->ring_debug_idx++; + if (ring_debug->ring_debug_idx == + ring_debug->num_ring_debug_entries) + ring_debug->ring_debug_idx = 0; + } +} +#else +static void target_if_dbr_add_ring_debug_entry( + struct wlan_objmgr_pdev *pdev, + uint32_t mod_id, + enum DBR_RING_DEBUG_EVENT event, + uint8_t srng_id) +{ +} +#endif /* DIRECT_BUF_RX_DEBUG */ + static int target_if_direct_buf_rx_rsp_event_handler(ol_scn_t scn, uint8_t *data_buf, uint32_t data_len) @@ -1074,10 +1345,20 @@ static int target_if_direct_buf_rx_rsp_event_handler(ol_scn_t scn, &dbr_data.meta_data) == QDF_STATUS_SUCCESS) dbr_data.meta_data_valid = true; } + + target_if_dbr_add_ring_debug_entry(pdev, dbr_rsp.mod_id, + DBR_RING_DEBUG_EVENT_RX, + srng_id); if (mod_param->dbr_rsp_handler(pdev, &dbr_data)) { status = target_if_dbr_replenish_ring(pdev, mod_param, dbr_data.vaddr, cookie); + + target_if_dbr_add_ring_debug_entry( + pdev, dbr_rsp.mod_id, + DBR_RING_DEBUG_EVENT_REPLENISH_RING, + srng_id); + if (QDF_IS_STATUS_ERROR(status)) { direct_buf_rx_err("Ring replenish failed"); qdf_mem_free(dbr_rsp.dbr_entries); diff --git a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h index 5e8e56637a38..45aebb4e6b30 100644 --- a/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h +++ b/target_if/direct_buf_rx/src/target_if_direct_buf_rx_main.h @@ -88,6 +88,56 @@ struct direct_buf_rx_ring_cap { uint32_t min_buf_align; }; +/** + * enum DBR_RING_DEBUG_EVENT - DMA ring debug event + * @DBR_RING_DEBUG_EVENT_NONE: Not a real value, just a place holder for + * no entry + * @DBR_RING_DEBUG_EVENT_RX: DBR Rx event + * @DBR_RING_DEBUG_EVENT_REPLENISH_RING: DBR replenish event + * @DBR_RING_DEBUG_EVENT_MAX: Not a real value, just a place holder for max + */ +enum DBR_RING_DEBUG_EVENT { + DBR_RING_DEBUG_EVENT_NONE = 0, + DBR_RING_DEBUG_EVENT_RX, + DBR_RING_DEBUG_EVENT_REPLENISH_RING, + DBR_RING_DEBUG_EVENT_MAX, +}; + +#define DIRECT_BUF_RX_MAX_RING_DEBUG_ENTRIES (1024) +/** + * struct direct_buf_rx_ring_debug_entry - DBR ring debug entry + * @head_idx: Head index of the DMA ring + * @tail_idx: Tail index of the DMA ring + * @timestamp: Timestamp at the time of logging + * @event: Name of the event + */ +struct direct_buf_rx_ring_debug_entry { + uint32_t head_idx; + uint32_t tail_idx; + uint64_t timestamp; + enum DBR_RING_DEBUG_EVENT event; +}; + +/** + * struct direct_buf_rx_ring_debug - DMA ring debug of a module + * @entries: Pointer to the array of ring debug entries + * @ring_debug_idx: Current index in the array of ring debug entries + * @num_ring_debug_entries: Total ring debug entries + */ +struct direct_buf_rx_ring_debug { + struct direct_buf_rx_ring_debug_entry *entries; + uint32_t ring_debug_idx; + uint32_t num_ring_debug_entries; +}; + +/** + * struct direct_buf_rx_module_debug - Debug of a module subscribed to DBR + * @dbr_ring_debug: Array of ring debug structers corresponding to each srng + */ +struct direct_buf_rx_module_debug { + struct direct_buf_rx_ring_debug dbr_ring_debug[DBR_SRNG_NUM]; +}; + /** * struct direct_buf_rx_module_param - DMA module param * @mod_id: Module ID @@ -113,10 +163,14 @@ struct direct_buf_rx_module_param { * struct direct_buf_rx_pdev_obj - Direct Buf RX pdev object struct * @num_modules: Number of modules registered to DBR for the pdev * @dbr_mod_param: Pointer to direct buf rx module param struct + * @dbr_mod_debug: Pointer to the array of DBR module debug structures */ struct direct_buf_rx_pdev_obj { uint32_t num_modules; struct direct_buf_rx_module_param (*dbr_mod_param)[DBR_SRNG_NUM]; +#ifdef DIRECT_BUF_RX_DEBUG + struct direct_buf_rx_module_debug *dbr_mod_debug; +#endif }; /** @@ -271,4 +325,21 @@ target_if_direct_buf_rx_get_ring_params(struct wlan_objmgr_pdev *pdev, struct module_ring_params *param, uint8_t mod_id, uint8_t srng_id); +/** + * target_if_dbr_start_ring_debug() - Start DBR ring debug + * @pdev: pointer to pdev object + * @mod_id: module ID indicating the module using direct buffer rx framework + * @num_ring_debug_entries: Size of the ring debug entries + */ +QDF_STATUS target_if_dbr_start_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id, + uint32_t num_ring_debug_entries); + +/** + * target_if_dbr_stop_ring_debug() - Stop DBR ring debug + * @pdev: pointer to pdev object + * @mod_id: module ID indicating the module using direct buffer rx framework + */ +QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, + uint8_t mod_id); #endif /* _TARGET_IF_DIRECT_BUF_RX_MAIN_H_ */ diff --git a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h index 815356d42a4c..a62ab9fb7672 100644 --- a/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h +++ b/umac/global_umac_dispatcher/lmac_if/inc/wlan_lmac_if_def.h @@ -597,6 +597,8 @@ struct wlan_lmac_if_wifi_pos_tx_ops { * @direct_buf_rx_print_ring_stat: Print ring status per module per pdev * * @direct_buf_rx_get_ring_params: Get ring parameters for module_id + * @direct_buf_rx_start_ring_debug: Start DBR ring debug + * @direct_buf_rx_stop_ring_debug: Stop DBR ring debug */ struct wlan_lmac_if_direct_buf_rx_tx_ops { QDF_STATUS (*direct_buf_rx_module_register)( @@ -617,6 +619,11 @@ struct wlan_lmac_if_direct_buf_rx_tx_ops { (struct wlan_objmgr_pdev *pdev, struct module_ring_params *param, uint8_t module_id, uint8_t srng_id); + QDF_STATUS (*direct_buf_rx_start_ring_debug)( + struct wlan_objmgr_pdev *pdev, uint8_t mod_id, + uint32_t num_ring_debug_entries); + QDF_STATUS (*direct_buf_rx_stop_ring_debug)( + struct wlan_objmgr_pdev *pdev, uint8_t mod_id); }; #endif