aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSean Paul <seanpaul@chromium.org>2014-11-19 13:04:49 -0500
committerThierry Reding <treding@nvidia.com>2014-12-17 08:27:39 -0500
commit93396d0f9c027654eb09151d2e22fe78a39feedb (patch)
tree7604f2eda411a260f1be1522b6051591d2d42943
parent73c42c79767a03ae64d11457e3ce80e80e09e514 (diff)
drm/tegra: dc: Select root window for event dispatch
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>
-rw-r--r--drivers/gpu/drm/tegra/dc.c24
1 files changed, 22 insertions, 2 deletions
diff --git a/drivers/gpu/drm/tegra/dc.c b/drivers/gpu/drm/tegra/dc.c
index ef36f9d5e35e..978993fa3a36 100644
--- a/drivers/gpu/drm/tegra/dc.c
+++ b/drivers/gpu/drm/tegra/dc.c
@@ -168,7 +168,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
168 const struct tegra_dc_window *window) 168 const struct tegra_dc_window *window)
169{ 169{
170 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp; 170 unsigned h_offset, v_offset, h_size, v_size, h_dda, v_dda, bpp;
171 unsigned long value; 171 unsigned long value, flags;
172 bool yuv, planar; 172 bool yuv, planar;
173 173
174 /* 174 /*
@@ -181,6 +181,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
181 else 181 else
182 bpp = planar ? 1 : 2; 182 bpp = planar ? 1 : 2;
183 183
184 spin_lock_irqsave(&dc->lock, flags);
185
184 value = WINDOW_A_SELECT << index; 186 value = WINDOW_A_SELECT << index;
185 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); 187 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
186 188
@@ -273,6 +275,7 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
273 275
274 case TEGRA_BO_TILING_MODE_BLOCK: 276 case TEGRA_BO_TILING_MODE_BLOCK:
275 DRM_ERROR("hardware doesn't support block linear mode\n"); 277 DRM_ERROR("hardware doesn't support block linear mode\n");
278 spin_unlock_irqrestore(&dc->lock, flags);
276 return -EINVAL; 279 return -EINVAL;
277 } 280 }
278 281
@@ -331,6 +334,8 @@ static int tegra_dc_setup_window(struct tegra_dc *dc, unsigned int index,
331 334
332 tegra_dc_window_commit(dc, index); 335 tegra_dc_window_commit(dc, index);
333 336
337 spin_unlock_irqrestore(&dc->lock, flags);
338
334 return 0; 339 return 0;
335} 340}
336 341
@@ -338,11 +343,14 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
338{ 343{
339 struct tegra_dc *dc = to_tegra_dc(plane->crtc); 344 struct tegra_dc *dc = to_tegra_dc(plane->crtc);
340 struct tegra_plane *p = to_tegra_plane(plane); 345 struct tegra_plane *p = to_tegra_plane(plane);
346 unsigned long flags;
341 u32 value; 347 u32 value;
342 348
343 if (!plane->crtc) 349 if (!plane->crtc)
344 return 0; 350 return 0;
345 351
352 spin_lock_irqsave(&dc->lock, flags);
353
346 value = WINDOW_A_SELECT << p->index; 354 value = WINDOW_A_SELECT << p->index;
347 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER); 355 tegra_dc_writel(dc, value, DC_CMD_DISPLAY_WINDOW_HEADER);
348 356
@@ -352,6 +360,8 @@ static int tegra_window_plane_disable(struct drm_plane *plane)
352 360
353 tegra_dc_window_commit(dc, p->index); 361 tegra_dc_window_commit(dc, p->index);
354 362
363 spin_unlock_irqrestore(&dc->lock, flags);
364
355 return 0; 365 return 0;
356} 366}
357 367
@@ -699,14 +709,16 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
699 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0); 709 struct tegra_bo *bo = tegra_fb_get_plane(fb, 0);
700 unsigned int h_offset = 0, v_offset = 0; 710 unsigned int h_offset = 0, v_offset = 0;
701 struct tegra_bo_tiling tiling; 711 struct tegra_bo_tiling tiling;
712 unsigned long value, flags;
702 unsigned int format, swap; 713 unsigned int format, swap;
703 unsigned long value;
704 int err; 714 int err;
705 715
706 err = tegra_fb_get_tiling(fb, &tiling); 716 err = tegra_fb_get_tiling(fb, &tiling);
707 if (err < 0) 717 if (err < 0)
708 return err; 718 return err;
709 719
720 spin_lock_irqsave(&dc->lock, flags);
721
710 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER); 722 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
711 723
712 value = fb->offsets[0] + y * fb->pitches[0] + 724 value = fb->offsets[0] + y * fb->pitches[0] +
@@ -752,6 +764,7 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
752 764
753 case TEGRA_BO_TILING_MODE_BLOCK: 765 case TEGRA_BO_TILING_MODE_BLOCK:
754 DRM_ERROR("hardware doesn't support block linear mode\n"); 766 DRM_ERROR("hardware doesn't support block linear mode\n");
767 spin_unlock_irqrestore(&dc->lock, flags);
755 return -EINVAL; 768 return -EINVAL;
756 } 769 }
757 770
@@ -778,6 +791,8 @@ static int tegra_dc_set_base(struct tegra_dc *dc, int x, int y,
778 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL); 791 tegra_dc_writel(dc, value << 8, DC_CMD_STATE_CONTROL);
779 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL); 792 tegra_dc_writel(dc, value, DC_CMD_STATE_CONTROL);
780 793
794 spin_unlock_irqrestore(&dc->lock, flags);
795
781 return 0; 796 return 0;
782} 797}
783 798
@@ -823,11 +838,16 @@ static void tegra_dc_finish_page_flip(struct tegra_dc *dc)
823 838
824 bo = tegra_fb_get_plane(crtc->primary->fb, 0); 839 bo = tegra_fb_get_plane(crtc->primary->fb, 0);
825 840
841 spin_lock_irqsave(&dc->lock, flags);
842
826 /* check if new start address has been latched */ 843 /* check if new start address has been latched */
844 tegra_dc_writel(dc, WINDOW_A_SELECT, DC_CMD_DISPLAY_WINDOW_HEADER);
827 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS); 845 tegra_dc_writel(dc, READ_MUX, DC_CMD_STATE_ACCESS);
828 base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR); 846 base = tegra_dc_readl(dc, DC_WINBUF_START_ADDR);
829 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS); 847 tegra_dc_writel(dc, 0, DC_CMD_STATE_ACCESS);
830 848
849 spin_unlock_irqrestore(&dc->lock, flags);
850
831 if (base == bo->paddr + crtc->primary->fb->offsets[0]) { 851 if (base == bo->paddr + crtc->primary->fb->offsets[0]) {
832 drm_crtc_send_vblank_event(crtc, dc->event); 852 drm_crtc_send_vblank_event(crtc, dc->event);
833 drm_crtc_vblank_put(crtc); 853 drm_crtc_vblank_put(crtc);