struct list_head done;
wait_queue_head_t wait;
pid_t pid;
+ atomic_t task_running;
} vpu_session;
/**
struct list_head running; /* link to link_reg in struct vpu_reg */
struct list_head done; /* link to link_reg in struct vpu_reg */
struct list_head session; /* link to list_session in struct vpu_session */
- atomic_t task_running;
+ atomic_t total_running;
bool enabled;
vpu_reg *reg_codec;
vpu_reg *reg_pproc;
clk_put(hclk_cpu_vcodec);
}
+static void vpu_reset(void)
+{
+ clk_disable(aclk_ddr_vepu);
+ cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, true);
+ cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, true);
+ cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, true);
+ cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, true);
+ mdelay(10);
+ cru_set_soft_reset(SOFT_RST_VCODEC_AXI_BUS, false);
+ cru_set_soft_reset(SOFT_RST_VCODEC_AHB_BUS, false);
+ cru_set_soft_reset(SOFT_RST_DDR_VCODEC_PORT, false);
+ cru_set_soft_reset(SOFT_RST_CPU_VODEC_A2A_AHB, false);
+ clk_enable(aclk_ddr_vepu);
+}
+
static void vpu_service_power_off(void)
{
if (!service.enabled)
service.enabled = false;
printk("vpu: power off\n");
- while(atomic_read(&service.task_running)) {
+ while(atomic_read(&service.total_running)) {
pr_alert("power off when task running!!\n");
udelay(10);
}
static void vpu_service_power_off_work_func(unsigned long data)
{
- printk("vpu: delayed power off work\n");
+ printk("delayed ");
vpu_service_power_off();
}
break;
}
}
+ atomic_sub(1, ®->session->task_running);
wake_up_interruptible_sync(®->session->wait);
spin_unlock(&service.lock);
}
{
int i;
u32 *src = (u32 *)®->reg[0];
- atomic_add(1, &service.task_running);
+ atomic_add(1, &service.total_running);
+ atomic_add(1, ®->session->task_running);
switch (reg->type) {
case VPU_ENC : {
u32 *dst = (u32 *)enc_dev.hwregs;
} break;
default : {
pr_err("unsupport session type %d", reg->type);
- atomic_sub(1, &service.task_running);
+ atomic_sub(1, &service.total_running);
+ atomic_sub(1, ®->session->task_running);
break;
}
}
case VPU_IOC_GET_REG : {
vpu_request req;
vpu_reg *reg;
+ unsigned long flag;
if (copy_from_user(&req, (void __user *)arg, sizeof(vpu_request))) {
pr_err("VPU_IOC_GET_REG copy_from_user failed\n");
return -EFAULT;
int ret = wait_event_interruptible_timeout(session->wait, !list_empty(&session->done), TIMEOUT_DELAY);
if (unlikely(ret < 0)) {
pr_err("pid %d wait task ret %d\n", session->pid, ret);
- return ret;
} else if (0 == ret) {
- pr_err("pid %d wait task done timeout\n", session->pid);
- return -ETIMEDOUT;
+ int task_running = atomic_read(&session->task_running);
+ pr_err("pid %d wait %d task done timeout\n", session->pid, task_running);
+ if (task_running) {
+ atomic_set(&session->task_running, 0);
+ atomic_sub(task_running, &service.total_running);
+ pr_err("%d task is running but not return, reset hardware...", task_running);
+ vpu_reset();
+ pr_err("done\n");
+ }
+ ret = -ETIMEDOUT;
+ }
+ if (ret < 0) {
+ vpu_reg *reg, *n;
+ spin_lock_irqsave(&service.lock, flag);
+ list_for_each_entry_safe(reg, n, &session->waiting, session_link) {
+ reg_deinit(reg);
+ }
+ list_for_each_entry_safe(reg, n, &session->running, session_link) {
+ reg_deinit(reg);
+ }
+ list_for_each_entry_safe(reg, n, &session->done, session_link) {
+ reg_deinit(reg);
+ }
+ spin_unlock_irqrestore(&service.lock, flag);
+ return ret;
}
}
- {
- unsigned long flag;
- spin_lock_irqsave(&service.lock, flag);
- reg = list_entry(session->done.next, vpu_reg, session_link);
- return_reg(reg, (u32 __user *)req.req);
- spin_unlock_irqrestore(&service.lock, flag);
- }
+ spin_lock_irqsave(&service.lock, flag);
+ reg = list_entry(session->done.next, vpu_reg, session_link);
+ return_reg(reg, (u32 __user *)req.req);
+ spin_unlock_irqrestore(&service.lock, flag);
break;
}
default : {
init_waitqueue_head(&session->wait);
/* no need to protect */
list_add_tail(&session->list_session, &service.session);
+ atomic_set(&session->task_running, 0);
filp->private_data = (void *)session;
pr_debug("dev opened\n");
static int vpu_service_release(struct inode *inode, struct file *filp)
{
unsigned long flag;
+ int task_running;
vpu_session *session = (vpu_session *)filp->private_data;
if (NULL == session)
return -EINVAL;
+ task_running = atomic_read(&session->task_running);
+ if (task_running) {
+ pr_err("vpu_service session %d still has %d task running when closing\n", session->pid, task_running);
+ msleep(50);
+ }
wake_up_interruptible_sync(&session->wait);
- msleep(50);
/* remove this filp from the asynchronusly notified filp's */
//vpu_service_fasync(-1, filp, 0);
list_del(&session->list_session);
/* clear dec IRQ */
writel(irq_status_dec & (~DEC_INTERRUPT_BIT), dev->hwregs + DEC_INTERRUPT_REGISTER);
pr_debug("DEC IRQ received!\n");
- atomic_sub(1, &service.task_running);
+ atomic_sub(1, &service.total_running);
if (NULL == service.reg_codec) {
pr_err("dec isr with no task waiting\n");
} else {
/* clear pp IRQ */
writel(irq_status_pp & (~DEC_INTERRUPT_BIT), dev->hwregs + PP_INTERRUPT_REGISTER);
pr_debug("PP IRQ received!\n");
- atomic_sub(1, &service.task_running);
+ atomic_sub(1, &service.total_running);
if (NULL == service.reg_pproc) {
pr_err("pp isr with no task waiting\n");
} else {
/* clear enc IRQ */
writel(irq_status & (~ENC_INTERRUPT_BIT), dev->hwregs + ENC_INTERRUPT_REGISTER);
pr_debug("ENC IRQ received!\n");
- atomic_sub(1, &service.task_running);
+ atomic_sub(1, &service.total_running);
if (NULL == service.reg_codec) {
pr_err("enc isr with no task waiting\n");
} else {
spin_lock_init(&service.lock);
service.reg_codec = NULL;
service.reg_pproc = NULL;
- atomic_set(&service.task_running, 0);
+ atomic_set(&service.total_running, 0);
service.enabled = false;
vpu_get_clk();