mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-25 02:09:42 +00:00
drm/exynos: fix kernel panic issue at drm releasing
This patch fixes a kernel panic issue which happened when drm driver is closed while modetest. This issue could be reproduced easily by launching modetest with page flip repeatedly. The reason is that invalid drm_file object could be accessed by send_vblank_event function when finishing page flip if the drm_file object was removed by drm_release and there was a pended page flip event which was already committed to hardware. So this patch makes the pended page flip event to be cancelled by preclose callback which is called at front of drm_release function. Changelog v2: - free vblank event objects belonging to the request process, increment event space and decrease pending_update when cancelling the event Signed-off-by: Inki Dae <inki.dae@samsung.com> Reviewed-by: Daniel Stone <daniels@collabora.com> Acked-by: Daniel Vetter <daniel@ffwll.ch>
This commit is contained in:
parent
d619894cf5
commit
c74d8eb564
3 changed files with 35 additions and 0 deletions
|
@ -226,3 +226,29 @@ void exynos_drm_crtc_te_handler(struct drm_crtc *crtc)
|
|||
if (exynos_crtc->ops->te_handler)
|
||||
exynos_crtc->ops->te_handler(exynos_crtc);
|
||||
}
|
||||
|
||||
void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct exynos_drm_crtc *exynos_crtc = to_exynos_crtc(crtc);
|
||||
struct drm_pending_vblank_event *e;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&crtc->dev->event_lock, flags);
|
||||
e = exynos_crtc->event;
|
||||
if (e && e->base.file_priv == file) {
|
||||
exynos_crtc->event = NULL;
|
||||
/*
|
||||
* event will be destroyed by core part
|
||||
* so below line should be removed later with core changes
|
||||
*/
|
||||
e->base.destroy(&e->base);
|
||||
/*
|
||||
* event_space will be increased by core part
|
||||
* so below line should be removed later with core changes.
|
||||
*/
|
||||
file->event_space += sizeof(e->event);
|
||||
atomic_dec(&exynos_crtc->pending_update);
|
||||
}
|
||||
spin_unlock_irqrestore(&crtc->dev->event_lock, flags);
|
||||
}
|
||||
|
|
|
@ -40,4 +40,8 @@ int exynos_drm_crtc_get_pipe_from_type(struct drm_device *drm_dev,
|
|||
*/
|
||||
void exynos_drm_crtc_te_handler(struct drm_crtc *crtc);
|
||||
|
||||
/* This function cancels a page flip request. */
|
||||
void exynos_drm_crtc_cancel_page_flip(struct drm_crtc *crtc,
|
||||
struct drm_file *file);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -330,7 +330,12 @@ static int exynos_drm_open(struct drm_device *dev, struct drm_file *file)
|
|||
static void exynos_drm_preclose(struct drm_device *dev,
|
||||
struct drm_file *file)
|
||||
{
|
||||
struct drm_crtc *crtc;
|
||||
|
||||
exynos_drm_subdrv_close(dev, file);
|
||||
|
||||
list_for_each_entry(crtc, &dev->mode_config.crtc_list, head)
|
||||
exynos_drm_crtc_cancel_page_flip(crtc, file);
|
||||
}
|
||||
|
||||
static void exynos_drm_postclose(struct drm_device *dev, struct drm_file *file)
|
||||
|
|
Loading…
Reference in a new issue