qcacmn: Definitions to support SMMU debug framework

To support SMMU debug framework, add new definitions
and add logic to track the mapping and unmapping of
a buffer via nbuf tracker.

CRs-Fixed: 3255423
Change-Id: I0b9e2828e6cd5e3204b6bba57af8806c4d080b32
This commit is contained in:
Devender Kumar
2022-08-12 13:43:29 +05:30
committed by Madan Koyyalamudi
parent a85ce1152c
commit 736edd06a2
2 changed files with 336 additions and 3 deletions

View File

@@ -1066,6 +1066,15 @@ typedef __qdf_nbuf_t qdf_nbuf_t;
* @unmap_line_num: mapping function line number * @unmap_line_num: mapping function line number
* @is_nbuf_mapped: indicate mapped/unmapped nbuf * @is_nbuf_mapped: indicate mapped/unmapped nbuf
* @time: mapping function timestamp * @time: mapping function timestamp
* @smmu_map_line_num: smmu mapping line number
* @smmu_unmap_line_num: smmu unmapping line number
* @smmu_map_func_name: smmu mapping function name
* @smmu_unmap_func_name: smmu unmapping function name
* @is_nbuf_smmu_mapped: nbuf is smmu mapped
* @smmu_map_iova_addr: nbuf smmu map virtual address
* @smmu_map_pa_addr: nbuf smmu map physical address
* @smmu_unmap_iova_addr: nbuf smmu unmap virtual address
* @smmu_unmap_pa_addr: nbuf smmu unmap physical address
*/ */
struct qdf_nbuf_track_t { struct qdf_nbuf_track_t {
struct qdf_nbuf_track_t *p_next; struct qdf_nbuf_track_t *p_next;
@@ -1079,6 +1088,17 @@ struct qdf_nbuf_track_t {
uint32_t unmap_line_num; uint32_t unmap_line_num;
bool is_nbuf_mapped; bool is_nbuf_mapped;
qdf_time_t time; qdf_time_t time;
#ifdef NBUF_SMMU_MAP_UNMAP_DEBUG
uint32_t smmu_map_line_num;
uint32_t smmu_unmap_line_num;
char smmu_map_func_name[QDF_MEM_FUNC_NAME_SIZE];
char smmu_unmap_func_name[QDF_MEM_FUNC_NAME_SIZE];
bool is_nbuf_smmu_mapped;
unsigned long smmu_map_iova_addr;
unsigned long smmu_map_pa_addr;
unsigned long smmu_unmap_iova_addr;
unsigned long smmu_unmap_pa_addr;
#endif
}; };
typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK; typedef struct qdf_nbuf_track_t QDF_NBUF_TRACK;
@@ -1125,7 +1145,7 @@ qdf_nbuf_set_send_complete_flag(qdf_nbuf_t buf, bool flag)
#ifdef NBUF_MAP_UNMAP_DEBUG #ifdef NBUF_MAP_UNMAP_DEBUG
/** /**
* qdf_nbuf_map_check_for_leaks() - check for nbut map leaks * qdf_nbuf_map_check_for_leaks() - check for nbuf map leaks
* *
* Check for net buffers that have been mapped, but never unmapped. * Check for net buffers that have been mapped, but never unmapped.
* *
@@ -1955,6 +1975,8 @@ enum qdf_nbuf_event_type {
QDF_NBUF_MAP, QDF_NBUF_MAP,
QDF_NBUF_UNMAP, QDF_NBUF_UNMAP,
QDF_NBUF_ALLOC_COPY_EXPAND, QDF_NBUF_ALLOC_COPY_EXPAND,
QDF_NBUF_SMMU_MAP,
QDF_NBUF_SMMU_UNMAP,
}; };
void qdf_net_buf_debug_init(void); void qdf_net_buf_debug_init(void);
@@ -1986,6 +2008,87 @@ void qdf_net_buf_debug_update_map_node(qdf_nbuf_t net_buf,
const char *func_name, const char *func_name,
uint32_t line_num); uint32_t line_num);
/**
* qdf_nbuf_smmu_map_debug() - map smmu buffer
* @nbuf: network buffer
* @hdl: ipa handle
* @num_buffers: number of buffers
* @info: memory info
* @func: function name
* @line: line number
*
* Return: QDF_STATUS
*/
QDF_STATUS qdf_nbuf_smmu_map_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line);
/**
* qdf_nbuf_smmu_unmap_debug() - unmap smmu buffer
* @nbuf: network buffer
* @hdl: ipa handle
* @num_buffers: number of buffers
* @info: memory info
* @func: function name
* @line: line number
*
* Return: QDF_STATUS
*/
QDF_STATUS qdf_nbuf_smmu_unmap_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line);
#ifdef NBUF_SMMU_MAP_UNMAP_DEBUG
/**
* qdf_nbuf_map_check_for_smmu_leaks() - check for nbuf smmu map leaks
*
* Check for net buffers that have been smmu mapped, but never smmu unmapped.
*
* Returns: None
*/
void qdf_nbuf_map_check_for_smmu_leaks(void);
/**
* qdf_net_buf_debug_update_smmu_map_node() - update nbuf in debug
* hash table with the mapping function info
* @nbuf: network buffer
* @iova: Virtual address of buffer
* @pa: Physical address of buffer
* @func: function name that requests for mapping the nbuf
* @line: function line number
*
* Return: none
*/
void qdf_net_buf_debug_update_smmu_map_node(qdf_nbuf_t nbuf,
unsigned long iova,
unsigned long pa,
const char *func,
uint32_t line);
/**
* qdf_net_buf_debug_update_smmu_unmap_node() - update nbuf in debug
* hash table with the unmapping function info
* @nbuf: network buffer
* @iova: Virtual address of buffer
* @pa: Physical address of buffer
* @func: function name that requests for unmapping the nbuf
* @line: function line number
*
* Return: none
*/
void qdf_net_buf_debug_update_smmu_unmap_node(qdf_nbuf_t nbuf,
unsigned long iova,
unsigned long pa,
const char *func,
uint32_t line);
#endif
/** /**
* qdf_net_buf_debug_update_unmap_node() - update nbuf in debug * qdf_net_buf_debug_update_unmap_node() - update nbuf in debug
* hash table with the unmap function info * hash table with the unmap function info

View File

@@ -21,7 +21,9 @@
* DOC: qdf_nbuf.c * DOC: qdf_nbuf.c
* QCA driver framework(QDF) network buffer management APIs * QCA driver framework(QDF) network buffer management APIs
*/ */
#ifdef IPA_OFFLOAD
#include <i_qdf_ipa_wdi3.h>
#endif
#include <linux/hashtable.h> #include <linux/hashtable.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/version.h> #include <linux/version.h>
@@ -786,7 +788,8 @@ qdf_nbuf_history_add(qdf_nbuf_t nbuf, const char *func, uint32_t line,
event->line = line; event->line = line;
event->type = type; event->type = type;
event->timestamp = qdf_get_log_timestamp(); event->timestamp = qdf_get_log_timestamp();
if (type == QDF_NBUF_MAP || type == QDF_NBUF_UNMAP) if (type == QDF_NBUF_MAP || type == QDF_NBUF_UNMAP ||
type == QDF_NBUF_SMMU_MAP || type == QDF_NBUF_SMMU_UNMAP)
event->iova = QDF_NBUF_CB_PADDR(nbuf); event->iova = QDF_NBUF_CB_PADDR(nbuf);
else else
event->iova = 0; event->iova = 0;
@@ -801,6 +804,167 @@ void qdf_set_smmu_fault_state(bool smmu_fault_state)
qdf_export_symbol(qdf_set_smmu_fault_state); qdf_export_symbol(qdf_set_smmu_fault_state);
#endif /* NBUF_MEMORY_DEBUG */ #endif /* NBUF_MEMORY_DEBUG */
#ifdef NBUF_SMMU_MAP_UNMAP_DEBUG
#define qdf_nbuf_smmu_map_tracker_bits 11 /* 2048 buckets */
qdf_tracker_declare(qdf_nbuf_smmu_map_tracker, qdf_nbuf_smmu_map_tracker_bits,
"nbuf map-no-unmap events", "nbuf map", "nbuf unmap");
static void qdf_nbuf_smmu_map_tracking_init(void)
{
qdf_tracker_init(&qdf_nbuf_smmu_map_tracker);
}
static void qdf_nbuf_smmu_map_tracking_deinit(void)
{
qdf_tracker_deinit(&qdf_nbuf_smmu_map_tracker);
}
static QDF_STATUS
qdf_nbuf_track_smmu_map(qdf_nbuf_t nbuf, const char *func, uint32_t line)
{
if (is_initial_mem_debug_disabled)
return QDF_STATUS_SUCCESS;
return qdf_tracker_track(&qdf_nbuf_smmu_map_tracker, nbuf, func, line);
}
static void
qdf_nbuf_untrack_smmu_map(qdf_nbuf_t nbuf, const char *func, uint32_t line)
{
if (is_initial_mem_debug_disabled)
return;
qdf_nbuf_history_add(nbuf, func, line, QDF_NBUF_SMMU_UNMAP);
qdf_tracker_untrack(&qdf_nbuf_smmu_map_tracker, nbuf, func, line);
}
void qdf_nbuf_map_check_for_smmu_leaks(void)
{
qdf_tracker_check_for_leaks(&qdf_nbuf_smmu_map_tracker);
}
QDF_STATUS qdf_nbuf_smmu_map_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line)
{
QDF_STATUS status;
status = qdf_nbuf_track_smmu_map(nbuf, func, line);
if (QDF_IS_STATUS_ERROR(status))
return status;
status = __qdf_ipa_wdi_create_smmu_mapping(hdl, num_buffers, info);
if (QDF_IS_STATUS_ERROR(status)) {
qdf_nbuf_untrack_smmu_map(nbuf, func, line);
} else {
if (!is_initial_mem_debug_disabled)
qdf_nbuf_history_add(nbuf, func, line, QDF_NBUF_MAP);
qdf_net_buf_debug_update_smmu_map_node(nbuf, info->iova,
info->pa, func, line);
}
return status;
}
qdf_export_symbol(qdf_nbuf_smmu_map_debug);
QDF_STATUS qdf_nbuf_smmu_unmap_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line)
{
QDF_STATUS status;
qdf_nbuf_untrack_smmu_map(nbuf, func, line);
status = __qdf_ipa_wdi_release_smmu_mapping(hdl, num_buffers, info);
qdf_net_buf_debug_update_smmu_unmap_node(nbuf, info->iova,
info->pa, func, line);
return status;
}
qdf_export_symbol(qdf_nbuf_smmu_unmap_debug);
static void qdf_nbuf_panic_on_free_if_smmu_mapped(qdf_nbuf_t nbuf,
const char *func,
uint32_t line)
{
char map_func[QDF_TRACKER_FUNC_SIZE];
uint32_t map_line;
if (!qdf_tracker_lookup(&qdf_nbuf_smmu_map_tracker, nbuf,
&map_func, &map_line))
return;
QDF_MEMDEBUG_PANIC("Nbuf freed @ %s:%u while mapped from %s:%u",
func, line, map_func, map_line);
}
static inline void qdf_net_buf_update_smmu_params(QDF_NBUF_TRACK *p_node)
{
p_node->smmu_unmap_line_num = 0;
p_node->is_nbuf_smmu_mapped = false;
p_node->smmu_map_line_num = 0;
p_node->smmu_map_func_name[0] = '\0';
p_node->smmu_unmap_func_name[0] = '\0';
p_node->smmu_unmap_iova_addr = 0;
p_node->smmu_unmap_pa_addr = 0;
p_node->smmu_map_iova_addr = 0;
p_node->smmu_map_pa_addr = 0;
}
#else
#ifdef NBUF_MEMORY_DEBUG
static void qdf_nbuf_smmu_map_tracking_init(void)
{
}
static void qdf_nbuf_smmu_map_tracking_deinit(void)
{
}
static void qdf_nbuf_panic_on_free_if_smmu_mapped(qdf_nbuf_t nbuf,
const char *func,
uint32_t line)
{
}
static inline void qdf_net_buf_update_smmu_params(QDF_NBUF_TRACK *p_node)
{
}
#endif
#ifdef IPA_OFFLOAD
QDF_STATUS qdf_nbuf_smmu_map_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line)
{
return __qdf_ipa_wdi_create_smmu_mapping(hdl, num_buffers, info);
}
qdf_export_symbol(qdf_nbuf_smmu_map_debug);
QDF_STATUS qdf_nbuf_smmu_unmap_debug(qdf_nbuf_t nbuf,
uint8_t hdl,
uint8_t num_buffers,
qdf_mem_info_t *info,
const char *func,
uint32_t line)
{
return __qdf_ipa_wdi_release_smmu_mapping(hdl, num_buffers, info);
}
qdf_export_symbol(qdf_nbuf_smmu_unmap_debug);
#endif
#endif
#ifdef NBUF_MAP_UNMAP_DEBUG #ifdef NBUF_MAP_UNMAP_DEBUG
#define qdf_nbuf_map_tracker_bits 11 /* 2048 buckets */ #define qdf_nbuf_map_tracker_bits 11 /* 2048 buckets */
qdf_tracker_declare(qdf_nbuf_map_tracker, qdf_nbuf_map_tracker_bits, qdf_tracker_declare(qdf_nbuf_map_tracker, qdf_nbuf_map_tracker_bits,
@@ -2886,6 +3050,7 @@ void qdf_net_buf_debug_init(void)
qdf_atomic_set(&qdf_nbuf_history_index, -1); qdf_atomic_set(&qdf_nbuf_history_index, -1);
qdf_nbuf_map_tracking_init(); qdf_nbuf_map_tracking_init();
qdf_nbuf_smmu_map_tracking_init();
qdf_nbuf_track_memory_manager_create(); qdf_nbuf_track_memory_manager_create();
for (i = 0; i < QDF_NET_BUF_TRACK_MAX_SIZE; i++) { for (i = 0; i < QDF_NET_BUF_TRACK_MAX_SIZE; i++) {
@@ -2938,6 +3103,7 @@ void qdf_net_buf_debug_exit(void)
qdf_nbuf_track_memory_manager_destroy(); qdf_nbuf_track_memory_manager_destroy();
qdf_nbuf_map_tracking_deinit(); qdf_nbuf_map_tracking_deinit();
qdf_nbuf_smmu_map_tracking_deinit();
#ifdef CONFIG_HALT_KMEMLEAK #ifdef CONFIG_HALT_KMEMLEAK
if (count) { if (count) {
@@ -3029,6 +3195,7 @@ void qdf_net_buf_debug_add_node(qdf_nbuf_t net_buf, size_t size,
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(); p_node->time = qdf_get_log_timestamp();
qdf_net_buf_update_smmu_params(p_node);
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;
@@ -3095,6 +3262,66 @@ void qdf_net_buf_debug_update_map_node(qdf_nbuf_t net_buf,
spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag); spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag);
} }
#ifdef NBUF_SMMU_MAP_UNMAP_DEBUG
void qdf_net_buf_debug_update_smmu_map_node(qdf_nbuf_t nbuf,
unsigned long iova,
unsigned long pa,
const char *func,
uint32_t line)
{
uint32_t i;
unsigned long irq_flag;
QDF_NBUF_TRACK *p_node;
if (is_initial_mem_debug_disabled)
return;
i = qdf_net_buf_debug_hash(nbuf);
spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag);
p_node = qdf_net_buf_debug_look_up(nbuf);
if (p_node) {
qdf_str_lcopy(p_node->smmu_map_func_name, func,
QDF_MEM_FUNC_NAME_SIZE);
p_node->smmu_map_line_num = line;
p_node->is_nbuf_smmu_mapped = true;
p_node->smmu_map_iova_addr = iova;
p_node->smmu_map_pa_addr = pa;
}
spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag);
}
void qdf_net_buf_debug_update_smmu_unmap_node(qdf_nbuf_t nbuf,
unsigned long iova,
unsigned long pa,
const char *func,
uint32_t line)
{
uint32_t i;
unsigned long irq_flag;
QDF_NBUF_TRACK *p_node;
if (is_initial_mem_debug_disabled)
return;
i = qdf_net_buf_debug_hash(nbuf);
spin_lock_irqsave(&g_qdf_net_buf_track_lock[i], irq_flag);
p_node = qdf_net_buf_debug_look_up(nbuf);
if (p_node) {
qdf_str_lcopy(p_node->smmu_unmap_func_name, func,
QDF_MEM_FUNC_NAME_SIZE);
p_node->smmu_unmap_line_num = line;
p_node->is_nbuf_smmu_mapped = false;
p_node->smmu_unmap_iova_addr = iova;
p_node->smmu_unmap_pa_addr = pa;
}
spin_unlock_irqrestore(&g_qdf_net_buf_track_lock[i], irq_flag);
}
#endif
void qdf_net_buf_debug_update_unmap_node(qdf_nbuf_t net_buf, void qdf_net_buf_debug_update_unmap_node(qdf_nbuf_t net_buf,
const char *func_name, const char *func_name,
uint32_t line_num) uint32_t line_num)
@@ -3311,6 +3538,7 @@ void qdf_nbuf_free_debug(qdf_nbuf_t nbuf, const char *func, uint32_t line)
goto free_buf; goto free_buf;
/* Remove SKB from internal QDF tracking table */ /* Remove SKB from internal QDF tracking table */
qdf_nbuf_panic_on_free_if_smmu_mapped(nbuf, func, line);
qdf_nbuf_panic_on_free_if_mapped(nbuf, func, line); qdf_nbuf_panic_on_free_if_mapped(nbuf, func, line);
qdf_net_buf_debug_delete_node(nbuf); qdf_net_buf_debug_delete_node(nbuf);
qdf_nbuf_history_add(nbuf, func, line, QDF_NBUF_FREE); qdf_nbuf_history_add(nbuf, func, line, QDF_NBUF_FREE);
@@ -3334,6 +3562,8 @@ void qdf_nbuf_free_debug(qdf_nbuf_t nbuf, const char *func, uint32_t line)
ext_list = qdf_nbuf_get_ext_list(nbuf); ext_list = qdf_nbuf_get_ext_list(nbuf);
while (ext_list) { while (ext_list) {
if (qdf_nbuf_get_users(ext_list) == 1) { if (qdf_nbuf_get_users(ext_list) == 1) {
qdf_nbuf_panic_on_free_if_smmu_mapped(ext_list, func,
line);
qdf_nbuf_panic_on_free_if_mapped(ext_list, func, line); qdf_nbuf_panic_on_free_if_mapped(ext_list, func, line);
idx = 0; idx = 0;
num_nr_frags = qdf_nbuf_get_nr_frags(ext_list); num_nr_frags = qdf_nbuf_get_nr_frags(ext_list);