Browse Source

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
Shwetha G K 5 years ago
parent
commit
29121213c8

+ 51 - 1
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 */

+ 67 - 0
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);

+ 7 - 0
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...) \

+ 37 - 0
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 <qdf_module.h>
 
+#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,

+ 436 - 48
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;

+ 29 - 0
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
 };