nt9856x/code/vos/drivers/source/kwrap/linux/rtos_os_spinlock.c
2023-03-28 15:07:53 +08:00

215 lines
7.0 KiB
C
Executable File

/*-----------------------------------------------------------------------------*/
/* Include Header Files */
/*-----------------------------------------------------------------------------*/
#include <linux/module.h>
#include <linux/spinlock.h>
#define __MODULE__ rtos_spinlock
#define __DBGLVL__ 8 // 0=FATAL, 1=ERR, 2=WRN, 3=UNIT, 4=FUNC, 5=IND, 6=MSG, 7=VALUE, 8=USER
#define __DBGFLT__ "*"
#include <kwrap/debug.h>
#include <kwrap/spinlock.h>
#define VOS_SPINLOCK_DEBUG 0 //0: disable, 1: enable
#define VOS_SPINLOCK_DEBUG_MAX_CORE 2
#define VOS_SPINLOCK_DEBUG_LIST_NUM 64
/*-----------------------------------------------------------------------------*/
/* Local Types Declarations */
/*-----------------------------------------------------------------------------*/
#define VOS_SPINLOCK_TAG_INITED MAKEFOURCC('V', 'S', 'P', 'N')
#ifndef sizeof_field
#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
#endif
STATIC_ASSERT(sizeof_field(vk_spinlock_t, buf) >= sizeof(spinlock_t));
/*-----------------------------------------------------------------------------*/
/* Local Global Variables */
/*-----------------------------------------------------------------------------*/
unsigned int rtos_spinlock_debug_level = NVT_DBG_WRN;
static DEFINE_SPINLOCK(vos_inter_lock);
module_param_named(rtos_spinlock_debug_level, rtos_spinlock_debug_level, int, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(rtos_spinlock_debug_level, "Debug message level");
#if VOS_SPINLOCK_DEBUG
typedef struct {
unsigned int next_idx;
unsigned long caller_ra[VOS_SPINLOCK_DEBUG_LIST_NUM];
} VOS_SPINLOCK_LIST;
static VOS_SPINLOCK_LIST g_vos_lock_list[VOS_SPINLOCK_DEBUG_MAX_CORE] = {0};
static VOS_SPINLOCK_LIST g_vos_unlock_list[VOS_SPINLOCK_DEBUG_MAX_CORE] = {0};
#endif
/*-----------------------------------------------------------------------------*/
/* Interface Functions */
/*-----------------------------------------------------------------------------*/
#if VOS_SPINLOCK_DEBUG
static inline void _vk_spin_add_lock_list(void)
{
unsigned long inter_flags = 0;
unsigned int cpu_id;
VOS_SPINLOCK_LIST *p_list;
static int print_once = 0;
spin_lock_irqsave(&vos_inter_lock, inter_flags);
if (!print_once) {
print_once = 1;
DBG_DUMP("[VOS_SPIN] max_core %d list_num %d\r\n", VOS_SPINLOCK_DEBUG_MAX_CORE, VOS_SPINLOCK_DEBUG_LIST_NUM);
for (cpu_id = 0; cpu_id < VOS_SPINLOCK_DEBUG_MAX_CORE; cpu_id++) {
DBG_DUMP("[VOS_SPIN] cpu%d loc next_idx = 0x%lX\r\n", cpu_id, (unsigned long)&g_vos_lock_list[cpu_id].next_idx);
DBG_DUMP("[VOS_SPIN] cpu%d loc caller_ra[0] = 0x%lX\r\n", cpu_id, (unsigned long)&g_vos_lock_list[cpu_id].caller_ra[0]);
DBG_DUMP("[VOS_SPIN] cpu%d unl next_idx = 0x%lX\r\n", cpu_id, (unsigned long)&g_vos_unlock_list[cpu_id].next_idx);
DBG_DUMP("[VOS_SPIN] cpu%d unl caller_ra[0] = 0x%lX\r\n", cpu_id, (unsigned long)&g_vos_unlock_list[cpu_id].caller_ra[0]);
}
}
cpu_id = smp_processor_id();
if (cpu_id > VOS_SPINLOCK_DEBUG_MAX_CORE - 1) {
DBG_ERR("Exceed max core 0x%x\r\n", VOS_SPINLOCK_DEBUG_MAX_CORE);
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
return;
}
p_list = &g_vos_lock_list[cpu_id];
p_list->caller_ra[p_list->next_idx] = (unsigned long)__builtin_return_address(0);
p_list->next_idx++;
if (p_list->next_idx >= VOS_SPINLOCK_DEBUG_LIST_NUM) {
p_list->next_idx = 0;
}
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
}
static inline void _vk_spin_add_unlock_list(void)
{
unsigned long inter_flags = 0;
unsigned int cpu_id;
VOS_SPINLOCK_LIST *p_list;
spin_lock_irqsave(&vos_inter_lock, inter_flags);
cpu_id = smp_processor_id();
if (cpu_id > VOS_SPINLOCK_DEBUG_MAX_CORE - 1) {
DBG_ERR("Exceed max core 0x%x\r\n", VOS_SPINLOCK_DEBUG_MAX_CORE);
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
return;
}
p_list = &g_vos_unlock_list[cpu_id];
p_list->caller_ra[p_list->next_idx] = (unsigned long)__builtin_return_address(0);
p_list->next_idx++;
if (p_list->next_idx >= VOS_SPINLOCK_DEBUG_LIST_NUM) {
p_list->next_idx = 0;
}
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
}
#endif //#if SPIN_LOCK_DEBUG
void vk_spin_dump_list(void)
{
#if !VOS_SPINLOCK_DEBUG
DBG_DUMP("VOS_SPINLOCK_DEBUG is disable\r\n");
return;
#else
unsigned long inter_flags = 0;
unsigned int cpu_id;
unsigned int list_idx;
spin_lock_irqsave(&vos_inter_lock, inter_flags);
for (cpu_id = 0; cpu_id < VOS_SPINLOCK_DEBUG_MAX_CORE; cpu_id++) {
DBG_DUMP("cpu%d loc next_idx 0x%X\r\n", cpu_id, g_vos_lock_list[cpu_id].next_idx);
for (list_idx = 0; list_idx < VOS_SPINLOCK_DEBUG_LIST_NUM; list_idx++) {
DBG_DUMP("cpu%d[%03d] loc_ra 0x%lX\r\n", cpu_id, list_idx,
g_vos_lock_list[cpu_id].caller_ra[list_idx]);
}
DBG_DUMP("cpu%d unl next_idx 0x%X\r\n", cpu_id, g_vos_unlock_list[cpu_id].next_idx);
for (list_idx = 0; list_idx < VOS_SPINLOCK_DEBUG_LIST_NUM; list_idx++) {
DBG_DUMP("cpu%d[%03d] unl_ra 0x%lX\r\n", cpu_id, list_idx,
g_vos_unlock_list[cpu_id].caller_ra[list_idx]);
}
}
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
#endif
}
EXPORT_SYMBOL(vk_spin_dump_list);
void vk_spin_lock_init(vk_spinlock_t *p_voslock)
{
unsigned long inter_flags = 0;
spinlock_t *p_spinlock = (spinlock_t *)p_voslock->buf;
spin_lock_irqsave(&vos_inter_lock, inter_flags);
//always init spinlock without checking init_tag to prevent dirty data
//coverity[side_effect_free]: spin_lock_init is kernel API, do not change
spin_lock_init(p_spinlock);
p_voslock->init_tag = VOS_SPINLOCK_TAG_INITED;
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
}
static void _vk_spin_lock_init_check_tag(vk_spinlock_t *p_voslock)
{
unsigned long inter_flags = 0;
spin_lock_irqsave(&vos_inter_lock, inter_flags);
//after inter lock, check the tag again to make sure not inited yet
if (VOS_SPINLOCK_TAG_INITED != p_voslock->init_tag) {
spinlock_t *p_spinlock = (spinlock_t *)p_voslock->buf;
// coverity[side_effect_free]: spin_lock_init is kernel API, do not change
spin_lock_init(p_spinlock);
p_voslock->init_tag = VOS_SPINLOCK_TAG_INITED;
}
spin_unlock_irqrestore(&vos_inter_lock, inter_flags);
}
unsigned long _vk_raw_spin_lock_irqsave(vk_spinlock_t *p_voslock)
{
spinlock_t *p_spinlock = (spinlock_t *)p_voslock->buf;
unsigned long flags = 0;
if (VOS_SPINLOCK_TAG_INITED != p_voslock->init_tag) {
_vk_spin_lock_init_check_tag(p_voslock);
}
#if VOS_SPINLOCK_DEBUG
_vk_spin_add_lock_list();
#endif
spin_lock_irqsave(p_spinlock, flags);
return flags;
}
void vk_spin_unlock_irqrestore(vk_spinlock_t *p_voslock, unsigned long flags)
{
spinlock_t *p_spinlock = (spinlock_t *)p_voslock->buf;
if (VOS_SPINLOCK_TAG_INITED != p_voslock->init_tag) {
DBG_ERR("lock not inited\r\n");
return;
}
#if VOS_SPINLOCK_DEBUG
_vk_spin_add_unlock_list();
#endif
spin_unlock_irqrestore(p_spinlock, flags);
}
EXPORT_SYMBOL(vk_spin_lock_init);
EXPORT_SYMBOL(_vk_raw_spin_lock_irqsave);
EXPORT_SYMBOL(vk_spin_unlock_irqrestore);