drm/rockchip: fix VOP vblank race
We have seen a case of a bad reference count for vblanks with the
Rockchip VOP:
------------[ cut here ]------------
WARNING: CPU: 1 PID: 383 at drivers/gpu/drm/drm_irq.c:1198 drm_vblank_put+0x40/0xcc
Modules linked in: brcmfmac brcmutil
CPU: 1 PID: 383 Comm: kworker/u8:2 Not tainted 4.9.75-rt60 #1
Hardware name: Rockchip (Device Tree)
Workqueue: events_unbound flip_worker
Backtrace:
[<
c010b7b0>] (dump_backtrace) from [<
c010ba4c>] (show_stack+0x18/0x1c)
r7:
c0b1b13c r6:
600b0013 r5:
00000000 r4:
c0b1b13c
[<
c010ba34>] (show_stack) from [<
c032d248>] (dump_stack+0x78/0x94)
[<
c032d1d0>] (dump_stack) from [<
c011e6e8>] (__warn+0xe4/0x104)
r7:
00000009 r6:
c03cf26c r5:
00000000 r4:
00000000
[<
c011e604>] (__warn) from [<
c011e7c0>] (warn_slowpath_null+0x28/0x30)
r9:
eeb443a0 r8:
eeb443c8 r7:
ee8a5ec0 r6:
ee8a5ec0 r5:
edb47f00 r4:
ee096200
[<
c011e798>] (warn_slowpath_null) from [<
c03cf26c>] (drm_vblank_put+0x40/0xcc)
[<
c03cf22c>] (drm_vblank_put) from [<
c03cf310>] (drm_crtc_vblank_put+0x18/0x1c)
r5:
edb47f00 r4:
ee3c8a80
[<
c03cf2f8>] (drm_crtc_vblank_put) from [<
c03ef9b4>] (vop_fb_unref_worker+0x18/0x24)
[<
c03ef99c>] (vop_fb_unref_worker) from [<
c03df194>] (flip_worker+0x98/0xb4)
r5:
edb47f00 r4:
eeb443a8
[<
c03df0fc>] (flip_worker) from [<
c0134808>] (process_one_work+0x1a8/0x2fc)
r9:
00000000 r8:
ee807d00 r7:
00000000 r6:
ee809c00 r5:
eeb443a8 r4:
edfe5f80
[<
c0134660>] (process_one_work) from [<
c01358ec>] (worker_thread+0x2ac/0x458)
r10:
00000088 r9:
edfe5f98 r8:
ee809c2c r7:
c0b04100 r6:
ee809c00 r5:
ee809c00
r4:
edfe5f80
[<
c0135640>] (worker_thread) from [<
c013a0bc>] (kthread+0xfc/0x10c)
r10:
00000000 r9:
00000000 r8:
c0135640 r7:
edfe5f80 r6:
00000000 r5:
edf0e240
r4:
ee8a4000 r3:
ed194e00
[<
c0139fc0>] (kthread) from [<
c0107cb8>] (ret_from_fork+0x14/0x3c)
r8:
00000000 r7:
00000000 r6:
00000000 r5:
c0139fc0 r4:
edf0e240
---[ end trace
0000000000000002 ]---
It seems that this is caused by unfortunate timing between
vop_crtc_atomic_flush() and vop_handle_vblank() given the following
ordering:
atomic_flush handle_vblank
------------ -------------
drm_flip_work_queue
set_bit
if (test_and_clear_bit(...))
drm_flip_work_commit
drm_vblank_get
This results in vop_fb_unref_worker (called as flip work) decrementing
the vblank refcount before it has been incremented.
Signed-off-by: John Keeping <john@metanate.com>
Reviewed-by: Sandy huang <hjc@rock-chips.com>
Signed-off-by: Sandy Huang <hjc@rock-chips.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20180328160351.23763-1-john@metanate.com