Skip to content

Commit

Permalink
drm/tegra: dc: Select root window for event dispatch
Browse files Browse the repository at this point in the history
In finish pageflip, the driver was not selecting the root window when
dispatching events. This exposed a race where a plane update would
change the window selection and cause tegra_dc_finish_page_flip to check
the wrong base address.

This patch also protects access to the window selection register as well
as the registers affected by it.

Signed-off-by: Sean Paul <seanpaul@chromium.org>
Signed-off-by: Thierry Reding <treding@nvidia.com>
  • Loading branch information
Sean Paul authored and Thierry Reding committed Dec 17, 2014
1 parent 73c42c7 commit 93396d0
Showing 1 changed file with 22 additions and 2 deletions.
24 changes: 22 additions & 2 deletions drivers/gpu/drm/tegra/dc.c
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
const struct tegra_dc_window *window)
{
unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
unsigned long value;
unsigned long value, flags;
bool yuv, planar;

/*
Expand All @@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
else
bpp = planar ? 1 : 2;

spin_lock_irqsave(&dc->lock, flags);

value = WINDOW_A_SELECT << index;
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);

Expand Down Expand Up @@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,

case TEGRA_BO_TILING_MODE_BLOCK:
DRM_ERROR("hardware doesn't support block linear mode\n");
spin_unlock_irqrestore(&dc->lock, flags);
return -EINVAL;
}

Expand Down Expand Up @@ -331,18 +334,23 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,

tegra_dc_window_commit(dc, index);

spin_unlock_irqrestore(&dc->lock, flags);

return 0;
}

static int tegra_window_plane_disable(struct drm_plane *plane)
{
struct tegra_dc *dc = to_tegra_dc(plane->crtc);
struct tegra_plane *p = to_tegra_plane(plane);
unsigned long flags;
u32 value;

if (!plane->crtc)
return 0;

spin_lock_irqsave(&dc->lock, flags);

value = WINDOW_A_SELECT << p->index;
tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);

Expand All @@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane)

tegra_dc_window_commit(dc, p->index);

spin_unlock_irqrestore(&dc->lock, flags);

return 0;
}

Expand Down Expand Up @@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
unsigned int h_offset = 0, v_offset = 0;
struct tegra_bo_tiling tiling;
unsigned long value, flags;
unsigned int format, swap;
unsigned long value;
int err;

err = tegra_fb_get_tiling(fb, &tiling);
if (err < 0)
return err;

spin_lock_irqsave(&dc->lock, flags);

tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);

value = fb->offsets[0] + y * fb->pitches[0] +
Expand Down Expand Up @@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,

case TEGRA_BO_TILING_MODE_BLOCK:
DRM_ERROR("hardware doesn't support block linear mode\n");
spin_unlock_irqrestore(&dc->lock, flags);
return -EINVAL;
}

Expand All @@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);

spin_unlock_irqrestore(&dc->lock, flags);

return 0;
}

Expand Down Expand Up @@ -823,11 +838,16 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)

bo = tegra_fb_get_plane(crtc->primary->fb, 0);

spin_lock_irqsave(&dc->lock, flags);

/* check if new start address has been latched */
tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);

spin_unlock_irqrestore(&dc->lock, flags);

if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
drm_crtc_send_vblank_event(crtc, dc->event);
drm_crtc_vblank_put(crtc);
Expand Down

0 comments on commit 93396d0

Please sign in to comment.