From: 黄涛 Date: Fri, 24 Aug 2012 09:19:18 +0000 (+0800) Subject: rga: fix deadlock issue between rga_power_on and rga_power_off_work X-Git-Tag: firefly_0821_release~8842 X-Git-Url: http://demsky.eecs.uci.edu/git/?a=commitdiff_plain;h=b618612b8852284f4c5b8a8be1c0c9afbf63c3b6;p=firefly-linux-kernel-4.4.55.git rga: fix deadlock issue between rga_power_on and rga_power_off_work Fix this deadlock by call mutex_trylock on rga_power_off_work: SurfaceFlinger D c086ec20 0 247 1 0x00000001 [] (__schedule+0x6d0/0x79c) from [] (schedule_timeout+0x1c/0x208) [] (schedule_timeout+0x1c/0x208) from [] (wait_for_common+0xdc/0x178) [] (wait_for_common+0xdc/0x178) from [] (wait_on_work+0xf0/0x158) [] (wait_on_work+0xf0/0x158) from [] (__cancel_work_timer+0xb8/0x104) [] (__cancel_work_timer+0xb8/0x104) from [] (rga_try_set_reg+0x38/0x270) [] (rga_try_set_reg+0x38/0x270) from [] (rga_blit+0x3b4/0x3fc) [] (rga_blit+0x3b4/0x3fc) from [] (rga_ioctl+0x154/0x374) [] (rga_ioctl+0x154/0x374) from [] (do_vfs_ioctl+0x500/0x57c) [] (do_vfs_ioctl+0x500/0x57c) from [] (sys_ioctl+0x34/0x54) [] (sys_ioctl+0x34/0x54) from [] (ret_fast_syscall+0x0/0x30) kworker/1:1 D c086ec20 0 7718 2 0x00000000 [] (__schedule+0x6d0/0x79c) from [] (__mutex_lock_slowpath+0x158/0x1d8) [] (__mutex_lock_slowpath+0x158/0x1d8) from [] (mutex_lock+0x20/0x38) [] (mutex_lock+0x20/0x38) from [] (rga_power_off_work+0x10/0x24) [] (rga_power_off_work+0x10/0x24) from [] (process_one_work+0x250/0x3ac) [] (process_one_work+0x250/0x3ac) from [] (worker_thread+0x228/0x3e8) [] (worker_thread+0x228/0x3e8) from [] (kthread+0x80/0x88) [] (kthread+0x80/0x88) from [] (kernel_thread_exit+0x0/0x8) Also do not call cancel_delayed_work_sync every time. --- diff --git a/drivers/video/rockchip/rga/rga_drv.c b/drivers/video/rockchip/rga/rga_drv.c index 6bf2399a59b8..555647126dff 100755 --- a/drivers/video/rockchip/rga/rga_drv.c +++ b/drivers/video/rockchip/rga/rga_drv.c @@ -210,11 +210,22 @@ static void rga_dump(void) } } +static inline void rga_queue_power_off_work(void) +{ + queue_delayed_work(system_nrt_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY); +} + /* Caller must hold rga_service.lock */ static void rga_power_on(void) { - cancel_delayed_work_sync(&drvdata->power_off_work); - queue_delayed_work(system_nrt_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY); + static ktime_t last; + ktime_t now = ktime_get(); + + if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) { + cancel_delayed_work_sync(&drvdata->power_off_work); + rga_queue_power_off_work(); + last = now; + } if (rga_service.enable) return; @@ -251,9 +262,13 @@ static void rga_power_off(void) static void rga_power_off_work(struct work_struct *work) { - mutex_lock(&rga_service.lock); - rga_power_off(); - mutex_unlock(&rga_service.lock); + if (mutex_trylock(&rga_service.lock)) { + rga_power_off(); + mutex_unlock(&rga_service.lock); + } else { + /* Come back later if the device is busy... */ + rga_queue_power_off_work(); + } } static int rga_flush(rga_session *session, unsigned long arg)