diff --git a/qdf/inc/qdf_nbuf.h b/qdf/inc/qdf_nbuf.h index c4abe7e131d5..46b983f05197 100644 --- a/qdf/inc/qdf_nbuf.h +++ b/qdf/inc/qdf_nbuf.h @@ -779,6 +779,8 @@ void qdf_net_buf_debug_delete_node(qdf_nbuf_t net_buf); void qdf_net_buf_debug_acquire_skb(qdf_nbuf_t net_buf, uint8_t *file_name, uint32_t line_num); void qdf_net_buf_debug_release_skb(qdf_nbuf_t net_buf); +void qdf_net_buf_free_debug_add(qdf_nbuf_t net_buf, uint8_t *file_name, + uint32_t line_num); /* nbuf allocation rouines */ @@ -800,15 +802,20 @@ qdf_nbuf_alloc_debug(qdf_device_t osdev, qdf_size_t size, int reserve, return net_buf; } -static inline void qdf_nbuf_free(qdf_nbuf_t net_buf) +#define qdf_nbuf_free(d) \ + qdf_nbuf_free_debug(d, __FILE__, __LINE__) +static inline void qdf_nbuf_free_debug(qdf_nbuf_t net_buf, + uint8_t *file_name, uint32_t line_num) { if (qdf_nbuf_is_tso(net_buf) && qdf_nbuf_get_users(net_buf) > 1) goto free_buf; /* Remove SKB from internal QDF tracking table */ - if (qdf_likely(net_buf)) + if (qdf_likely(net_buf)) { + qdf_net_buf_free_debug_add(net_buf, file_name, line_num); qdf_net_buf_debug_delete_node(net_buf); + } free_buf: __qdf_nbuf_free(net_buf); diff --git a/qdf/linux/src/qdf_nbuf.c b/qdf/linux/src/qdf_nbuf.c index 61bd357fb104..5e5600734f6b 100644 --- a/qdf/linux/src/qdf_nbuf.c +++ b/qdf/linux/src/qdf_nbuf.c @@ -42,6 +42,7 @@ #include #include #include +#include #include #if defined(FEATURE_TSO) @@ -1213,6 +1214,30 @@ 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 * @@ -1515,6 +1540,51 @@ 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 *