|
@@ -470,6 +470,50 @@ void __qdf_nbuf_free(struct sk_buff *skb)
|
|
|
EXPORT_SYMBOL(__qdf_nbuf_free);
|
|
|
|
|
|
#ifdef MEMORY_DEBUG
|
|
|
+enum qdf_nbuf_event_type {
|
|
|
+ QDF_NBUF_ALLOC,
|
|
|
+ QDF_NBUF_FREE,
|
|
|
+ QDF_NBUF_MAP,
|
|
|
+ QDF_NBUF_UNMAP,
|
|
|
+};
|
|
|
+
|
|
|
+struct qdf_nbuf_event {
|
|
|
+ qdf_nbuf_t nbuf;
|
|
|
+ const char *file;
|
|
|
+ uint32_t line;
|
|
|
+ enum qdf_nbuf_event_type type;
|
|
|
+ uint64_t timestamp;
|
|
|
+};
|
|
|
+
|
|
|
+#define QDF_NBUF_HISTORY_SIZE 4096
|
|
|
+static qdf_atomic_t qdf_nbuf_history_index;
|
|
|
+static struct qdf_nbuf_event qdf_nbuf_history[QDF_NBUF_HISTORY_SIZE];
|
|
|
+
|
|
|
+static int32_t qdf_nbuf_circular_index_next(qdf_atomic_t *index, int size)
|
|
|
+{
|
|
|
+ int32_t next = qdf_atomic_inc_return(index);
|
|
|
+
|
|
|
+ if (next == size)
|
|
|
+ qdf_atomic_sub(size, index);
|
|
|
+
|
|
|
+ return next % size;
|
|
|
+}
|
|
|
+
|
|
|
+static void
|
|
|
+qdf_nbuf_history_add(qdf_nbuf_t nbuf, const char *file, uint32_t line,
|
|
|
+ enum qdf_nbuf_event_type type)
|
|
|
+{
|
|
|
+ int32_t idx = qdf_nbuf_circular_index_next(&qdf_nbuf_history_index,
|
|
|
+ QDF_NBUF_HISTORY_SIZE);
|
|
|
+ struct qdf_nbuf_event *event = &qdf_nbuf_history[idx];
|
|
|
+
|
|
|
+ event->nbuf = nbuf;
|
|
|
+ event->file = file;
|
|
|
+ event->line = line;
|
|
|
+ event->type = type;
|
|
|
+ event->timestamp = qdf_get_log_timestamp();
|
|
|
+}
|
|
|
+
|
|
|
#define QDF_NBUF_MAP_HT_BITS 10 /* 1024 buckets */
|
|
|
static DECLARE_HASHTABLE(qdf_nbuf_map_ht, QDF_NBUF_MAP_HT_BITS);
|
|
|
static qdf_spinlock_t qdf_nbuf_map_lock;
|
|
@@ -569,6 +613,8 @@ qdf_nbuf_track_map(qdf_nbuf_t nbuf, const char *file, uint32_t line)
|
|
|
hash_add(qdf_nbuf_map_ht, &meta->node, (size_t)nbuf);
|
|
|
qdf_spin_unlock_irqrestore(&qdf_nbuf_map_lock);
|
|
|
|
|
|
+ qdf_nbuf_history_add(nbuf, file, line, QDF_NBUF_MAP);
|
|
|
+
|
|
|
return QDF_STATUS_SUCCESS;
|
|
|
}
|
|
|
|
|
@@ -594,6 +640,8 @@ qdf_nbuf_untrack_map(qdf_nbuf_t nbuf, const char *file, uint32_t line)
|
|
|
qdf_spin_unlock_irqrestore(&qdf_nbuf_map_lock);
|
|
|
|
|
|
qdf_mem_free(meta);
|
|
|
+
|
|
|
+ qdf_nbuf_history_add(nbuf, file, line, QDF_NBUF_UNMAP);
|
|
|
}
|
|
|
|
|
|
QDF_STATUS qdf_nbuf_map_debug(qdf_device_t osdev,
|
|
@@ -1606,30 +1654,6 @@ static uint32_t qdf_net_buf_track_max_used;
|
|
|
static uint32_t qdf_net_buf_track_max_free;
|
|
|
static uint32_t qdf_net_buf_track_max_allocated;
|
|
|
|
|
|
-/**
|
|
|
- * struct qdf_nbuf_free_track_t - Network buffer free track structure
|
|
|
- * @p_next: Pointer to next
|
|
|
- * @net_buf: Pointer to network buffer
|
|
|
- * @file_name: File name
|
|
|
- * @line_num: Line number
|
|
|
- * @time: Time stamp
|
|
|
- */
|
|
|
-struct qdf_nbuf_free_track_t {
|
|
|
- struct qdf_nbuf_track_t *p_next;
|
|
|
- qdf_nbuf_t net_buf;
|
|
|
- uint8_t *file_name;
|
|
|
- uint32_t line_num;
|
|
|
- uint64_t time;
|
|
|
-};
|
|
|
-
|
|
|
-struct qdf_nbuf_free_record_t {
|
|
|
- struct qdf_nbuf_free_track_t gp_qdf_netbuf_free_tbl[
|
|
|
- QDF_NET_BUF_TRACK_MAX_SIZE];
|
|
|
- qdf_atomic_t count;
|
|
|
-};
|
|
|
-
|
|
|
-static struct qdf_nbuf_free_record_t qdf_nbuf_free_record_info;
|
|
|
-
|
|
|
/**
|
|
|
* update_max_used() - update qdf_net_buf_track_max_used tracking variable
|
|
|
*
|
|
@@ -1880,6 +1904,8 @@ void qdf_net_buf_debug_init(void)
|
|
|
{
|
|
|
uint32_t i;
|
|
|
|
|
|
+ qdf_atomic_set(&qdf_nbuf_history_index, -1);
|
|
|
+
|
|
|
qdf_nbuf_map_tracking_init();
|
|
|
qdf_nbuf_track_memory_manager_create();
|
|
|
|
|
@@ -1934,51 +1960,6 @@ void qdf_net_buf_debug_exit(void)
|
|
|
}
|
|
|
EXPORT_SYMBOL(qdf_net_buf_debug_exit);
|
|
|
|
|
|
-/**
|
|
|
- * qdf_nbuf_free_dbg_get_index() - Get the next record index
|
|
|
- * @tbl_index: atomic index variable to increment
|
|
|
- * @size: array size of the circular buffer
|
|
|
- *
|
|
|
- * Return: array index
|
|
|
- */
|
|
|
-static int qdf_nbuf_free_dbg_get_index(qdf_atomic_t *tbl_index, int size)
|
|
|
-{
|
|
|
- int index = qdf_atomic_inc_return(tbl_index);
|
|
|
-
|
|
|
- if (index == size)
|
|
|
- qdf_atomic_sub(size, tbl_index);
|
|
|
-
|
|
|
- while (index >= size)
|
|
|
- index -= size;
|
|
|
-
|
|
|
- return index;
|
|
|
-}
|
|
|
-
|
|
|
-/**
|
|
|
- * qdf_netbuf_free_debug_add() - Add netbuff free info to the debug
|
|
|
- * @netbuf: pointer to network buffer
|
|
|
- * @file_name: fie name from where net buff is freed
|
|
|
- * @line_num: line number
|
|
|
- *
|
|
|
- * Return: none
|
|
|
- */
|
|
|
-void qdf_net_buf_free_debug_add(qdf_nbuf_t net_buf, uint8_t *file_name,
|
|
|
- uint32_t line_num)
|
|
|
-{
|
|
|
- struct qdf_nbuf_free_track_t *p_node;
|
|
|
- uint16_t index;
|
|
|
-
|
|
|
- index = qdf_nbuf_free_dbg_get_index(&qdf_nbuf_free_record_info.count,
|
|
|
- QDF_NET_BUF_TRACK_MAX_SIZE);
|
|
|
-
|
|
|
- p_node = &qdf_nbuf_free_record_info.gp_qdf_netbuf_free_tbl[index];
|
|
|
- p_node->net_buf = net_buf;
|
|
|
- p_node->file_name = file_name;
|
|
|
- p_node->line_num = line_num;
|
|
|
- p_node->time = qdf_get_log_timestamp();
|
|
|
-}
|
|
|
-EXPORT_SYMBOL(qdf_net_buf_free_debug_add);
|
|
|
-
|
|
|
/**
|
|
|
* qdf_net_buf_debug_hash() - hash network buffer pointer
|
|
|
*
|
|
@@ -2165,6 +2146,40 @@ void qdf_net_buf_debug_release_skb(qdf_nbuf_t net_buf)
|
|
|
}
|
|
|
EXPORT_SYMBOL(qdf_net_buf_debug_release_skb);
|
|
|
|
|
|
+qdf_nbuf_t qdf_nbuf_alloc_debug(qdf_device_t osdev, qdf_size_t size,
|
|
|
+ int reserve, int align, int prio,
|
|
|
+ uint8_t *file, uint32_t line)
|
|
|
+{
|
|
|
+ qdf_nbuf_t nbuf;
|
|
|
+
|
|
|
+ nbuf = __qdf_nbuf_alloc(osdev, size, reserve, align, prio);
|
|
|
+
|
|
|
+ /* Store SKB in internal QDF tracking table */
|
|
|
+ if (qdf_likely(nbuf)) {
|
|
|
+ qdf_net_buf_debug_add_node(nbuf, size, file, line);
|
|
|
+ qdf_nbuf_history_add(nbuf, file, line, QDF_NBUF_ALLOC);
|
|
|
+ }
|
|
|
+
|
|
|
+ return nbuf;
|
|
|
+}
|
|
|
+qdf_export_symbol(qdf_nbuf_alloc_debug);
|
|
|
+
|
|
|
+void qdf_nbuf_free_debug(qdf_nbuf_t nbuf, uint8_t *file, uint32_t line)
|
|
|
+{
|
|
|
+ if (qdf_nbuf_is_tso(nbuf) && qdf_nbuf_get_users(nbuf) > 1)
|
|
|
+ goto free_buf;
|
|
|
+
|
|
|
+ /* Remove SKB from internal QDF tracking table */
|
|
|
+ if (qdf_likely(nbuf)) {
|
|
|
+ qdf_net_buf_debug_delete_node(nbuf);
|
|
|
+ qdf_nbuf_history_add(nbuf, file, line, QDF_NBUF_FREE);
|
|
|
+ }
|
|
|
+
|
|
|
+free_buf:
|
|
|
+ __qdf_nbuf_free(nbuf);
|
|
|
+}
|
|
|
+qdf_export_symbol(qdf_nbuf_free_debug);
|
|
|
+
|
|
|
#endif /*MEMORY_DEBUG */
|
|
|
#if defined(FEATURE_TSO)
|
|
|
|