mirror of
https://github.com/revyos/thead-kernel.git
synced 2026-06-21 09:12:26 +02:00
vc8000e-kernel: fixup vcmdbuf release leak issue
This issue is reported in TLV-299. This commit fixed allocate_cmdbuf may infinite loop and leak of release the cmdbuf only reserved but not link_and_run. If cmdbuf not run done when release,do not firstly abort, instead wait done event reduce abort failed. Add cmdbuf id and line info for error log. Fixed busy count record idle twice in read module all regs issue. Signed-off-by: xianbing Zhu <xianbing.zhu@linux.alibaba.com> Change-Id: Ia006f8123e38022400959bed838ef76f7aef14a0 Signed-off-by: Han Gao <gaohan@iscas.ac.cn>
This commit is contained in:
@@ -634,7 +634,7 @@ struct cmdbuf_obj
|
||||
u16 cmdbuf_id; //used to manage CMDBUF in driver.It is a handle to identify cmdbuf.also is an interrupt vector.position in pool,same as status position.
|
||||
u8 cmdbuf_data_loaded; //0 means sw has not copied data into this CMDBUF; 1 means sw has copied data into this CMDBUF
|
||||
u8 cmdbuf_data_linked; //0 :not linked, 1:linked.into a vcmd core list.
|
||||
u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
|
||||
volatile u8 cmdbuf_run_done; //if 0,waiting for CMDBUF finish; if 1, op code in CMDBUF has finished one by one. HANTRO_VCMD_IOCH_WAIT_CMDBUF will check this variable.
|
||||
u8 cmdbuf_need_remove; // if 0, not need to remove CMDBUF; 1 CMDBUF can be removed if it is not the last CMDBUF;
|
||||
u8 has_end_cmdbuf; //if 1, the last opcode is end opCode.
|
||||
u8 no_normal_int_cmdbuf; //if 1, JMP will not send normal interrupt.
|
||||
@@ -930,8 +930,47 @@ static void free_cmdbuf_mem(u16 cmdbuf_id )
|
||||
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
cmdbuf_used[cmdbuf_id]=0;
|
||||
cmdbuf_used_residual +=1;
|
||||
PDEBUG(" ## real free cmdbuf[%d]\n",cmdbuf_id);
|
||||
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
|
||||
wake_up_all(&vcmd_cmdbuf_memory_wait);
|
||||
}
|
||||
|
||||
static void free_cmdbuf_not_linked_by_flip(struct file *filp)
|
||||
{
|
||||
unsigned long flags;
|
||||
int i;
|
||||
struct cmdbuf_obj* cmdbuf_obj;
|
||||
bi_list_node* new_cmdbuf_node;
|
||||
bool freed_flag = false;
|
||||
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
|
||||
for(i = 0; i < TOTAL_DISCRETE_CMDBUF_NUM; i++)
|
||||
{
|
||||
if(cmdbuf_used[i] && global_cmdbuf_node[i] != NULL)
|
||||
{
|
||||
new_cmdbuf_node = global_cmdbuf_node[i];
|
||||
if(new_cmdbuf_node == 0x55555555)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data;
|
||||
if(cmdbuf_obj->filp == filp && !cmdbuf_obj->cmdbuf_data_linked && !cmdbuf_obj->cmdbuf_run_done)
|
||||
{
|
||||
cmdbuf_used[i]=0;
|
||||
cmdbuf_used_residual +=1;
|
||||
global_cmdbuf_node[i] = NULL;
|
||||
freed_flag = true;
|
||||
PDEBUG(" ## Find left node not freed,real free cmdbuf[%d],remain %d\n",i,cmdbuf_used_residual);
|
||||
}
|
||||
}
|
||||
|
||||
if(cmdbuf_used_residual >= (TOTAL_DISCRETE_CMDBUF_NUM-2))
|
||||
break;
|
||||
|
||||
}
|
||||
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
if(freed_flag)
|
||||
wake_up_all(&vcmd_cmdbuf_memory_wait);
|
||||
}
|
||||
|
||||
static bi_list_node* create_cmdbuf_node(void)
|
||||
@@ -941,8 +980,13 @@ static bi_list_node* create_cmdbuf_node(void)
|
||||
struct noncache_mem new_cmdbuf_addr;
|
||||
struct noncache_mem new_status_cmdbuf_addr;
|
||||
|
||||
if(wait_event_interruptible(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr)) )
|
||||
if(!wait_event_interruptible_timeout(vcmd_cmdbuf_memory_wait, allocate_cmdbuf(&new_cmdbuf_addr,&new_status_cmdbuf_addr),
|
||||
msecs_to_jiffies(500)) )
|
||||
{
|
||||
pr_err("vc8000e: wait allocate_cmdbuf timeout\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
cmdbuf_obj = create_vcmd_cmdbuf_obj(new_cmdbuf_addr.cmdbuf_id);
|
||||
if(cmdbuf_obj==NULL)
|
||||
{
|
||||
@@ -1048,18 +1092,21 @@ static u32 calculate_executing_time_after_node_high_priority(bi_list_node* exe_c
|
||||
}
|
||||
return time_run_all;
|
||||
}
|
||||
|
||||
|
||||
#ifdef DEBUG_CMDBUF_ALLOC
|
||||
int cmdbuf_node_unexpected[TOTAL_DISCRETE_CMDBUF_NUM];
|
||||
#endif
|
||||
/**********************************************************************************************************\
|
||||
*cmdbuf pool management
|
||||
\***********************************************************************************************************/
|
||||
static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache_mem* new_status_cmdbuf_addr)
|
||||
{
|
||||
unsigned long flags;
|
||||
u16 cmdbuf_used_pos_start = cmdbuf_used_pos;
|
||||
spin_lock_irqsave(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
if(cmdbuf_used_residual==0)
|
||||
{
|
||||
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
pr_err("%s:vc8000e:no empty cmdbuf\n",__func__);
|
||||
//no empty cmdbuf
|
||||
return 0;
|
||||
}
|
||||
@@ -1080,6 +1127,7 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
|
||||
new_status_cmdbuf_addr->mmu_bus_address=vcmd_status_buf_mem_pool.mmu_bus_address + cmdbuf_used_pos*CMDBUF_MAX_SIZE;
|
||||
new_status_cmdbuf_addr->size=CMDBUF_MAX_SIZE;
|
||||
new_status_cmdbuf_addr->cmdbuf_id = cmdbuf_used_pos;
|
||||
global_cmdbuf_node[cmdbuf_used_pos]=0x55555555; //temp set it,for another thread not hit cmdbuf_used[x] set but global_cmdbuf_node[x] is null
|
||||
cmdbuf_used_pos++;
|
||||
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
|
||||
cmdbuf_used_pos=0;
|
||||
@@ -1088,11 +1136,30 @@ static int allocate_cmdbuf(struct noncache_mem* new_cmdbuf_addr,struct noncache
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG_CMDBUF_ALLOC
|
||||
if(cmdbuf_used[cmdbuf_used_pos]==0 && (global_cmdbuf_node[cmdbuf_used_pos]!=NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
|
||||
{
|
||||
pr_warn("vc8000e:unexpected cmdbuf_used[%d] is 0,but global_cmdbuf_node[%d] != NULL\n",
|
||||
cmdbuf_used_pos,cmdbuf_used_pos);
|
||||
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
|
||||
}
|
||||
else if(cmdbuf_used[cmdbuf_used_pos]!=0 && (global_cmdbuf_node[cmdbuf_used_pos] == NULL ) && (cmdbuf_node_unexpected[cmdbuf_used_pos] == 0x55))
|
||||
{
|
||||
pr_warn("vc8000e:unexpected cmdbuf_used[%d] != 0,but global_cmdbuf_node[%d] is NULL\n",
|
||||
cmdbuf_used_pos,cmdbuf_used_pos);
|
||||
cmdbuf_node_unexpected[cmdbuf_used_pos] = 0x55;
|
||||
}
|
||||
#endif
|
||||
cmdbuf_used_pos++;
|
||||
if(cmdbuf_used_pos>=TOTAL_DISCRETE_CMDBUF_NUM)
|
||||
cmdbuf_used_pos=0;
|
||||
|
||||
if(cmdbuf_used_pos_start == cmdbuf_used_pos) //searched all,not find one,should return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&vcmd_cmdbuf_alloc_lock, flags);
|
||||
pr_err("%s:vc8000e: no cmdbuf found,cmdbuf_used_residual %d\n",__func__,cmdbuf_used_residual);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1493,8 +1560,13 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa
|
||||
spin_lock_irqsave(&process_manager_obj->spinlock, flags);
|
||||
process_manager_obj->total_exe_time += input_para->executing_time;
|
||||
spin_unlock_irqrestore(&process_manager_obj->spinlock, flags);
|
||||
if(wait_event_interruptible(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj)))
|
||||
return -1;
|
||||
if(!wait_event_interruptible_timeout(process_manager_obj->wait_queue, wait_process_resource_rdy(process_manager_obj),
|
||||
msecs_to_jiffies(500) ))
|
||||
{
|
||||
pr_err("vc8000e: wait_process_resource_rdy timeout! total_exe_time %lld\n",process_manager_obj->total_exe_time);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
new_cmdbuf_node=create_cmdbuf_node();
|
||||
if(new_cmdbuf_node==NULL)
|
||||
@@ -1728,7 +1800,7 @@ static long link_and_run_cmdbuf(struct file *filp,struct exchange_parameter* inp
|
||||
|
||||
dev = &hantrovcmd_data[cmdbuf_obj->core_id];
|
||||
input_para->core_id = cmdbuf_obj->core_id;
|
||||
PDEBUG("Allocate cmd buffer [%d] to core [%d]\n", cmdbuf_id, input_para->core_id);
|
||||
PDEBUG("filp=%px, VCMD Link CMDBUF [%d] to core [%d]\n", (void *)filp, cmdbuf_id, input_para->core_id);
|
||||
//set ddr address for vcmd registers copy.
|
||||
if(dev->hw_version_id > HW_ID_1_0_C )
|
||||
{
|
||||
@@ -1937,7 +2009,7 @@ static unsigned int wait_cmdbuf_ready(struct file *filp,u16 cmdbuf_id,u32 *irq_s
|
||||
check_cmdbuf_irq(dev,cmdbuf_obj,irq_status_ret), msecs_to_jiffies(500) )
|
||||
)
|
||||
{
|
||||
pr_err("vcmd_wait_queue_0 timeout\n");
|
||||
pr_err("vc8000e:vcmd_wait_queue_0 timeout cmdbuf[%d]\n",cmdbuf_id);
|
||||
//abort the vcmd
|
||||
vcmd_write_register_value((const void *)dev->hwregs,dev->reg_mirror,HWIF_VCMD_START_TRIGGER,0);
|
||||
return -ETIME;
|
||||
@@ -1952,7 +2024,7 @@ bool hantrovcmd_devfreq_check_state(void)
|
||||
u32 state = 0;
|
||||
for (core_id = 0;core_id < total_vcmd_core_num; core_id++) {
|
||||
state = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE);
|
||||
if((state != 3) && (state != 0)) //HW state pend or idle
|
||||
if((state != 0) && (state != 3) ) //HW state pend or idle
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -2078,7 +2150,7 @@ static long hantrovcmd_ioctl(struct file *filp,
|
||||
ret = reserve_cmdbuf(filp,&input_para);
|
||||
if (ret == 0)
|
||||
copy_to_user((struct exchange_parameter*)arg,&input_para,sizeof(struct exchange_parameter));
|
||||
PDEBUG(" VCMD Reserve CMDBUF %d\n", input_para.cmdbuf_id);
|
||||
PDEBUG("filp=%px, VCMD Reserve CMDBUF [%d] remain %d \n", (void *)filp, input_para.cmdbuf_id,cmdbuf_used_residual);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -2088,7 +2160,7 @@ static long hantrovcmd_ioctl(struct file *filp,
|
||||
long retVal;
|
||||
copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter));
|
||||
|
||||
PDEBUG("VCMD link and run cmdbuf\n");
|
||||
PDEBUG("filp=%px,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id);
|
||||
pm_runtime_resume_and_get(dev);
|
||||
if (process_manager_obj)
|
||||
process_manager_obj->pm_count++;
|
||||
@@ -2107,10 +2179,11 @@ static long hantrovcmd_ioctl(struct file *filp,
|
||||
__get_user(cmdbuf_id, (u16*)arg);
|
||||
/*high 16 bits are core id, low 16 bits are cmdbuf_id*/
|
||||
|
||||
PDEBUG("VCMD wait for CMDBUF finishing. \n");
|
||||
PDEBUG("filp=%px,VCMD wait for CMDBUF finishing. %d,\n",filp,cmdbuf_id);
|
||||
|
||||
//TODO
|
||||
tmp = wait_cmdbuf_ready(filp,cmdbuf_id,&irq_status_ret);
|
||||
PDEBUG("filp=%px,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id);
|
||||
cmdbuf_id=(u16)irq_status_ret;
|
||||
if (tmp==0)
|
||||
{
|
||||
@@ -2130,13 +2203,12 @@ static long hantrovcmd_ioctl(struct file *filp,
|
||||
__get_user(cmdbuf_id, (u16*)arg);
|
||||
/*16 bits are cmdbuf_id*/
|
||||
|
||||
PDEBUG("VCMD release CMDBUF\n");
|
||||
|
||||
pm_runtime_mark_last_busy(dev);
|
||||
pm_runtime_put_autosuspend(dev);
|
||||
if (process_manager_obj)
|
||||
process_manager_obj->pm_count--;
|
||||
release_cmdbuf(filp,cmdbuf_id);
|
||||
PDEBUG("filp=%px,VCMD release CMDBUF ,%d,remain %d \n",filp,cmdbuf_id,cmdbuf_used_residual);
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
@@ -2388,7 +2460,7 @@ static int hantrovcmd_open(struct inode *inode, struct file *filp)
|
||||
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
|
||||
filp->private_data = process_manager_node->data;
|
||||
|
||||
PDEBUG("dev opened\n");
|
||||
PDEBUG("process node %px for filp opened %px\n", (void *)process_manager_node, (void *)filp);
|
||||
return result;
|
||||
}
|
||||
static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
@@ -2406,9 +2478,8 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
unsigned long flags;
|
||||
long retVal=0;
|
||||
|
||||
PDEBUG("dev closed for process %p\n", (void *)filp);
|
||||
if (down_interruptible(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]))
|
||||
return -ERESTARTSYS;
|
||||
PDEBUG("dev closed for process %px\n", (void *)filp);
|
||||
down(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]); //should be wait,do not use interruptible interface
|
||||
|
||||
for (core_id = 0;core_id < total_vcmd_core_num; core_id++)
|
||||
{
|
||||
@@ -2421,6 +2492,13 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
if(new_cmdbuf_node==NULL)
|
||||
break;
|
||||
cmdbuf_obj_temp=(struct cmdbuf_obj*)new_cmdbuf_node->data;
|
||||
if(cmdbuf_obj_temp->cmdbuf_id > 1)
|
||||
{
|
||||
PDEBUG("Process %px is releasing: checking cmdbuf %d (done %d,linked %d wstat %d) process %px. remain %d\n",
|
||||
filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->cmdbuf_run_done,cmdbuf_obj_temp->cmdbuf_data_linked,
|
||||
dev[core_id].working_state,
|
||||
cmdbuf_obj_temp->filp,cmdbuf_used_residual);
|
||||
}
|
||||
if (dev[core_id].hwregs && (cmdbuf_obj_temp->filp == filp))
|
||||
{
|
||||
if(cmdbuf_obj_temp->cmdbuf_run_done)
|
||||
@@ -2451,111 +2529,127 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
bi_list_node* done_cmdbuf_node = NULL;
|
||||
int abort_cmdbuf_id;
|
||||
int loop_count = 0;
|
||||
u32 irq_status_ret;
|
||||
|
||||
//abort the vcmd and wait
|
||||
PDEBUG("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
|
||||
#ifdef VCMD_DEBUG_INTERNAL
|
||||
printk_vcmd_register_debug((const void *)dev[core_id].hwregs, "Before trigger to 0");
|
||||
#endif
|
||||
// disable abort interrupt
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
|
||||
vcmd_aborted = 1;
|
||||
software_triger_abort = 1;
|
||||
#ifdef VCMD_DEBUG_INTERNAL
|
||||
printk_vcmd_register_debug((const void *)dev[core_id].hwregs,"After trigger to 0");
|
||||
#endif
|
||||
// wait vcmd core aborted and vcmd enters IDLE mode.
|
||||
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
|
||||
loop_count++;
|
||||
if (!(loop_count % 10)) {
|
||||
u32 irq_status = vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
|
||||
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
|
||||
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev[core_id].hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
|
||||
}
|
||||
mdelay(10); // wait 10ms
|
||||
if (loop_count > 100) { // too long
|
||||
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
|
||||
process_manager_obj = (struct process_manager_obj*)filp->private_data;
|
||||
if (process_manager_obj)
|
||||
{
|
||||
while(process_manager_obj->pm_count > 0)
|
||||
{
|
||||
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
|
||||
pm_runtime_put_autosuspend(&dev[0].pdev->dev);
|
||||
process_manager_obj->pm_count--;
|
||||
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
|
||||
if(wait_event_timeout(*dev[core_id].wait_queue,
|
||||
check_cmdbuf_irq(dev,cmdbuf_obj_temp,&irq_status_ret),msecs_to_jiffies(1000))
|
||||
)
|
||||
{
|
||||
spin_lock_irqsave(dev[core_id].spinlock, flags);
|
||||
PDEBUG(" ## wait got cmdbuf[%d] done %d \n",cmdbuf_obj_temp->cmdbuf_id,cmdbuf_obj_temp->cmdbuf_run_done);
|
||||
cmdbuf_obj_temp->cmdbuf_need_remove=1;
|
||||
retVal=release_cmdbuf_node(&dev[core_id].list_manager,new_cmdbuf_node);
|
||||
if(retVal==1)
|
||||
cmdbuf_obj_temp->process_manager_obj = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
//abort the vcmd and wait
|
||||
PDEBUG("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id);
|
||||
#ifdef VCMD_DEBUG_INTERNAL
|
||||
printk_vcmd_register_debug((const void *)dev[core_id].hwregs, "Before trigger to 0");
|
||||
#endif
|
||||
// disable abort interrupt
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0);
|
||||
vcmd_aborted = 1;
|
||||
software_triger_abort = 1;
|
||||
#ifdef VCMD_DEBUG_INTERNAL
|
||||
printk_vcmd_register_debug((const void *)dev[core_id].hwregs,"After trigger to 0");
|
||||
#endif
|
||||
// wait vcmd core aborted and vcmd enters IDLE mode.
|
||||
while (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_WORK_STATE)) {
|
||||
loop_count++;
|
||||
if (!(loop_count % 10)) {
|
||||
u32 irq_status = vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET);
|
||||
pr_err("hantrovcmd: expected idle state, but irq status = 0x%0x\n", irq_status);
|
||||
pr_err("hantrovcmd: vcmd current status is %d\n", vcmd_get_register_value((const void *)dev[core_id].hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE));
|
||||
}
|
||||
mdelay(10); // wait 10ms
|
||||
if (loop_count > 100) { // too long
|
||||
pr_err("hantrovcmd: too long before vcmd core to IDLE state\n");
|
||||
process_manager_obj = (struct process_manager_obj*)filp->private_data;
|
||||
if (process_manager_obj)
|
||||
{
|
||||
while(process_manager_obj->pm_count > 0)
|
||||
{
|
||||
pm_runtime_mark_last_busy(&dev[0].pdev->dev);
|
||||
pm_runtime_put_autosuspend(&dev[0].pdev->dev);
|
||||
process_manager_obj->pm_count--;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
|
||||
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(dev[core_id].spinlock, flags);
|
||||
up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]);
|
||||
return -ERESTARTSYS;
|
||||
}
|
||||
}
|
||||
dev[core_id].working_state = WORKING_STATE_IDLE;
|
||||
// clear interrupt & restore abort_e
|
||||
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
|
||||
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
|
||||
vcmd_write_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
|
||||
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
|
||||
}
|
||||
|
||||
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
|
||||
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
|
||||
dev[core_id].sw_cmdbuf_rdy_num = 0;
|
||||
dev[core_id].duration_without_int = 0;
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
|
||||
|
||||
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
|
||||
done_cmdbuf_node = dev[core_id].list_manager.head;
|
||||
while (done_cmdbuf_node) {
|
||||
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
|
||||
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
|
||||
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
|
||||
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
|
||||
}
|
||||
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
|
||||
break;
|
||||
done_cmdbuf_node = done_cmdbuf_node->next;
|
||||
}
|
||||
if (cmdbuf_obj_temp->cmdbuf_run_done) {
|
||||
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
|
||||
Just delink and remove it from the list. */
|
||||
if (done_cmdbuf_node && done_cmdbuf_node->data) {
|
||||
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
|
||||
}
|
||||
done_cmdbuf_node = done_cmdbuf_node->next;
|
||||
if (done_cmdbuf_node)
|
||||
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
|
||||
if (restart_cmdbuf) {
|
||||
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
|
||||
}
|
||||
} else {
|
||||
last_cmdbuf_node = new_cmdbuf_node;
|
||||
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
|
||||
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
|
||||
last_cmdbuf_node = new_cmdbuf_node->previous;
|
||||
|
||||
while (last_cmdbuf_node &&
|
||||
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
|
||||
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
|
||||
last_cmdbuf_node = last_cmdbuf_node->previous;
|
||||
dev[core_id].sw_cmdbuf_rdy_num++;
|
||||
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
|
||||
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
|
||||
dev[core_id].working_state = WORKING_STATE_IDLE;
|
||||
// clear interrupt & restore abort_e
|
||||
if (vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT)) {
|
||||
PDEBUG("Abort interrupt triggered, now clear it to avoid abort int...\n");
|
||||
vcmd_write_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4);
|
||||
PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev[core_id].hwregs, VCMD_REGISTER_INT_STATUS_OFFSET));
|
||||
}
|
||||
}
|
||||
if (restart_cmdbuf) {
|
||||
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
|
||||
}
|
||||
}
|
||||
|
||||
// remove first linked cmdbuf from list
|
||||
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
|
||||
abort_cmdbuf_id = vcmd_get_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_CMDBUF_EXECUTING_ID);
|
||||
PDEBUG("Abort when executing cmd buf %d.\n", abort_cmdbuf_id);
|
||||
dev[core_id].sw_cmdbuf_rdy_num = 0;
|
||||
dev[core_id].duration_without_int = 0;
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_EXE_CMDBUF_COUNT,0);
|
||||
vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_RDY_CMDBUF_COUNT,0);
|
||||
|
||||
/* Mark cmdbuf_run_done to 1 for all the cmd buf executed. */
|
||||
done_cmdbuf_node = dev[core_id].list_manager.head;
|
||||
while (done_cmdbuf_node) {
|
||||
if (!((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done) {
|
||||
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_run_done = 1;
|
||||
((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_data_linked = 0;
|
||||
PDEBUG("Set cmdbuf [%d] cmdbuf_run_done to 1.\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
|
||||
}
|
||||
if (((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id == abort_cmdbuf_id)
|
||||
break;
|
||||
done_cmdbuf_node = done_cmdbuf_node->next;
|
||||
}
|
||||
if (cmdbuf_obj_temp->cmdbuf_run_done) {
|
||||
/* current cmdbuf is in fact has been executed, but due to interrupt is not triggered, the status is not updated.
|
||||
Just delink and remove it from the list. */
|
||||
if (done_cmdbuf_node && done_cmdbuf_node->data) {
|
||||
PDEBUG("done_cmdbuf_node is cmdbuf [%d].\n", ((struct cmdbuf_obj*)done_cmdbuf_node->data)->cmdbuf_id);
|
||||
}
|
||||
done_cmdbuf_node = done_cmdbuf_node->next;
|
||||
if (done_cmdbuf_node)
|
||||
restart_cmdbuf = (struct cmdbuf_obj*)done_cmdbuf_node->data;
|
||||
if (restart_cmdbuf) {
|
||||
PDEBUG("Set restart cmdbuf [%d] via if.\n", restart_cmdbuf->cmdbuf_id);
|
||||
}
|
||||
} else {
|
||||
last_cmdbuf_node = new_cmdbuf_node;
|
||||
/* cmd buf num from aborted cmd buf to current cmdbuf_obj_temp */
|
||||
if (cmdbuf_obj_temp->cmdbuf_id != abort_cmdbuf_id) {
|
||||
last_cmdbuf_node = new_cmdbuf_node->previous;
|
||||
|
||||
while (last_cmdbuf_node &&
|
||||
((struct cmdbuf_obj*)last_cmdbuf_node->data)->cmdbuf_id != abort_cmdbuf_id) {
|
||||
restart_cmdbuf = (struct cmdbuf_obj*)last_cmdbuf_node->data;
|
||||
last_cmdbuf_node = last_cmdbuf_node->previous;
|
||||
dev[core_id].sw_cmdbuf_rdy_num++;
|
||||
dev[core_id].duration_without_int += restart_cmdbuf->executing_time;
|
||||
PDEBUG("Keep valid cmdbuf [%d] in the list.\n", restart_cmdbuf->cmdbuf_id);
|
||||
}
|
||||
}
|
||||
if (restart_cmdbuf) {
|
||||
PDEBUG("Set restart cmdbuf [%d] via else.\n", restart_cmdbuf->cmdbuf_id);
|
||||
}
|
||||
}
|
||||
|
||||
// remove first linked cmdbuf from list
|
||||
vcmd_delink_rm_cmdbuf(&dev[core_id], new_cmdbuf_node);
|
||||
}
|
||||
|
||||
}
|
||||
software_triger_abort = 0;
|
||||
release_cmdbuf_num++;
|
||||
PDEBUG("release reserved cmdbuf\n");
|
||||
PDEBUG("vc8000e : release reserved cmdbuf,remain %d\n",cmdbuf_used_residual);
|
||||
}
|
||||
else if (vcmd_aborted && !cmdbuf_obj_temp->cmdbuf_run_done) {
|
||||
/* VCMD is aborted, need to re-calculate the duration_without_int */
|
||||
@@ -2618,7 +2712,12 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
wake_up_all(dev[core_id].wait_queue);
|
||||
}
|
||||
if(release_cmdbuf_num)
|
||||
wake_up_interruptible_all(&vcmd_cmdbuf_memory_wait);
|
||||
wake_up_all(&vcmd_cmdbuf_memory_wait);
|
||||
|
||||
// free reserved but unlinkd node
|
||||
// Here is powerfull free all this process reserved/linked cmdbuf
|
||||
free_cmdbuf_not_linked_by_flip(filp);
|
||||
|
||||
spin_lock_irqsave(&vcmd_process_manager_lock, flags);
|
||||
process_manager_node = global_process_manager.head;
|
||||
while(1)
|
||||
@@ -2640,6 +2739,7 @@ static int __hantrovcmd_release(struct inode *inode, struct file *filp)
|
||||
}
|
||||
}
|
||||
//remove node from list
|
||||
PDEBUG("process node %px for filp to be removed: %px remain %d\n", (void *)process_manager_node, (void *)process_manager_obj->filp,cmdbuf_used_residual);
|
||||
bi_list_remove_node(&global_process_manager,process_manager_node);
|
||||
spin_unlock_irqrestore(&vcmd_process_manager_lock, flags);
|
||||
free_process_manager_node(process_manager_node);
|
||||
@@ -2790,7 +2890,7 @@ static u32 ConfigAXIFE(u32 mode)
|
||||
#endif
|
||||
if (axife_hwregs[i][0] != NULL)
|
||||
{
|
||||
PDEBUG("ConfigAXIFE: axife_hwregs[%d][0]=%p\n", i, axife_hwregs[i][0]);
|
||||
PDEBUG("ConfigAXIFE: axife_hwregs[%d][0]=%px\n", i, axife_hwregs[i][0]);
|
||||
AXIFEEnable(axife_hwregs[i][0], mode);
|
||||
}
|
||||
}
|
||||
@@ -2810,7 +2910,7 @@ static u32 ConfigAXIFE(u32 mode)
|
||||
#endif
|
||||
if (axife_hwregs[i][1] != NULL)
|
||||
{
|
||||
PDEBUG("ConfigAXIFE: axife_hwregs[%d][1]=%p\n", i, axife_hwregs[i][1]);
|
||||
PDEBUG("ConfigAXIFE: axife_hwregs[%d][1]=%px\n", i, axife_hwregs[i][1]);
|
||||
AXIFEEnable(axife_hwregs[i][1] , mode);
|
||||
}
|
||||
}
|
||||
@@ -2858,7 +2958,7 @@ static u32 ConfigMMU(void)
|
||||
}
|
||||
else
|
||||
pr_info("MMU detected!\n");
|
||||
PDEBUG("mmu_hwregs[%d][0]=%p\n", i, mmu_hwregs[i][0]);
|
||||
PDEBUG("mmu_hwregs[%d][0]=%px\n", i, mmu_hwregs[i][0]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2876,7 +2976,7 @@ static u32 ConfigMMU(void)
|
||||
mmu_hwregs[i][1] = (volatile u8*)ioremap(vcmd_core_array[i].vcmd_base_addr
|
||||
+vcmd_core_array[i].submodule_MMU_addr[1], MMU_SIZE);
|
||||
#endif
|
||||
PDEBUG("mmu_hwregs[%d][1]=%p\n", i, mmu_hwregs[i][1]);
|
||||
PDEBUG("mmu_hwregs[%d][1]=%px\n", i, mmu_hwregs[i][1]);
|
||||
}
|
||||
}
|
||||
mmu_status = MMUEnable(mmu_hwregs);
|
||||
@@ -3492,7 +3592,8 @@ static void read_main_module_all_registers(u32 main_module_type)
|
||||
//msleep(1000);
|
||||
hantrovcmd_isr(input_para.core_id, &hantrovcmd_data[input_para.core_id]);
|
||||
wait_cmdbuf_ready(NULL,input_para.cmdbuf_id,&irq_status_ret);
|
||||
encoder_devfreq_record_idle( encoder_get_devfreq_priv_data() );
|
||||
|
||||
pr_info("%s:record_idle:busy_count = %d\n",__func__,encoder_get_devfreq_priv_data()->busy_count);
|
||||
status_base_virt_addr=vcmd_status_buf_mem_pool.virtualAddress + input_para.cmdbuf_id*CMDBUF_MAX_SIZE/4+(vcmd_manager[input_para.module_type][0]->vcmd_core_cfg.submodule_main_addr/2/4+0);
|
||||
pr_info("vc8000_vcmd_driver: main module register 0:0x%x\n",*status_base_virt_addr);
|
||||
pr_info("vc8000_vcmd_driver: main module register 80:0x%x\n",*(status_base_virt_addr+80));
|
||||
@@ -3869,7 +3970,7 @@ void encoder_devfreq_record_busy(struct encoder_devfreq *devfreq)
|
||||
encoder_dev_clk_lock();
|
||||
spin_lock_irqsave(&devfreq->lock, irqflags);
|
||||
busy_count = devfreq->busy_count;
|
||||
//pr_info("record_busy:busy_count = %d\n",busy_count);
|
||||
PDEBUG("record_busy:busy_count = %d\n",busy_count);
|
||||
if(devfreq->busy_count > 0)
|
||||
{
|
||||
devfreq->busy_count++;
|
||||
@@ -3898,7 +3999,7 @@ void encoder_devfreq_record_idle(struct encoder_devfreq *devfreq)
|
||||
return;
|
||||
|
||||
spin_lock_irqsave(&devfreq->lock, irqflags);
|
||||
//pr_info("record_idle:busy_count = %d\n",devfreq->busy_count);
|
||||
PDEBUG("record_idle:busy_count = %d\n",devfreq->busy_count);
|
||||
if(devfreq->busy_count > 1)
|
||||
{
|
||||
devfreq->busy_count--;
|
||||
@@ -4102,7 +4203,7 @@ int encoder_devfreq_init(struct device *dev)
|
||||
int ret = 0;
|
||||
struct encoder_devfreq *devfreq = encoder_get_devfreq_priv_data();
|
||||
|
||||
memset(devfreq,sizeof(struct encoder_devfreq),0);
|
||||
memset(devfreq,0,sizeof(struct encoder_devfreq));
|
||||
spin_lock_init(&devfreq->lock);
|
||||
init_waitqueue_head(&devfreq->target_freq_wait_queue);
|
||||
mutex_init(&devfreq->clk_mutex);
|
||||
@@ -4486,6 +4587,7 @@ int __init hantroenc_vcmd_probe(struct platform_device *pdev)
|
||||
cmdbuf_used_pos=1;
|
||||
cmdbuf_used[0]=1;
|
||||
cmdbuf_used_residual -=1;
|
||||
pr_info(" CMDBUF[0] reserved,remain %d\n",cmdbuf_used_residual);
|
||||
|
||||
pr_info("vc8000_vcmd_driver: module inserted. Major <%d>\n", hantrovcmd_major);
|
||||
|
||||
@@ -4699,7 +4801,7 @@ static int vcmd_reserve_IO(void)
|
||||
|
||||
/*read hwid and check validness and store it*/
|
||||
hwid = (u32)ioread32(( void *)hantrovcmd_data[i].hwregs);
|
||||
pr_info("vcmd_reserve_IO: hantrovcmd_data[%d].hwregs=0x%p\n",i, hantrovcmd_data[i].hwregs);
|
||||
pr_info("vcmd_reserve_IO: hantrovcmd_data[%d].hwregs=0x%px\n",i, hantrovcmd_data[i].hwregs);
|
||||
pr_info("hwid=0x%08x\n", hwid);
|
||||
hantrovcmd_data[i].hw_version_id = hwid;
|
||||
|
||||
@@ -4879,7 +4981,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
||||
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
||||
if(new_cmdbuf_node==NULL)
|
||||
{
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
|
||||
spin_unlock_irqrestore(dev->spinlock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -4951,7 +5053,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
||||
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
||||
if(new_cmdbuf_node==NULL)
|
||||
{
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
|
||||
spin_unlock_irqrestore(dev->spinlock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -5023,7 +5125,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
||||
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
||||
if(new_cmdbuf_node==NULL)
|
||||
{
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
|
||||
spin_unlock_irqrestore(dev->spinlock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -5163,7 +5265,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
||||
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
||||
if(new_cmdbuf_node==NULL)
|
||||
{
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
|
||||
spin_unlock_irqrestore(dev->spinlock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
@@ -5233,7 +5335,7 @@ static irqreturn_t hantrovcmd_isr(int irq, void *dev_id)
|
||||
new_cmdbuf_node = global_cmdbuf_node[cmdbuf_id];
|
||||
if(new_cmdbuf_node==NULL)
|
||||
{
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id !!\n");
|
||||
pr_err("hantrovcmd_isr error cmdbuf_id %d line %d!!\n",cmdbuf_id,__LINE__);
|
||||
spin_unlock_irqrestore(dev->spinlock, flags);
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user