Commit 64d77564 authored by Mark yao's avatar Mark yao Committed by Mark Yao

drm/rockchip: vop: fix iommu page fault when resume

Iommu would get page fault with following path:
   vop_disable:
      1, disable all windows and set vop config done
      2, vop enter to standy, all windows not works, but their registers
         are not clean, when you read window's enable bit, may found the
         window is enable.

   vop_enable:
      1, memcpy(vop->regsbak, vop->regs, len)
         save current vop registers to vop->regsbak, then you can found
         window is enable on regsbak.
      2, VOP_WIN_SET(vop, win, gate, 1);
         force enable window gate, but gate and enable are on same
         hardware register, then window enable bit rewrite to vop hardware.
      3, vop power on, and vop might try to scan destroyed buffer,
         then iommu get page fault.

Move windows disable after vop regsbak restore, then vop regsbak mechanism
would keep tracing the modify, everything would be safe.
Signed-off-by: default avatarMark Yao <mark.yao@rock-chips.com>
Reviewed-by: default avatarSandy huang <sandy.huang@rock-chips.com>
Link: https://patchwork.freedesktop.org/patch/msgid/1501494582-6934-1-git-send-email-mark.yao@rock-chips.com
parent b5015e92
...@@ -495,7 +495,7 @@ static void vop_line_flag_irq_disable(struct vop *vop) ...@@ -495,7 +495,7 @@ static void vop_line_flag_irq_disable(struct vop *vop)
static int vop_enable(struct drm_crtc *crtc) static int vop_enable(struct drm_crtc *crtc)
{ {
struct vop *vop = to_vop(crtc); struct vop *vop = to_vop(crtc);
int ret; int ret, i;
ret = pm_runtime_get_sync(vop->dev); ret = pm_runtime_get_sync(vop->dev);
if (ret < 0) { if (ret < 0) {
...@@ -528,6 +528,20 @@ static int vop_enable(struct drm_crtc *crtc) ...@@ -528,6 +528,20 @@ static int vop_enable(struct drm_crtc *crtc)
} }
memcpy(vop->regs, vop->regsbak, vop->len); memcpy(vop->regs, vop->regsbak, vop->len);
/*
* We need to make sure that all windows are disabled before we
* enable the crtc. Otherwise we might try to scan from a destroyed
* buffer later.
*/
for (i = 0; i < vop->data->win_size; i++) {
struct vop_win *vop_win = &vop->win[i];
const struct vop_win_data *win = vop_win->data;
spin_lock(&vop->reg_lock);
VOP_WIN_SET(vop, win, enable, 0);
spin_unlock(&vop->reg_lock);
}
vop_cfg_done(vop); vop_cfg_done(vop);
/* /*
...@@ -562,28 +576,11 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc, ...@@ -562,28 +576,11 @@ static void vop_crtc_atomic_disable(struct drm_crtc *crtc,
struct drm_crtc_state *old_state) struct drm_crtc_state *old_state)
{ {
struct vop *vop = to_vop(crtc); struct vop *vop = to_vop(crtc);
int i;
WARN_ON(vop->event); WARN_ON(vop->event);
rockchip_drm_psr_deactivate(&vop->crtc); rockchip_drm_psr_deactivate(&vop->crtc);
/*
* We need to make sure that all windows are disabled before we
* disable that crtc. Otherwise we might try to scan from a destroyed
* buffer later.
*/
for (i = 0; i < vop->data->win_size; i++) {
struct vop_win *vop_win = &vop->win[i];
const struct vop_win_data *win = vop_win->data;
spin_lock(&vop->reg_lock);
VOP_WIN_SET(vop, win, enable, 0);
spin_unlock(&vop->reg_lock);
}
vop_cfg_done(vop);
drm_crtc_vblank_off(crtc); drm_crtc_vblank_off(crtc);
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment