215 lines
7.0 KiB
C
Executable File
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);
|