Browse Source

qcacmn: Add major print logic for SKB

Add major print logic for SKB as it is currently done for kmalloc and
dma allocations so that SKB allocations can be profiled.

Change-Id: Ic78cef61bc1519aa54da9823199add92c116aad7
CRs-Fixed: 2769631
Alan Chen 4 years ago
parent
commit
907c485706
3 changed files with 294 additions and 30 deletions
  1. 73 1
      qdf/inc/qdf_nbuf.h
  2. 199 0
      qdf/linux/src/qdf_mem.c
  3. 22 29
      qdf/linux/src/qdf_nbuf.c

+ 73 - 1
qdf/inc/qdf_nbuf.h

@@ -148,6 +148,9 @@
 #define QDF_NBUF_TX_PKT_STATE_MAX            10
 #define QDF_NBUF_TX_PKT_STATE_MAX            10
 #define QDF_NBUF_TX_PKT_LI_DP                11
 #define QDF_NBUF_TX_PKT_LI_DP                11
 
 
+/* nbuf allocations only come from one domain */
+#define QDF_DEBUG_NBUF_DOMAIN		     0
+
 /* qdf_nbuf allocate and map max retry threshold when failed */
 /* qdf_nbuf allocate and map max retry threshold when failed */
 #define QDF_NBUF_ALLOC_MAP_RETRY_THRESHOLD      20
 #define QDF_NBUF_ALLOC_MAP_RETRY_THRESHOLD      20
 
 
@@ -408,7 +411,7 @@ struct qdf_radiotap_vendor_ns {
 } __attribute__((__packed__));
 } __attribute__((__packed__));
 
 
 /**
 /**
- * strcut qdf_radiotap_vendor_ns_ath - Combined QTI Vendor NS
+ * struct qdf_radiotap_vendor_ns_ath - Combined QTI Vendor NS
  * including the Radiotap specified Vendor Namespace header and
  * including the Radiotap specified Vendor Namespace header and
  * QTI specific Vendor Namespace data
  * QTI specific Vendor Namespace data
  * @lsig: L_SIG_A (or L_SIG)
  * @lsig: L_SIG_A (or L_SIG)
@@ -425,6 +428,8 @@ struct qdf_radiotap_vendor_ns_ath {
 	uint32_t ppdu_start_timestamp;
 	uint32_t ppdu_start_timestamp;
 } __attribute__((__packed__));
 } __attribute__((__packed__));
 
 
+#define QDF_MEM_FUNC_NAME_SIZE 48
+
 /* Masks for HE SIG known fields in mon_rx_status structure */
 /* Masks for HE SIG known fields in mon_rx_status structure */
 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0	0x00000001
 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU0	0x00000001
 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU1	0x00000002
 #define QDF_MON_STATUS_HE_SIG_B_COMMON_KNOWN_RU1	0x00000002
@@ -654,6 +659,37 @@ enum cb_ftype {
  */
  */
 typedef __qdf_nbuf_t qdf_nbuf_t;
 typedef __qdf_nbuf_t qdf_nbuf_t;
 
 
+/**
+ * struct qdf_nbuf_track_t - Network buffer track structure
+ *
+ * @p_next: Pointer to next
+ * @net_buf: Pointer to network buffer
+ * @func_name: Function name
+ * @line_num: Line number
+ * @size: Size
+ * @map_func_name: nbuf mapping function name
+ * @map_line_num: mapping function line number
+ * @unmap_func_name: nbuf unmapping function name
+ * @unmap_line_num: mapping function line number
+ * @is_nbuf_mapped: indicate mapped/unmapped nbuf
+ * @time: mapping function timestamp
+ */
+struct qdf_nbuf_track_t {
+	struct qdf_nbuf_track_t *p_next;
+	qdf_nbuf_t net_buf;
+	char func_name[QDF_MEM_FUNC_NAME_SIZE];
+	uint32_t line_num;
+	size_t size;
+	char map_func_name[QDF_MEM_FUNC_NAME_SIZE];
+	uint32_t map_line_num;
+	char unmap_func_name[QDF_MEM_FUNC_NAME_SIZE];
+	uint32_t unmap_line_num;
+	bool is_nbuf_mapped;
+	qdf_time_t time;
+};
+
+typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK;
+
 /**
 /**
  * typedef qdf_nbuf_queue_head_t - Platform indepedent nbuf queue head
  * typedef qdf_nbuf_queue_head_t - Platform indepedent nbuf queue head
  */
  */
@@ -1454,6 +1490,9 @@ static inline qdf_nbuf_t qdf_nbuf_next(qdf_nbuf_t buf)
 }
 }
 
 
 #ifdef NBUF_MEMORY_DEBUG
 #ifdef NBUF_MEMORY_DEBUG
+
+#define QDF_NET_BUF_TRACK_MAX_SIZE    (1024)
+
 void qdf_net_buf_debug_init(void);
 void qdf_net_buf_debug_init(void);
 void qdf_net_buf_debug_exit(void);
 void qdf_net_buf_debug_exit(void);
 void qdf_net_buf_debug_clean(void);
 void qdf_net_buf_debug_clean(void);
@@ -3907,6 +3946,39 @@ static inline void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf,
 }
 }
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
 
 
+#ifdef MEMORY_DEBUG
+/**
+ * qdf_nbuf_acquire_track_lock - acquire the nbuf spinlock at the
+ * specified index
+ * @index: index to get the lock
+ * @irq_flag: lock flag for using nbuf lock
+ *
+ * Return: none
+ */
+void qdf_nbuf_acquire_track_lock(uint32_t index,
+				 unsigned long irq_flag);
+
+/**
+ * qdf_nbuf_release_track_lock - release the nbuf spinlock at the
+ * specified index
+ * @index: index of the lock to be released
+ * @irq_flag: lock flag for using nbuf lock
+ *
+ * Return: none
+ */
+void qdf_nbuf_release_track_lock(uint32_t index,
+				 unsigned long irq_flag);
+
+/**
+ * qdf_nbuf_get_track_tbl - get the QDF_NBUF_TRACK entry from the track
+ * table at the specified index
+ * @index: index to get the table entry
+ *
+ * Return: the QDF_NBUF_TRACK entry at the specified index in the table
+ */
+QDF_NBUF_TRACK *qdf_nbuf_get_track_tbl(uint32_t index);
+#endif /* MEMORY_DEBUG */
+
 #ifdef CONFIG_NBUF_AP_PLATFORM
 #ifdef CONFIG_NBUF_AP_PLATFORM
 #include <i_qdf_nbuf_api_w.h>
 #include <i_qdf_nbuf_api_w.h>
 #else
 #else

+ 199 - 0
qdf/linux/src/qdf_mem.c

@@ -73,6 +73,7 @@ static struct __qdf_mem_stat {
 enum list_type {
 enum list_type {
 	LIST_TYPE_MEM = 0,
 	LIST_TYPE_MEM = 0,
 	LIST_TYPE_DMA = 1,
 	LIST_TYPE_DMA = 1,
+	LIST_TYPE_NBUF = 2,
 	LIST_TYPE_MAX,
 	LIST_TYPE_MAX,
 };
 };
 
 
@@ -103,6 +104,13 @@ static struct major_alloc_priv dma_priv = {
 	50
 	50
 };
 };
 
 
+static struct major_alloc_priv nbuf_priv = {
+	/* List type set to NBUF */
+	LIST_TYPE_NBUF,
+	/* initial threshold to list APIs which allocates nbuf >= 50 times */
+	50
+};
+
 static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT];
 static qdf_list_t qdf_mem_domains[QDF_DEBUG_DOMAIN_COUNT];
 static qdf_spinlock_t qdf_mem_list_lock;
 static qdf_spinlock_t qdf_mem_list_lock;
 
 
@@ -699,6 +707,181 @@ static ssize_t qdf_major_alloc_set_threshold(struct file *file,
 	return buf_size;
 	return buf_size;
 }
 }
 
 
+/**
+ * qdf_print_major_nbuf_allocs() - output agnostic nbuf print logic
+ * @threshold: the threshold value set by uset to list top allocations
+ * @print: the print adapter function
+ * @print_priv: the private data to be consumed by @print
+ * @mem_print: pointer to function which prints the memory allocation data
+ *
+ * Return: None
+ */
+static void
+qdf_print_major_nbuf_allocs(uint32_t threshold,
+			    qdf_abstract_print print,
+			    void *print_priv,
+			    void (*mem_print)(struct __qdf_mem_info *,
+					      qdf_abstract_print,
+					      void *, uint32_t))
+{
+	uint32_t nbuf_iter;
+	unsigned long irq_flag = 0;
+	QDF_NBUF_TRACK *p_node;
+	QDF_NBUF_TRACK *p_prev;
+	struct __qdf_mem_info table[QDF_MEM_STAT_TABLE_SIZE];
+	struct qdf_mem_header meta;
+	bool is_full;
+
+	qdf_mem_zero(table, sizeof(table));
+	qdf_mem_debug_print_header(print, print_priv, threshold);
+
+	if (is_initial_mem_debug_disabled)
+		return;
+
+	qdf_rl_info("major nbuf print with threshold %u", threshold);
+
+	for (nbuf_iter = 0; nbuf_iter < QDF_NET_BUF_TRACK_MAX_SIZE;
+	     nbuf_iter++) {
+		qdf_nbuf_acquire_track_lock(nbuf_iter, irq_flag);
+		p_node = qdf_nbuf_get_track_tbl(nbuf_iter);
+		while (p_node) {
+			meta.line = p_node->line_num;
+			meta.size = p_node->size;
+			meta.caller = NULL;
+			meta.time = p_node->time;
+			qdf_str_lcopy(meta.func, p_node->func_name,
+				      QDF_MEM_FUNC_NAME_SIZE);
+
+			is_full = qdf_mem_meta_table_insert(table, &meta);
+
+			if (is_full) {
+				(*mem_print)(table, print,
+					     print_priv, threshold);
+				qdf_mem_zero(table, sizeof(table));
+			}
+
+			p_prev = p_node;
+			p_node = p_node->p_next;
+		}
+		qdf_nbuf_release_track_lock(nbuf_iter, irq_flag);
+	}
+
+	(*mem_print)(table, print, print_priv, threshold);
+
+	qdf_rl_info("major nbuf print end");
+}
+
+/**
+ * qdf_major_nbuf_alloc_show() - print sequential callback
+ * @seq: seq_file handle
+ * @v: current iterator
+ *
+ * Return: 0 - success
+ */
+static int qdf_major_nbuf_alloc_show(struct seq_file *seq, void *v)
+{
+	struct major_alloc_priv *priv = (struct major_alloc_priv *)seq->private;
+
+	if (!priv) {
+		qdf_err("priv is null");
+		return -EINVAL;
+	}
+
+	qdf_print_major_nbuf_allocs(priv->threshold,
+				    seq_printf_printer,
+				    seq,
+				    qdf_print_major_alloc);
+
+	return 0;
+}
+
+/**
+ * qdf_nbuf_seq_start() - sequential callback to start
+ * @seq: seq_file handle
+ * @pos: The start position of the sequence
+ *
+ * Return: iterator pointer, or NULL if iteration is complete
+ */
+static void *qdf_nbuf_seq_start(struct seq_file *seq, loff_t *pos)
+{
+	enum qdf_debug_domain domain = *pos;
+
+	if (domain > QDF_DEBUG_NBUF_DOMAIN)
+		return NULL;
+
+	return pos;
+}
+
+/**
+ * qdf_nbuf_seq_next() - next sequential callback
+ * @seq: seq_file handle
+ * @v: the current iterator
+ * @pos: the current position
+ *
+ * Get the next node and release previous node.
+ *
+ * Return: iterator pointer, or NULL if iteration is complete
+ */
+static void *qdf_nbuf_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+{
+	++*pos;
+
+	return qdf_nbuf_seq_start(seq, pos);
+}
+
+/**
+ * qdf_nbuf_seq_stop() - stop sequential callback
+ * @seq: seq_file handle
+ * @v: current iterator
+ *
+ * Return: None
+ */
+static void qdf_nbuf_seq_stop(struct seq_file *seq, void *v) { }
+
+/* sequential file operation table created to track major skb allocs */
+static const struct seq_operations qdf_major_nbuf_allocs_seq_ops = {
+	.start = qdf_nbuf_seq_start,
+	.next = qdf_nbuf_seq_next,
+	.stop = qdf_nbuf_seq_stop,
+	.show = qdf_major_nbuf_alloc_show,
+};
+
+static int qdf_major_nbuf_allocs_open(struct inode *inode, struct file *file)
+{
+	void *private = inode->i_private;
+	struct seq_file *seq;
+	int rc;
+
+	rc = seq_open(file, &qdf_major_nbuf_allocs_seq_ops);
+	if (rc == 0) {
+		seq = file->private_data;
+		seq->private = private;
+	}
+	return rc;
+}
+
+static ssize_t qdf_major_nbuf_alloc_set_threshold(struct file *file,
+						  const char __user *user_buf,
+						  size_t count,
+						  loff_t *pos)
+{
+	char buf[32];
+	ssize_t buf_size;
+	uint32_t threshold;
+	struct seq_file *seq = file->private_data;
+	struct major_alloc_priv *priv = (struct major_alloc_priv *)seq->private;
+
+	buf_size = min(count, (sizeof(buf) - 1));
+	if (buf_size <= 0)
+		return 0;
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+	buf[buf_size] = '\0';
+	if (!kstrtou32(buf, 10, &threshold))
+		priv->threshold = threshold;
+	return buf_size;
+}
+
 /* file operation table for listing major allocs */
 /* file operation table for listing major allocs */
 static const struct file_operations fops_qdf_major_allocs = {
 static const struct file_operations fops_qdf_major_allocs = {
 	.owner = THIS_MODULE,
 	.owner = THIS_MODULE,
@@ -718,6 +901,16 @@ static const struct file_operations fops_qdf_mem_debugfs = {
 	.release = seq_release,
 	.release = seq_release,
 };
 };
 
 
+/* file operation table for listing major allocs */
+static const struct file_operations fops_qdf_nbuf_major_allocs = {
+	.owner = THIS_MODULE,
+	.open = qdf_major_nbuf_allocs_open,
+	.read = seq_read,
+	.llseek = seq_lseek,
+	.release = seq_release,
+	.write = qdf_major_nbuf_alloc_set_threshold,
+};
+
 static QDF_STATUS qdf_mem_debug_debugfs_init(void)
 static QDF_STATUS qdf_mem_debug_debugfs_init(void)
 {
 {
 	if (is_initial_mem_debug_disabled)
 	if (is_initial_mem_debug_disabled)
@@ -744,6 +937,12 @@ static QDF_STATUS qdf_mem_debug_debugfs_init(void)
 			    &dma_priv,
 			    &dma_priv,
 			    &fops_qdf_major_allocs);
 			    &fops_qdf_major_allocs);
 
 
+	debugfs_create_file("major_nbuf_allocs",
+			    0600,
+			    qdf_mem_debugfs_root,
+			    &nbuf_priv,
+			    &fops_qdf_nbuf_major_allocs);
+
 	return QDF_STATUS_SUCCESS;
 	return QDF_STATUS_SUCCESS;
 }
 }
 
 

+ 22 - 29
qdf/linux/src/qdf_nbuf.c

@@ -2109,37 +2109,8 @@ bool __qdf_nbuf_is_bcast_pkt(qdf_nbuf_t nbuf)
 qdf_export_symbol(__qdf_nbuf_is_bcast_pkt);
 qdf_export_symbol(__qdf_nbuf_is_bcast_pkt);
 
 
 #ifdef NBUF_MEMORY_DEBUG
 #ifdef NBUF_MEMORY_DEBUG
-#define QDF_NET_BUF_TRACK_MAX_SIZE    (1024)
-
-/**
- * struct qdf_nbuf_track_t - Network buffer track structure
- *
- * @p_next: Pointer to next
- * @net_buf: Pointer to network buffer
- * @func_name: Function name
- * @line_num: Line number
- * @size: Size
- * @map_func_name: nbuf mapping function name
- * @map_line_num: mapping function line number
- * @unmap_func_name: nbuf unmapping function name
- * @unmap_line_num: mapping function line number
- * @is_nbuf_mapped: indicate mapped/unmapped nbuf
- */
-struct qdf_nbuf_track_t {
-	struct qdf_nbuf_track_t *p_next;
-	qdf_nbuf_t net_buf;
-	char func_name[QDF_MEM_FUNC_NAME_SIZE];
-	uint32_t line_num;
-	size_t size;
-	char map_func_name[QDF_MEM_FUNC_NAME_SIZE];
-	uint32_t map_line_num;
-	char unmap_func_name[QDF_MEM_FUNC_NAME_SIZE];
-	uint32_t unmap_line_num;
-	bool is_nbuf_mapped;
-};
 
 
 static spinlock_t g_qdf_net_buf_track_lock[QDF_NET_BUF_TRACK_MAX_SIZE];
 static spinlock_t g_qdf_net_buf_track_lock[QDF_NET_BUF_TRACK_MAX_SIZE];
-typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK;
 
 
 static QDF_NBUF_TRACK *gp_qdf_net_buf_track_tbl[QDF_NET_BUF_TRACK_MAX_SIZE];
 static QDF_NBUF_TRACK *gp_qdf_net_buf_track_tbl[QDF_NET_BUF_TRACK_MAX_SIZE];
 static struct kmem_cache *nbuf_tracking_cache;
 static struct kmem_cache *nbuf_tracking_cache;
@@ -2551,6 +2522,7 @@ void qdf_net_buf_debug_add_node(qdf_nbuf_t net_buf, size_t size,
 			p_node->map_func_name[0] = '\0';
 			p_node->map_func_name[0] = '\0';
 			p_node->unmap_func_name[0] = '\0';
 			p_node->unmap_func_name[0] = '\0';
 			p_node->size = size;
 			p_node->size = size;
+			p_node->time = qdf_get_log_timestamp();
 			qdf_mem_skb_inc(size);
 			qdf_mem_skb_inc(size);
 			p_node->p_next = gp_qdf_net_buf_track_tbl[i];
 			p_node->p_next = gp_qdf_net_buf_track_tbl[i];
 			gp_qdf_net_buf_track_tbl[i] = p_node;
 			gp_qdf_net_buf_track_tbl[i] = p_node;
@@ -4826,3 +4798,24 @@ void qdf_net_buf_debug_release_frag(qdf_nbuf_t buf, const char *func,
 
 
 qdf_export_symbol(qdf_net_buf_debug_release_frag);
 qdf_export_symbol(qdf_net_buf_debug_release_frag);
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
 #endif /* NBUF_FRAG_MEMORY_DEBUG */
+
+#ifdef MEMORY_DEBUG
+void qdf_nbuf_acquire_track_lock(uint32_t index,
+				 unsigned long irq_flag)
+{
+	spin_lock_irqsave(&g_qdf_net_buf_track_lock[index],
+			  irq_flag);
+}
+
+void qdf_nbuf_release_track_lock(uint32_t index,
+				 unsigned long irq_flag)
+{
+	spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[index],
+			       irq_flag);
+}
+
+QDF_NBUF_TRACK *qdf_nbuf_get_track_tbl(uint32_t index)
+{
+	return gp_qdf_net_buf_track_tbl[index];
+}
+#endif /* MEMORY_DEBUG */