From 29121213c8b94460364de94e04970a960999e0fd Mon Sep 17 00:00:00 2001 From: Shwetha G K Date: Fri, 25 Oct 2019 14:18:27 +0530 Subject: [PATCH] qcacmn: Add debugfs support for DBR ring debug For each DBR ring, add debugfs entry to dump at real-time the ring parameters like head, tail index, the timestamps at which a buffer is received and replenished. Issues that are specific to tail index movement from the target can be identified with this debugfs entry. CRs-Fixed: 2466514 Change-Id: Iafbc61726264464212cb783a1cce46e16b8a48ff --- qdf/inc/qdf_debugfs.h | 52 +- qdf/linux/src/qdf_debugfs.c | 67 +++ .../inc/target_if_direct_buf_rx_api.h | 7 + .../src/target_if_direct_buf_rx_api.c | 37 ++ .../src/target_if_direct_buf_rx_main.c | 484 ++++++++++++++++-- .../src/target_if_direct_buf_rx_main.h | 29 ++ 6 files changed, 627 insertions(+), 49 deletions(-) diff --git a/qdf/inc/qdf_debugfs.h b/qdf/inc/qdf_debugfs.h index 62200b30fdae..46dc3a945a5a 100644 --- a/qdf/inc/qdf_debugfs.h +++ b/qdf/inc/qdf_debugfs.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2017-2018 The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019 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 @@ -240,6 +240,43 @@ void qdf_debugfs_remove_dir(qdf_dentry_t d); */ void qdf_debugfs_remove_file(qdf_dentry_t d); +/** + * qdf_debugfs_create_file_simplified() - Create a simple debugfs file + * where a single function call produces all the desired output + * @name: name of the file + * @mode: qdf file mode + * @parent: parent node. If NULL, defaults to base 'qdf_debugfs_root' + * @fops: file operations { .show, .write , .priv... } + * + * Users just have to define the show() function and pass it via @fops.show() + * argument. When the output time comes, the show() will be called once. + * The show() function must do everything that is needed to write the data, + * all in one function call. + * This is useful either for writing small amounts of data to debugfs or + * for cases in which the output is not iterative. + * The private data can be passed via @fops.priv, which will be available + * inside the show() function as the 'private' filed of the qdf_debugfs_file_t. + * + * Return: dentry structure pointer in case of success, otherwise NULL. + * + */ + +qdf_dentry_t qdf_debugfs_create_file_simplified(const char *name, uint16_t mode, + qdf_dentry_t parent, + struct qdf_debugfs_fops *fops); + +/** + * qdf_debugfs_printer() - Print formated string into debugfs file + * @priv: The private data + * @fmt: Format string + * @...: arguments for the format string + * + * This function prints a new line character after printing the formatted + * string into the debugfs file. + * This function can be passed when the argument is of type qdf_abstract_print + */ +int qdf_debugfs_printer(void *priv, const char *fmt, ...); + #else /* WLAN_DEBUGFS */ static inline QDF_STATUS qdf_debugfs_init(void) @@ -333,5 +370,18 @@ static inline void qdf_debugfs_remove_dir_recursive(qdf_dentry_t d) {} static inline void qdf_debugfs_remove_dir(qdf_dentry_t d) {} static inline void qdf_debugfs_remove_file(qdf_dentry_t d) {} +static inline +qdf_dentry_t qdf_debugfs_create_file_simplified(const char *name, uint16_t mode, + qdf_dentry_t parent, + struct qdf_debugfs_fops *fops) +{ + return NULL; +} + +static inline +int qdf_debugfs_printer(void *priv, const char *fmt, ...) +{ + return 0; +} #endif /* WLAN_DEBUGFS */ #endif /* _QDF_DEBUGFS_H */ diff --git a/qdf/linux/src/qdf_debugfs.c b/qdf/linux/src/qdf_debugfs.c index f16908b26458..da98bb0bbe88 100644 --- a/qdf/linux/src/qdf_debugfs.c +++ b/qdf/linux/src/qdf_debugfs.c @@ -468,3 +468,70 @@ void qdf_debugfs_remove_file(qdf_dentry_t d) debugfs_remove(d); } qdf_export_symbol(qdf_debugfs_remove_file); + +static int qdf_debugfs_single_show(struct seq_file *seq, void *v) +{ + struct qdf_debugfs_fops *fops = seq->private; + + if (fops && fops->show) + fops->show(seq, fops->priv); + + return 0; +} + +/* .open() */ +static int qdf_debugfs_single_open(struct inode *inode, struct file *file) +{ + return single_open(file, qdf_debugfs_single_show, + inode->i_private); +} + +/* File operations for the simplified version */ +static const struct file_operations qdf_debugfs_fops_simple = { + .owner = THIS_MODULE, + .open = qdf_debugfs_single_open, + .release = single_release, + .read = seq_read, + .llseek = seq_lseek, +}; + +qdf_dentry_t qdf_debugfs_create_file_simplified( + const char *name, uint16_t mode, + qdf_dentry_t parent, struct qdf_debugfs_fops *fops) +{ + qdf_dentry_t file; + umode_t filemode; + + if (!name || !fops) + return NULL; + + if (!parent) + parent = qdf_debugfs_get_root(); + + filemode = qdf_debugfs_get_filemode(mode); + file = debugfs_create_file(name, filemode, parent, fops, + &qdf_debugfs_fops_simple); + + if (IS_ERR_OR_NULL(file)) { + QDF_TRACE(QDF_MODULE_ID_QDF, QDF_TRACE_LEVEL_ERROR, + "%s creation failed 0x%pK", name, file); + file = NULL; + } + + return file; +} +qdf_export_symbol(qdf_debugfs_create_file_simplified); + +int qdf_debugfs_printer(void *priv, const char *fmt, ...) +{ + struct seq_file *file = priv; + va_list args; + + va_start(args, fmt); + seq_vprintf(file, fmt, args); + seq_puts(file, "\n"); + va_end(args); + + return 0; +} +qdf_export_symbol(qdf_debugfs_printer); diff --git a/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h b/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h index 6df48d23d5e4..10882f2f2c2c 100644 --- a/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h +++ b/target_if/direct_buf_rx/inc/target_if_direct_buf_rx_api.h @@ -23,6 +23,13 @@ #include "qdf_atomic.h" #include "wmi_unified_api.h" +#ifdef WLAN_DEBUGFS +#ifdef DIRECT_BUF_RX_DEBUG +/* Base debugfs entry for DBR module */ +extern qdf_dentry_t dbr_debugfs_entry; +#endif /* DIRECT_BUF_RX_DEBUG */ +#endif /* WLAN_DEBUGFS */ + #define direct_buf_rx_alert(params...) \ QDF_TRACE_FATAL(QDF_MODULE_ID_DIRECT_BUF_RX, params) #define direct_buf_rx_err(params...) \ 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 4bae3b872b79..082316bae16e 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 @@ -25,6 +25,39 @@ #include "target_if_direct_buf_rx_main.h" #include +#if defined(WLAN_DEBUGFS) && defined(DIRECT_BUF_RX_DEBUG) +/* Base debugfs entry for DBR module */ +qdf_dentry_t dbr_debugfs_entry; + +static inline void +target_if_direct_buf_rx_debugfs_init(void) +{ + dbr_debugfs_entry = qdf_debugfs_create_dir("dbr_ring_debug", NULL); + + if (!dbr_debugfs_entry) + direct_buf_rx_err("error while creating direct_buf rx debugfs dir"); +} + +static inline void +target_if_direct_buf_rx_debugfs_deinit(void) +{ + if (dbr_debugfs_entry) { + qdf_debugfs_remove_dir_recursive(dbr_debugfs_entry); + dbr_debugfs_entry = NULL; + } +} +#else +static inline void +target_if_direct_buf_rx_debugfs_init(void) +{ +} + +static inline void +target_if_direct_buf_rx_debugfs_deinit(void) +{ +} +#endif /* WLAN_DEBUGFS && DIRECT_BUF_RX_DEBUG */ + QDF_STATUS direct_buf_rx_init(void) { QDF_STATUS status; @@ -69,6 +102,8 @@ QDF_STATUS direct_buf_rx_init(void) goto dbr_unreg_pdev_create; } + target_if_direct_buf_rx_debugfs_init(); + direct_buf_rx_info("Direct Buffer RX pdev,psoc create and destroy handlers registered"); return QDF_STATUS_SUCCESS; @@ -99,6 +134,8 @@ QDF_STATUS direct_buf_rx_deinit(void) { QDF_STATUS status; + target_if_direct_buf_rx_debugfs_deinit(); + status = wlan_objmgr_unregister_pdev_destroy_handler( WLAN_TARGET_IF_COMP_DIRECT_BUF_RX, target_if_direct_buf_rx_pdev_destroy_handler, 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 957fd7e627c5..47f9e0f61daf 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 @@ -120,14 +120,13 @@ 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, +static inline struct direct_buf_rx_module_debug * +target_if_get_dbr_mod_debug_from_dbr_pdev_obj( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj, uint8_t mod_id) { - struct direct_buf_rx_pdev_obj *dbr_pdev_obj; - - if (!pdev) { - direct_buf_rx_err("pdev is null"); + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); return NULL; } @@ -136,14 +135,6 @@ static inline struct direct_buf_rx_module_debug *target_if_get_dbr_mod_debug( 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; @@ -155,9 +146,121 @@ static inline struct direct_buf_rx_module_debug *target_if_get_dbr_mod_debug( } return &dbr_pdev_obj->dbr_mod_debug[mod_id]; } + +static inline struct direct_buf_rx_module_debug * +target_if_get_dbr_mod_debug_from_pdev( + 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; + } + + dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + return target_if_get_dbr_mod_debug_from_dbr_pdev_obj( + dbr_pdev_obj, mod_id); +} #endif #ifdef DIRECT_BUF_RX_DEBUG +#define RING_DEBUG_EVENT_NAME_SIZE 12 +static const unsigned char +g_dbr_ring_debug_event[DBR_RING_DEBUG_EVENT_MAX][RING_DEBUG_EVENT_NAME_SIZE] = { + [DBR_RING_DEBUG_EVENT_RX] = "Rx", + [DBR_RING_DEBUG_EVENT_REPLENISH_RING] = "Replenish", +}; + +/** + * target_if_dbr_print_ring_debug_entries() - Print ring debug entries + * @print: The print adapter function + * @print_priv: The private data to be consumed by @print + * @dbr_pdev_obj: Pdev object of the DBR module + * @mod_id: Module ID + * + * Print ring debug entries of the ring identified by @dbr_pdev_obj and @mod_id + * using the given print adapter function + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS target_if_dbr_print_ring_debug_entries( + qdf_abstract_print print, void *print_priv, + struct direct_buf_rx_pdev_obj *dbr_pdev_obj, + uint8_t mod_id, uint8_t srng_id) +{ + struct direct_buf_rx_module_debug *mod_debug; + struct direct_buf_rx_ring_debug *ring_debug; + int idx; + + mod_debug = target_if_get_dbr_mod_debug_from_dbr_pdev_obj(dbr_pdev_obj, + mod_id); + if (!mod_debug) + return QDF_STATUS_E_INVAL; + + mod_debug = &dbr_pdev_obj->dbr_mod_debug[mod_id]; + ring_debug = &mod_debug->dbr_ring_debug[srng_id]; + + if (ring_debug->entries) { + print(print_priv, "Current debug entry is %d", + ring_debug->ring_debug_idx); + print(print_priv, "---------------------------------------------------------"); + print(print_priv, "| Number | Head Idx | Tail Idx | Timestamp | event |"); + print(print_priv, "---------------------------------------------------------"); + for (idx = 0; idx < ring_debug->num_ring_debug_entries; ++idx) { + print(print_priv, "|%8u|%10u|%10u|%11llu|%12s|", idx, + ring_debug->entries[idx].head_idx, + ring_debug->entries[idx].tail_idx, + ring_debug->entries[idx].timestamp, + g_dbr_ring_debug_event[ + ring_debug->entries[idx].event]); + } + print(print_priv, "---------------------------------------------------------"); + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dbr_qdf_err_printer() - QDF error level printer for DBR module + * @print_priv: The private data + * @fmt: Format string + * + * This function should be passed in place of the 'print' argument to + * target_if_dbr_print_ring_debug_entries function for the logs that should be + * printed via QDF trace + * + * Return: QDF_STATUS of operation + */ +static int target_if_dbr_qdf_err_printer(void *priv, const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + QDF_VTRACE(QDF_MODULE_ID_DIRECT_BUF_RX, QDF_TRACE_LEVEL_ERROR, + (char *)fmt, args); + va_end(args); + + return 0; +} + +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; + } +} + static inline QDF_STATUS target_if_direct_buf_rx_alloc_mod_debug( struct direct_buf_rx_pdev_obj *dbr_pdev_obj) { @@ -181,7 +284,71 @@ static inline QDF_STATUS target_if_direct_buf_rx_alloc_mod_debug( { return QDF_STATUS_SUCCESS; } -#endif /* DIRECT_BUF_RX_DEBUG */ + +static inline void target_if_direct_buf_rx_free_mod_debug( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ +} +#endif + +#if defined(WLAN_DEBUGFS) && defined(DIRECT_BUF_RX_DEBUG) +static inline void target_if_direct_buf_pdev_debugfs_init( + struct wlan_objmgr_pdev *pdev) +{ + char dir_name[32]; + struct wlan_objmgr_psoc *psoc; + struct direct_buf_rx_pdev_obj *dbr_pdev_obj; + + if (!pdev) { + direct_buf_rx_err("pdev is null"); + 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); + + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); + return; + } + + qdf_snprintf(dir_name, sizeof(dir_name), "SOC%u_PDEV%u", + wlan_psoc_get_id(psoc), + wlan_objmgr_pdev_get_pdev_id(pdev)); + + /* Create debugfs entry for this radio */ + dbr_pdev_obj->debugfs_entry = qdf_debugfs_create_dir( + dir_name, dbr_debugfs_entry); + + if (!dbr_pdev_obj->debugfs_entry) + direct_buf_rx_err("error while creating direct_buf debugfs dir"); +} + +static inline void target_if_direct_buf_pdev_debugfs_deinit( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ + if (!dbr_pdev_obj) { + direct_buf_rx_err("dir buf rx object is null"); + return; + } + /* Remove the debugfs entry of the radio */ + if (dbr_pdev_obj->debugfs_entry) { + qdf_debugfs_remove_dir_recursive(dbr_pdev_obj->debugfs_entry); + dbr_pdev_obj->debugfs_entry = NULL; + } +} +#else +static inline void target_if_direct_buf_pdev_debugfs_init( + struct wlan_objmgr_pdev *pdev) +{ +} + +static inline void target_if_direct_buf_pdev_debugfs_deinit( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj) +{ +} +#endif /* WLAN_DEBUGFS && DIRECT_BUF_RX_DEBUG */ QDF_STATUS target_if_direct_buf_rx_pdev_create_handler( struct wlan_objmgr_pdev *pdev, void *data) @@ -247,6 +414,8 @@ QDF_STATUS target_if_direct_buf_rx_pdev_create_handler( QDF_STATUS_SUCCESS) goto dbr_mod_debug_fail; + target_if_direct_buf_pdev_debugfs_init(pdev); + return QDF_STATUS_SUCCESS; dbr_mod_debug_fail: @@ -261,27 +430,6 @@ dbr_mod_param_fail: 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) { @@ -315,6 +463,7 @@ QDF_STATUS target_if_direct_buf_rx_pdev_destroy_handler( mod_idx, srng_id); } + target_if_direct_buf_pdev_debugfs_deinit(dbr_pdev_obj); 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; @@ -401,6 +550,203 @@ QDF_STATUS target_if_direct_buf_rx_psoc_destroy_handler( return status; } +#if defined(WLAN_DEBUGFS) && defined(DIRECT_BUF_RX_DEBUG) +/** + * target_if_dbr_debugfs_show_ring_debug() - Function to display ring debug + * entries in debugfs + * @file: qdf debugfs file handler + * @arg: pointer to DBR debugfs private object + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS target_if_dbr_debugfs_show_ring_debug( + qdf_debugfs_file_t file, void *arg) +{ + struct dbr_debugfs_priv *priv = arg; + + return target_if_dbr_print_ring_debug_entries(qdf_debugfs_printer, + file, priv->dbr_pdev_obj, + priv->mod_id, + priv->srng_id); +} + +/** + * target_if_dbr_mod_debugfs_init() - Init debugfs for a given module + * @dbr_pdev_obj: Pointer to the pdev obj of Direct buffer rx module + * @mod_id: Module ID corresponding to this ring + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS target_if_dbr_mod_debugfs_init( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj, + enum DBR_MODULE mod_id) +{ + struct direct_buf_rx_module_debug *mod_debug; + + mod_debug = target_if_get_dbr_mod_debug_from_dbr_pdev_obj(dbr_pdev_obj, + mod_id); + + if (!mod_debug) + return QDF_STATUS_E_INVAL; + + if (mod_debug->debugfs_entry) { + direct_buf_rx_err("debugfs mod entry was already created for %s module", + g_dbr_module_name[mod_id].module_name_str); + return QDF_STATUS_SUCCESS; + } + + mod_debug->debugfs_entry = + qdf_debugfs_create_dir(g_dbr_module_name[mod_id].module_name_str, + dbr_pdev_obj->debugfs_entry); + + if (!mod_debug->debugfs_entry) { + direct_buf_rx_err("error while creating direct_buf debugfs entry for %s module", + g_dbr_module_name[mod_id].module_name_str); + return QDF_STATUS_E_FAILURE; + } + + return QDF_STATUS_SUCCESS; +} + +/** + * target_if_dbr_ring_debugfs_init() - Init debugfs for a given ring + * @dbr_pdev_obj: Pointer to the pdev obj of Direct buffer rx module + * @mod_id: Module ID corresponding to this ring + * @srng_id: srng ID corresponding to this ring + * + * Return: QDF_STATUS of operation + */ +static QDF_STATUS target_if_dbr_ring_debugfs_init( + struct direct_buf_rx_pdev_obj *dbr_pdev_obj, + enum DBR_MODULE mod_id, uint8_t srng_id) +{ + struct direct_buf_rx_module_debug *mod_debug; + struct direct_buf_rx_ring_debug *ring_debug; + struct dbr_debugfs_priv *priv; + char debug_file_name[32]; + + mod_debug = target_if_get_dbr_mod_debug_from_dbr_pdev_obj(dbr_pdev_obj, + mod_id); + + if (!mod_debug) + return QDF_STATUS_E_INVAL; + + ring_debug = &mod_debug->dbr_ring_debug[srng_id]; + + if (!mod_debug->debugfs_entry) { + direct_buf_rx_err("error mod_debug->debugfs_entry not created"); + return QDF_STATUS_E_FAILURE; + } + + if (ring_debug->debugfs_entry) { + direct_buf_rx_err("debugfs file for %d ring under %s module already created", + srng_id, + g_dbr_module_name[mod_id].module_name_str); + return QDF_STATUS_SUCCESS; + } + + qdf_snprintf(debug_file_name, sizeof(debug_file_name), + "ring_%d", srng_id); + + // Allocate debugfs ops + ring_debug->debugfs_fops = + qdf_mem_malloc(sizeof(*ring_debug->debugfs_fops)); + if (!ring_debug->debugfs_fops) { + direct_buf_rx_err("error in allocating debugfs ops"); + return QDF_STATUS_E_NOMEM; + } + + // Allocate private data + priv = qdf_mem_malloc(sizeof(*priv)); + if (!priv) { + direct_buf_rx_err("error in creating debugfs private data"); + goto priv_alloc_fail; + } + priv->dbr_pdev_obj = dbr_pdev_obj; + priv->mod_id = mod_id; + priv->srng_id = srng_id; + + /* Fill in the debugfs ops for this ring. + * When the output time comes, the 'show' function will be + * called with 'priv' as an argument. + */ + ring_debug->debugfs_fops->show = target_if_dbr_debugfs_show_ring_debug; + ring_debug->debugfs_fops->priv = priv; + + ring_debug->debugfs_entry = + qdf_debugfs_create_file_simplified( + debug_file_name, + (QDF_FILE_USR_READ | QDF_FILE_GRP_READ | + QDF_FILE_OTH_READ), + mod_debug->debugfs_entry, + ring_debug->debugfs_fops); + + if (!ring_debug->debugfs_entry) { + direct_buf_rx_err("error while creating direct_buf debugfs file for %d ring under %s module", + srng_id, + g_dbr_module_name[mod_id].module_name_str); + goto file_creation_fail; + } + + return QDF_STATUS_SUCCESS; + +file_creation_fail: + qdf_mem_free(ring_debug->debugfs_fops->priv); + +priv_alloc_fail: + qdf_mem_free(ring_debug->debugfs_fops); + ring_debug->debugfs_fops = NULL; + return QDF_STATUS_E_NOMEM; +} + +/** + * target_if_dbr_mod_debugfs_deinit() - De-init debugfs for a given module + * @mod_debug: Pointer to direct_buf_rx_module_debug structure + * + * Return: void + */ +static void target_if_dbr_mod_debugfs_deinit( + struct direct_buf_rx_module_debug *mod_debug) +{ + if (!mod_debug) { + direct_buf_rx_err("mod_debug is null"); + return; + } + + if (mod_debug->debugfs_entry) { + qdf_debugfs_remove_file(mod_debug->debugfs_entry); + mod_debug->debugfs_entry = NULL; + } +} + +/** + * target_if_dbr_ring_debugfs_deinit() - De-init debugfs for a given ring + * @ring_debug: Pointer to direct_buf_rx_ring_debug structure + * + * Return: void + */ +static void target_if_dbr_ring_debugfs_deinit( + struct direct_buf_rx_ring_debug *ring_debug) +{ + if (!ring_debug) { + direct_buf_rx_err("ring_debug is null"); + return; + } + + if (ring_debug->debugfs_entry) { + qdf_debugfs_remove_file(ring_debug->debugfs_entry); + ring_debug->debugfs_entry = NULL; + } + + // Free the private data and debugfs ops of this ring + if (ring_debug->debugfs_fops) { + qdf_mem_free(ring_debug->debugfs_fops->priv); + qdf_mem_free(ring_debug->debugfs_fops); + ring_debug->debugfs_fops = NULL; + } +} +#endif /* WLAN_DEBUGFS && DIRECT_BUF_RX_DEBUG */ + #ifdef DIRECT_BUF_RX_DEBUG QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, uint8_t mod_id) @@ -409,13 +755,19 @@ QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, struct direct_buf_rx_ring_debug *ring_debug; uint8_t srng_id; - mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(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]; - + if (!ring_debug->entries) { + direct_buf_rx_err("DBR ring debug for module %d srng %d was already disabled", + mod_id, srng_id); + continue; + } + /* De-init debugsfs for this ring */ + target_if_dbr_ring_debugfs_deinit(ring_debug); qdf_mem_free(ring_debug->entries); ring_debug->entries = NULL; ring_debug->ring_debug_idx = 0; @@ -423,6 +775,7 @@ QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, direct_buf_rx_info("DBR ring debug for module %d srng %d is now stopped", mod_id, srng_id); } + target_if_dbr_mod_debugfs_deinit(mod_debug); return QDF_STATUS_SUCCESS; } @@ -431,11 +784,12 @@ 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_pdev_obj *dbr_pdev_obj; 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); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(pdev, mod_id); if (!mod_debug) return QDF_STATUS_E_INVAL; @@ -448,13 +802,18 @@ QDF_STATUS target_if_dbr_start_ring_debug(struct wlan_objmgr_pdev *pdev, return QDF_STATUS_E_FAILURE; } + dbr_pdev_obj = wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + target_if_dbr_mod_debugfs_init(dbr_pdev_obj, mod_id); + 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; + mod_id, srng_id); + continue; } ring_debug->entries = qdf_mem_malloc( @@ -466,9 +825,12 @@ QDF_STATUS target_if_dbr_start_ring_debug(struct wlan_objmgr_pdev *pdev, ring_debug->ring_debug_idx = 0; ring_debug->num_ring_debug_entries = num_ring_debug_entries; - + /* Init debugsfs for this ring */ + target_if_dbr_ring_debugfs_init( + dbr_pdev_obj, + mod_id, srng_id); direct_buf_rx_info("DBR ring debug for module %d srng %d is now started", - mod_id, srng_id); + mod_id, srng_id); } return QDF_STATUS_SUCCESS; } @@ -478,7 +840,7 @@ QDF_STATUS target_if_dbr_start_buffer_poisoning(struct wlan_objmgr_pdev *pdev, { struct direct_buf_rx_module_debug *mod_debug; - mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(pdev, mod_id); if (!mod_debug) return QDF_STATUS_E_INVAL; @@ -497,7 +859,7 @@ QDF_STATUS target_if_dbr_stop_buffer_poisoning( { struct direct_buf_rx_module_debug *mod_debug; - mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(pdev, mod_id); if (!mod_debug) return QDF_STATUS_E_INVAL; @@ -557,7 +919,7 @@ static QDF_STATUS target_if_dbr_debug_poison_buffer( { struct direct_buf_rx_module_debug *mod_debug; - mod_debug = target_if_get_dbr_mod_debug(pdev, mod_id); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(pdev, mod_id); if (!mod_debug) return QDF_STATUS_E_INVAL; @@ -570,6 +932,19 @@ static QDF_STATUS target_if_dbr_debug_poison_buffer( return QDF_STATUS_SUCCESS; } +static inline void target_if_dbr_qdf_show_ring_debug( + struct wlan_objmgr_pdev *pdev, + uint8_t mod_id, uint8_t srng_id) +{ + struct direct_buf_rx_pdev_obj *dbr_pdev_obj = + wlan_objmgr_pdev_get_comp_private_obj( + pdev, WLAN_TARGET_IF_COMP_DIRECT_BUF_RX); + + target_if_dbr_print_ring_debug_entries( + target_if_dbr_qdf_err_printer, + NULL, dbr_pdev_obj, + mod_id, srng_id); +} #else QDF_STATUS target_if_dbr_stop_ring_debug(struct wlan_objmgr_pdev *pdev, uint8_t mod_id) @@ -603,6 +978,12 @@ static QDF_STATUS target_if_dbr_debug_poison_buffer( { return QDF_STATUS_SUCCESS; } + +static inline void target_if_dbr_qdf_show_ring_debug( + struct wlan_objmgr_pdev *pdev, + uint8_t mod_id, uint8_t srng_id) +{ +} #endif /* DIRECT_BUF_RX_DEBUG */ static QDF_STATUS target_if_dbr_replenish_ring(struct wlan_objmgr_pdev *pdev, @@ -664,7 +1045,13 @@ static QDF_STATUS target_if_dbr_replenish_ring(struct wlan_objmgr_pdev *pdev, hal_srng_access_start(hal_soc, srng); ring_entry = hal_srng_src_get_next(hal_soc, srng); - QDF_ASSERT(ring_entry); + + if (!ring_entry) { + target_if_dbr_qdf_show_ring_debug(pdev, mod_param->mod_id, + mod_param->srng_id); + QDF_BUG(0); + } + dw_lo = (uint64_t)paddr & 0xFFFFFFFF; WMI_HOST_DBR_RING_ADDR_HI_SET(dw_hi, (uint64_t)paddr >> 32); WMI_HOST_DBR_DATA_ADDR_HI_HOST_DATA_SET(dw_hi, cookie); @@ -961,6 +1348,7 @@ static QDF_STATUS target_if_init_dbr_ring(struct wlan_objmgr_pdev *pdev, mod_param->mod_id = mod_id; mod_param->pdev_id = dbr_get_pdev_id( srng_id, wlan_objmgr_pdev_get_pdev_id(pdev)); + mod_param->srng_id = srng_id; /* Initialize DMA ring now */ status = target_if_dbr_init_srng(pdev, mod_param); @@ -1303,7 +1691,7 @@ static void target_if_dbr_add_ring_debug_entry( 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); + mod_debug = target_if_get_dbr_mod_debug_from_pdev(pdev, mod_id); if (!mod_debug) return; 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 aa7e77ef03ac..2828b97142ef 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 @@ -118,16 +118,36 @@ struct direct_buf_rx_ring_debug_entry { enum DBR_RING_DEBUG_EVENT event; }; +#ifdef WLAN_DEBUGFS +/** + * struct dbr_debugfs_priv - Private data for DBR ring debugfs + * @dbr_pdev_obj: Pointer to the pdev obj of Direct buffer rx module + * @mod_id: Pointer to the registered module ID + * @srng_id: srng ID + */ +struct dbr_debugfs_priv { + struct direct_buf_rx_pdev_obj *dbr_pdev_obj; + enum DBR_MODULE mod_id; + uint8_t srng_id; +}; +#endif + /** * 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 + * @debugfs_entry: Debugfs entry for this ring + * @debugfs_priv: Debugfs ops for this ring */ 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; +#ifdef WLAN_DEBUGFS + qdf_dentry_t debugfs_entry; + struct qdf_debugfs_fops *debugfs_fops; +#endif }; /** @@ -135,11 +155,15 @@ struct direct_buf_rx_ring_debug { * @dbr_ring_debug: Array of ring debug structers corresponding to each srng * @poisoning_enabled: Whether buffer poisoning is enabled for this module * @poison_value: Value with which buffers should be poisoned + * @debugfs_entry: Debugfs entry for this module */ struct direct_buf_rx_module_debug { struct direct_buf_rx_ring_debug dbr_ring_debug[DBR_SRNG_NUM]; bool poisoning_enabled; uint32_t poison_value; +#ifdef WLAN_DEBUGFS + qdf_dentry_t debugfs_entry; +#endif }; /** @@ -155,6 +179,7 @@ struct direct_buf_rx_module_debug { struct direct_buf_rx_module_param { enum DBR_MODULE mod_id; uint8_t pdev_id; + uint8_t srng_id; struct dbr_module_config dbr_config; struct direct_buf_rx_ring_cap *dbr_ring_cap; struct direct_buf_rx_ring_cfg *dbr_ring_cfg; @@ -168,12 +193,16 @@ struct direct_buf_rx_module_param { * @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 + * @debugfs_entry: DBR debugfs entry of this radio */ 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; +#ifdef WLAN_DEBUGFS + qdf_dentry_t debugfs_entry; +#endif #endif };