rga: fix deadlock issue between rga_power_on and rga_power_off_work
author黄涛 <huangtao@rock-chips.com>
Fri, 24 Aug 2012 09:19:18 +0000 (17:19 +0800)
committer黄涛 <huangtao@rock-chips.com>
Fri, 24 Aug 2012 09:27:46 +0000 (17:27 +0800)
Fix this deadlock by call mutex_trylock on rga_power_off_work:

SurfaceFlinger  D c086ec20     0   247      1 0x00000001
[<c086ec20>] (__schedule+0x6d0/0x79c) from [<c086f110>] (schedule_timeout+0x1c/0x208)
[<c086f110>] (schedule_timeout+0x1c/0x208) from [<c086e36c>] (wait_for_common+0xdc/0x178)
[<c086e36c>] (wait_for_common+0xdc/0x178) from [<c04773b8>] (wait_on_work+0xf0/0x158)
[<c04773b8>] (wait_on_work+0xf0/0x158) from [<c0477d30>] (__cancel_work_timer+0xb8/0x104)
[<c0477d30>] (__cancel_work_timer+0xb8/0x104) from [<c05ca548>] (rga_try_set_reg+0x38/0x270)
[<c05ca548>] (rga_try_set_reg+0x38/0x270) from [<c05cafc4>] (rga_blit+0x3b4/0x3fc)
[<c05cafc4>] (rga_blit+0x3b4/0x3fc) from [<c05cb29c>] (rga_ioctl+0x154/0x374)
[<c05cb29c>] (rga_ioctl+0x154/0x374) from [<c04e3480>] (do_vfs_ioctl+0x500/0x57c)
[<c04e3480>] (do_vfs_ioctl+0x500/0x57c) from [<c04e3530>] (sys_ioctl+0x34/0x54)
[<c04e3530>] (sys_ioctl+0x34/0x54) from [<c0435c80>] (ret_fast_syscall+0x0/0x30)
kworker/1:1     D c086ec20     0  7718      2 0x00000000
[<c086ec20>] (__schedule+0x6d0/0x79c) from [<c086f784>] (__mutex_lock_slowpath+0x158/0x1d8)
[<c086f784>] (__mutex_lock_slowpath+0x158/0x1d8) from [<c086f824>] (mutex_lock+0x20/0x38)
[<c086f824>] (mutex_lock+0x20/0x38) from [<c05ca920>] (rga_power_off_work+0x10/0x24)
[<c05ca920>] (rga_power_off_work+0x10/0x24) from [<c0475d74>] (process_one_work+0x250/0x3ac)
[<c0475d74>] (process_one_work+0x250/0x3ac) from [<c04762b4>] (worker_thread+0x228/0x3e8)
[<c04762b4>] (worker_thread+0x228/0x3e8) from [<c047bc18>] (kthread+0x80/0x88)
[<c047bc18>] (kthread+0x80/0x88) from [<c0436678>] (kernel_thread_exit+0x0/0x8)

Also do not call cancel_delayed_work_sync every time.

drivers/video/rockchip/rga/rga_drv.c

index 6bf2399a59b82a29b8e770b83038e700bfb84bfa..555647126dff8eaf6b67eef520003f4e19b0ae23 100755 (executable)
@@ -210,11 +210,22 @@ static void rga_dump(void)
        }\r
 }\r
 \r
+static inline void rga_queue_power_off_work(void)\r
+{\r
+       queue_delayed_work(system_nrt_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY);\r
+}\r
+\r
 /* Caller must hold rga_service.lock */\r
 static void rga_power_on(void)\r
 {\r
-       cancel_delayed_work_sync(&drvdata->power_off_work);\r
-       queue_delayed_work(system_nrt_wq, &drvdata->power_off_work, RGA_POWER_OFF_DELAY);\r
+       static ktime_t last;\r
+       ktime_t now = ktime_get();\r
+\r
+       if (ktime_to_ns(ktime_sub(now, last)) > NSEC_PER_SEC) {\r
+               cancel_delayed_work_sync(&drvdata->power_off_work);\r
+               rga_queue_power_off_work();\r
+               last = now;\r
+       }\r
        if (rga_service.enable)\r
                return;\r
 \r
@@ -251,9 +262,13 @@ static void rga_power_off(void)
 \r
 static void rga_power_off_work(struct work_struct *work)\r
 {\r
-       mutex_lock(&rga_service.lock);\r
-       rga_power_off();\r
-       mutex_unlock(&rga_service.lock);\r
+       if (mutex_trylock(&rga_service.lock)) {\r
+               rga_power_off();\r
+               mutex_unlock(&rga_service.lock);\r
+       } else {\r
+               /* Come back later if the device is busy... */\r
+               rga_queue_power_off_work();\r
+       }\r
 }\r
 \r
 static int rga_flush(rga_session *session, unsigned long arg)\r