diff options
author | John Keeping <john@metanate.com> | 2016-03-11 17:21:17 +0000 |
---|---|---|
committer | Mark Yao <mark.yao@rock-chips.com> | 2016-03-28 14:48:29 +0800 |
commit | f135046e519dc54a701110fa93a6d61c4989ed96 (patch) | |
tree | bfd38bcc50a9aeeaa8f188e738c1a7642b5b447a /drivers/gpu/drm/rockchip/rockchip_drm_drv.c | |
parent | 92915da647be831ddbaa7e03e7528d921ec7f8aa (diff) | |
download | talos-obmc-linux-f135046e519dc54a701110fa93a6d61c4989ed96.tar.gz talos-obmc-linux-f135046e519dc54a701110fa93a6d61c4989ed96.zip |
drm/rockchip: cancel pending vblanks on close
When closing the DRM device while a vblank is pending, we access
file_priv after it has been free'd, which gives:
Unable to handle kernel NULL pointer dereference at virtual address 00000000
...
PC is at __list_add+0x5c/0xe8
LR is at send_vblank_event+0x54/0x1f0
...
[<c02952e8>] (__list_add) from [<c031a7b4>] (send_vblank_event+0x54/0x1f0)
[<c031a760>] (send_vblank_event) from [<c031a9c0>] (drm_send_vblank_event+0x70/0x78)
[<c031a950>] (drm_send_vblank_event) from [<c031a9f8>] (drm_crtc_send_vblank_event+0x30/0x34)
[<c031a9c8>] (drm_crtc_send_vblank_event) from [<c0339ad8>] (vop_isr+0x224/0x28c)
[<c03398b4>] (vop_isr) from [<c0081780>] (handle_irq_event_percpu+0x12c/0x3e4)
This can be triggered somewhat reliably with:
modetest -M rockchip -v -s ...
Add a preclose hook to the driver so that we can discard any pending
vblank events when the device is closed.
Signed-off-by: John Keeping <john@metanate.com>
Diffstat (limited to 'drivers/gpu/drm/rockchip/rockchip_drm_drv.c')
-rw-r--r-- | drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c index 896da09e49ee..f556a8f4fde6 100644 --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c @@ -251,6 +251,27 @@ static int rockchip_drm_unload(struct drm_device *drm_dev) return 0; } +static void rockchip_drm_crtc_cancel_pending_vblank(struct drm_crtc *crtc, + struct drm_file *file_priv) +{ + struct rockchip_drm_private *priv = crtc->dev->dev_private; + int pipe = drm_crtc_index(crtc); + + if (pipe < ROCKCHIP_MAX_CRTC && + priv->crtc_funcs[pipe] && + priv->crtc_funcs[pipe]->cancel_pending_vblank) + priv->crtc_funcs[pipe]->cancel_pending_vblank(crtc, file_priv); +} + +static void rockchip_drm_preclose(struct drm_device *dev, + struct drm_file *file_priv) +{ + struct drm_crtc *crtc; + + list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) + rockchip_drm_crtc_cancel_pending_vblank(crtc, file_priv); +} + void rockchip_drm_lastclose(struct drm_device *dev) { struct rockchip_drm_private *priv = dev->dev_private; @@ -281,6 +302,7 @@ static struct drm_driver rockchip_drm_driver = { DRIVER_PRIME | DRIVER_ATOMIC, .load = rockchip_drm_load, .unload = rockchip_drm_unload, + .preclose = rockchip_drm_preclose, .lastclose = rockchip_drm_lastclose, .get_vblank_counter = drm_vblank_no_hw_counter, .enable_vblank = rockchip_drm_crtc_enable_vblank, |