From 9ee78c8b5135bfba6cc052708bfe95c8658d924f Mon Sep 17 00:00:00 2001 From: Han Gao Date: Sat, 20 Jul 2024 15:32:15 +0800 Subject: [PATCH] vc8000d-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 Change-Id: Ieb0b751d18a1ed65fe198e3d75a6953dabf15ef8 Signed-off-by: Han Gao --- .../linux/subsys_driver/hantro_dec.c | 6 +- .../linux/subsys_driver/hantro_mmu.c | 4 +- .../linux/subsys_driver/hantro_vcmd.c | 347 ++++++++++++------ 3 files changed, 231 insertions(+), 126 deletions(-) diff --git a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_dec.c b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_dec.c index c775cc517..1047be9c6 100644 --- a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_dec.c +++ b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_dec.c @@ -2348,7 +2348,7 @@ void decoder_devfreq_record_busy(struct decoder_devfreq *devfreq) decoder_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++; @@ -2376,7 +2376,7 @@ void decoder_devfreq_record_idle(struct decoder_devfreq *devfreq) if (!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--; @@ -2581,7 +2581,7 @@ int decoder_devfreq_init(struct device *dev) int ret = 0; struct decoder_devfreq *devfreq = decoder_get_devfreq_priv_data(); - memset(devfreq,sizeof(struct decoder_devfreq),0); + memset(devfreq,0,sizeof(struct decoder_devfreq)); spin_lock_init(&devfreq->lock); init_waitqueue_head(&devfreq->target_freq_wait_queue); mutex_init(&devfreq->clk_mutex); diff --git a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_mmu.c b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_mmu.c index 54b4752da..2b89c9607 100644 --- a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_mmu.c +++ b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_mmu.c @@ -1425,7 +1425,7 @@ static enum MMUStatus MMUMemNodeMap(struct addr_desc *addr, struct file *filp) { page_count = (addr->size - 1)/PAGE_SIZE + 1; GetPhysicalAddress(addr->virtual_address, &address); - MMUDEBUG(" *****MMU map address*****%x\n", address); + MMUDEBUG(" *****MMU map address*****%llx phys_to_virt %lx\n", address,(unsigned long)phys_to_virt(address)); if(address >= REGION_IN_START && address + addr->size < REGION_IN_END) e = MMU_REGION_IN; @@ -1505,7 +1505,7 @@ static enum MMUStatus MMUMemNodeMap(struct addr_desc *addr, struct file *filp) { MMUDEBUG(" MMU_MTLB_SHIFT %d MMU_STLB_4K_SHIFT %d\n", MMU_MTLB_SHIFT, MMU_STLB_4K_SHIFT); MMUDEBUG(" MMUMemNodeMap map total %d pages in region %d\nMTLB/STLB starts %d/%d, MTLB/STLB ends %d/%d\n", page_count, (u32)e, p->mtlb_start, p->stlb_start, p->mtlb_end, p->stlb_end); - MMUDEBUG(" MMUMemNodeMap map %p -> 0x%08x\n", addr->virtual_address, addr->bus_address); + MMUDEBUG(" MMUMemNodeMap map %px -> 0x%08x\n", addr->virtual_address, addr->bus_address); ReleaseMutex(g_mmu->page_table_mutex); diff --git a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_vcmd.c b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_vcmd.c index fef38f269..123896a9f 100644 --- a/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_vcmd.c +++ b/drivers/staging/media/vpu-vc8000d-kernel/linux/subsys_driver/hantro_vcmd.c @@ -580,6 +580,7 @@ struct process_manager_obj u64 total_exe_time; spinlock_t spinlock; u32 pm_count; + wait_queue_head_t wait_queue; } ; @@ -602,7 +603,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. - 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; u32 waited; // if 0, the cmd buf hasn't been waited, otherwise, has been waited. u8 has_end_cmdbuf; //if 1, the last opcode is end opCode. @@ -896,8 +897,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) @@ -907,8 +947,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("wait allocate_cmdbuf timeout\n"); return NULL; + } + #ifdef DYNAMIC_MALLOC_VCMDNODE cmdbuf_obj=create_cmdbuf_obj(); #else @@ -1028,18 +1073,21 @@ static u64 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:no empty cmdbuf\n",__func__); //no empty cmdbuf return 0; } @@ -1060,6 +1108,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; @@ -1068,11 +1117,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("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("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: no cmdbuf found,cmdbuf_used_residual %d\n",__func__,cmdbuf_used_residual); return 0; } @@ -1113,7 +1181,9 @@ static int select_vcmd(bi_list_node* new_cmdbuf_node) size_t exe_cmdbuf_addr=0; struct cmdbuf_obj* cmdbuf_obj_temp=NULL; u32 cmdbuf_id=0; + struct process_manager_obj* process_manager_temp; cmdbuf_obj=(struct cmdbuf_obj*)new_cmdbuf_node->data; + //there is an empty vcmd to be used while(1) { @@ -1446,7 +1516,7 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa { return -1; } - PDEBUG("reserve cmdbuf filp %p\n", (void *)filp); + PDEBUG("reserve cmdbuf filp %px\n", (void *)filp); spin_lock_irqsave(&vcmd_process_manager_lock, flags); process_manager_node = global_process_manager.head; while(1) @@ -1459,7 +1529,7 @@ static long reserve_cmdbuf(struct file *filp,struct exchange_parameter* input_pa return -1; } process_manager_obj = (struct process_manager_obj*)process_manager_node->data; - PDEBUG("reserve loop: node %p, filp %p\n", (void *)process_manager_node, + PDEBUG("reserve loop: node %px, filp %px\n", (void *)process_manager_node, (void *)process_manager_obj->filp); if (filp == process_manager_obj->filp) break; @@ -1470,13 +1540,19 @@ 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("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) return -1; + cmdbuf_obj = (struct cmdbuf_obj* )new_cmdbuf_node->data; cmdbuf_obj->module_type = input_para->module_type; cmdbuf_obj->priority = input_para->priority; @@ -1559,6 +1635,7 @@ static long release_cmdbuf(struct file *filp,u16 cmdbuf_id) up(&vcmd_reserve_cmdbuf_sem[module_type]); return 0; } + static long release_cmdbuf_node(bi_list* list,bi_list_node*cmdbuf_node) { bi_list_node* new_cmdbuf_node=NULL; @@ -1710,7 +1787,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("filp=%p, VCMD Link CMDBUF [%d] to core [%d]\n", (void *)filp, 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 ) { @@ -1953,11 +2030,11 @@ 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"); + pr_err("vcmd_wait_queue_0 timeout cmdbuf[%d]\n",cmdbuf_id); return -ETIME; } - PDEBUG("filp=%p, VCMD Wait CMDBUF [%d]\n", (void *)filp, cmdbuf_id); + PDEBUG("filp=%px, VCMD Wait CMDBUF [%d]\n", (void *)filp, cmdbuf_id); return 0; } else { if (check_mc_cmdbuf_irq(filp, cmdbuf_obj, irq_status_ret)) @@ -2096,7 +2173,7 @@ 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("filp=%p, VCMD Reserve CMDBUF [%d]\n", (void *)filp, 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; } @@ -2106,7 +2183,7 @@ long hantrovcmd_ioctl(struct file *filp, long retVal; copy_from_user(&input_para,(struct exchange_parameter*)arg,sizeof(struct exchange_parameter)); - PDEBUG("filp=%p,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id); + PDEBUG("filp=%px,VCMD link and run cmdbuf,[%d] \n",(void *)filp, input_para.cmdbuf_id); if (process_manager_obj) process_manager_obj->pm_count++; @@ -2126,11 +2203,11 @@ 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("filp=%p,VCMD wait for CMDBUF finishing. %d,\n",filp,cmdbuf_id); + 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=%p,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id); + PDEBUG("filp=%px,VCMD wait for CMDBUF finished. %d,\n",filp,cmdbuf_id); cmdbuf_id=(u16)irq_status_ret; if (tmp==0) { @@ -2151,11 +2228,11 @@ long hantrovcmd_ioctl(struct file *filp, __get_user(cmdbuf_id, (u16*)arg); /*16 bits are cmdbuf_id*/ - PDEBUG("filp=%p,VCMD release CMDBUF ,%d\n",filp,cmdbuf_id); 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; } @@ -2403,7 +2480,7 @@ int hantrovcmd_open(struct inode *inode, struct file *filp) filp->private_data = process_manager_node->data; PDEBUG("dev opened\n"); - PDEBUG("process node %p for filp opened %p\n", (void *)process_manager_node, (void *)filp); + PDEBUG("process node %px for filp opened %px\n", (void *)process_manager_node, (void *)filp); return result; } @@ -2422,7 +2499,7 @@ int hantrovcmd_release(struct inode *inode, struct file *filp) unsigned long flags; long retVal=0; - PDEBUG("dev closed for process %p via hantrovcmd_release\n", (void *)filp); + PDEBUG("dev closed for process %px via hantrovcmd_release\n", (void *)filp); down(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]); for (core_id = 0;core_id < total_vcmd_core_num; core_id++) @@ -2436,8 +2513,13 @@ 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; - PDEBUG("Process %p is releasing: checking cmdbuf %d of process %p.\n", - filp, cmdbuf_obj_temp->cmdbuf_id, cmdbuf_obj_temp->filp); + 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) @@ -2473,105 +2555,122 @@ int hantrovcmd_release(struct inode *inode, struct file *filp) bi_list_node* done_cmdbuf_node = NULL; int abort_cmdbuf_id; int loop_count = 0; - - //abort the vcmd and wait - pr_info("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id); - printk_vcmd_register_debug((const void *)dev->hwregs, "Before trigger to 0"); - // disable abort interrupt - //vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,0); - vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0); - vcmd_aborted = 1; - - printk_vcmd_register_debug((const void *)dev->hwregs,"After trigger to 0"); - // Wait vcmd core aborted and vcmd enters IDLE mode. - //while (dev[core_id].working_state != WORKING_STATE_IDLE) { - 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->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->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"); - - - spin_unlock_irqrestore(dev[core_id].spinlock, flags); - pm_runtime_mark_last_busy(&dev[0].pdev->dev); - pm_runtime_put_sync_suspend(&dev[0].pdev->dev); - up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]); - return -ERESTARTSYS; - } + u32 irq_status_ret; + + 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; } - 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->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4); - PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET)); - } - //printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd status to IDLE"); + else + { + spin_lock_irqsave(dev[core_id].spinlock, flags); + //abort the vcmd and wait + pr_info("Abort due to linked cmdbuf %d of current process.\n", cmdbuf_obj_temp->cmdbuf_id); + printk_vcmd_register_debug((const void *)dev->hwregs, "Before trigger to 0"); + // disable abort interrupt + //vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_IRQ_ABORT_EN,0); + vcmd_write_register_value((const void *)dev[core_id].hwregs,dev[core_id].reg_mirror,HWIF_VCMD_START_TRIGGER,0); + vcmd_aborted = 1; - 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); + printk_vcmd_register_debug((const void *)dev->hwregs,"After trigger to 0"); + // Wait vcmd core aborted and vcmd enters IDLE mode. + //while (dev[core_id].working_state != WORKING_STATE_IDLE) { + 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->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->hwregs, dev[core_id].reg_mirror, HWIF_VCMD_WORK_STATE)); + } + mdelay(50); // wait 10ms + if (loop_count > 100) { // too long + pr_err("hantrovcmd: too long before vcmd core to IDLE state\n"); - /* 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); - } - if (done_cmdbuf_node) { - 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); + spin_unlock_irqrestore(dev[core_id].spinlock, flags); + pm_runtime_mark_last_busy(&dev[0].pdev->dev); + pm_runtime_put_sync_suspend(&dev[0].pdev->dev); + up(&vcmd_reserve_cmdbuf_sem[dev->vcmd_core_cfg.sub_module_type]); + return -ERESTARTSYS; + } } - } - if (restart_cmdbuf) { - PDEBUG("Set restart cmdbuf [%d] via else.\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->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET, 0x1<<4); + PDEBUG("Now irq status = 0x%0x.\n", vcmd_read_reg((const void *)dev->hwregs, VCMD_REGISTER_INT_STATUS_OFFSET)); + } + //printk_vcmd_register_debug((const void *)dev->hwregs, "vcmd status to IDLE"); - // 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); + } + if (done_cmdbuf_node) { + 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); + } } release_cmdbuf_num++; - PDEBUG("release reserved cmdbuf\n"); + PDEBUG("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 */ if (!restart_cmdbuf) @@ -2630,7 +2729,12 @@ int hantrovcmd_release(struct inode *inode, struct file *filp) } 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) @@ -2642,10 +2746,10 @@ int hantrovcmd_release(struct inode *inode, struct file *filp) break; process_manager_node = process_manager_node->next; } - + //remove node from list - PDEBUG("process node %p for filp to be removed: %p\n", (void *)process_manager_node, (void *)process_manager_obj->filp); + 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); @@ -3140,7 +3244,7 @@ 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); - decoder_devfreq_record_idle( decoder_get_devfreq_priv_data() ); + pr_info("%s:record_idle:busy_count = %d\n",__func__,decoder_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 50:0x%08x\n",*(status_base_virt_addr+50)); @@ -3293,6 +3397,7 @@ int hantrovcmd_init(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); create_kernel_process_manager(); for(i=0;ispinlock, flags); return IRQ_HANDLED; } @@ -3681,7 +3786,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; } @@ -3754,7 +3859,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; } @@ -3823,7 +3928,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; } @@ -3896,7 +4001,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; } @@ -3967,7 +4072,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; }