aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJyri Sarha <jsarha@ti.com>2016-10-25 05:27:31 -0400
committerJyri Sarha <jsarha@ti.com>2016-11-29 14:03:20 -0500
commit2d53a18098e5a03a30b1b1419ab4103357b69f0d (patch)
tree0f06ec73b1cdb5bf4f2e6bcde30fd59d0b1c403f
parent9e79e062dc9b3aed541d6e47ac178aff815ab0e8 (diff)
drm/tilcdc: Fix race from forced shutdown of crtc in unload
Fix race from forced shutdown of crtc in unload by adding internal locking and a boolean telling if device is going to be shutdown. Signed-off-by: Jyri Sarha <jsarha@ti.com>
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_crtc.c29
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.c2
-rw-r--r--drivers/gpu/drm/tilcdc/tilcdc_drv.h3
3 files changed, 26 insertions, 8 deletions
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
index 62773633ef5a..0d09acce4916 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_crtc.c
@@ -33,7 +33,9 @@ struct tilcdc_crtc {
33 struct drm_plane primary; 33 struct drm_plane primary;
34 const struct tilcdc_panel_info *info; 34 const struct tilcdc_panel_info *info;
35 struct drm_pending_vblank_event *event; 35 struct drm_pending_vblank_event *event;
36 struct mutex enable_lock;
36 bool enabled; 37 bool enabled;
38 bool shutdown;
37 wait_queue_head_t frame_done_wq; 39 wait_queue_head_t frame_done_wq;
38 bool frame_done; 40 bool frame_done;
39 spinlock_t irq_lock; 41 spinlock_t irq_lock;
@@ -158,9 +160,11 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
158 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); 160 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
159 161
160 WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 162 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
161 163 mutex_lock(&tilcdc_crtc->enable_lock);
162 if (tilcdc_crtc->enabled) 164 if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) {
165 mutex_unlock(&tilcdc_crtc->enable_lock);
163 return; 166 return;
167 }
164 168
165 pm_runtime_get_sync(dev->dev); 169 pm_runtime_get_sync(dev->dev);
166 170
@@ -175,17 +179,22 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
175 drm_crtc_vblank_on(crtc); 179 drm_crtc_vblank_on(crtc);
176 180
177 tilcdc_crtc->enabled = true; 181 tilcdc_crtc->enabled = true;
182 mutex_unlock(&tilcdc_crtc->enable_lock);
178} 183}
179 184
180void tilcdc_crtc_off(struct drm_crtc *crtc) 185static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
181{ 186{
182 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc); 187 struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
183 struct drm_device *dev = crtc->dev; 188 struct drm_device *dev = crtc->dev;
184 struct tilcdc_drm_private *priv = dev->dev_private; 189 struct tilcdc_drm_private *priv = dev->dev_private;
185 190
186 if (!tilcdc_crtc->enabled) 191 mutex_lock(&tilcdc_crtc->enable_lock);
192 if (shutdown)
193 tilcdc_crtc->shutdown = true;
194 if (!tilcdc_crtc->enabled) {
195 mutex_unlock(&tilcdc_crtc->enable_lock);
187 return; 196 return;
188 197 }
189 tilcdc_crtc->frame_done = false; 198 tilcdc_crtc->frame_done = false;
190 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE); 199 tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);
191 200
@@ -224,12 +233,18 @@ void tilcdc_crtc_off(struct drm_crtc *crtc)
224 tilcdc_crtc->last_vblank = ktime_set(0, 0); 233 tilcdc_crtc->last_vblank = ktime_set(0, 0);
225 234
226 tilcdc_crtc->enabled = false; 235 tilcdc_crtc->enabled = false;
236 mutex_unlock(&tilcdc_crtc->enable_lock);
227} 237}
228 238
229static void tilcdc_crtc_disable(struct drm_crtc *crtc) 239static void tilcdc_crtc_disable(struct drm_crtc *crtc)
230{ 240{
231 WARN_ON(!drm_modeset_is_locked(&crtc->mutex)); 241 WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
232 tilcdc_crtc_off(crtc); 242 tilcdc_crtc_off(crtc, false);
243}
244
245void tilcdc_crtc_shutdown(struct drm_crtc *crtc)
246{
247 tilcdc_crtc_off(crtc, true);
233} 248}
234 249
235static bool tilcdc_crtc_is_on(struct drm_crtc *crtc) 250static bool tilcdc_crtc_is_on(struct drm_crtc *crtc)
@@ -857,6 +872,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
857 if (ret < 0) 872 if (ret < 0)
858 goto fail; 873 goto fail;
859 874
875 mutex_init(&tilcdc_crtc->enable_lock);
876
860 init_waitqueue_head(&tilcdc_crtc->frame_done_wq); 877 init_waitqueue_head(&tilcdc_crtc->frame_done_wq);
861 878
862 drm_flip_work_init(&tilcdc_crtc->unref_work, 879 drm_flip_work_init(&tilcdc_crtc->unref_work,
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.c b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
index 48757f1a1a59..3d2cea090d6f 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.c
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.c
@@ -197,7 +197,7 @@ static void tilcdc_fini(struct drm_device *dev)
197 struct tilcdc_drm_private *priv = dev->dev_private; 197 struct tilcdc_drm_private *priv = dev->dev_private;
198 198
199 if (priv->crtc) 199 if (priv->crtc)
200 tilcdc_crtc_off(priv->crtc); 200 tilcdc_crtc_shutdown(priv->crtc);
201 201
202 if (priv->is_registered) 202 if (priv->is_registered)
203 drm_dev_unregister(dev); 203 drm_dev_unregister(dev);
diff --git a/drivers/gpu/drm/tilcdc/tilcdc_drv.h b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
index 7db23f27e9fb..d31fe5d8ab9d 100644
--- a/drivers/gpu/drm/tilcdc/tilcdc_drv.h
+++ b/drivers/gpu/drm/tilcdc/tilcdc_drv.h
@@ -33,6 +33,7 @@
33#include <drm/drm_crtc_helper.h> 33#include <drm/drm_crtc_helper.h>
34#include <drm/drm_gem_cma_helper.h> 34#include <drm/drm_gem_cma_helper.h>
35#include <drm/drm_fb_cma_helper.h> 35#include <drm/drm_fb_cma_helper.h>
36#include <drm/drm_bridge.h>
36 37
37/* Defaulting to pixel clock defined on AM335x */ 38/* Defaulting to pixel clock defined on AM335x */
38#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000 39#define TILCDC_DEFAULT_MAX_PIXELCLOCK 126000
@@ -173,7 +174,7 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
173 bool simulate_vesa_sync); 174 bool simulate_vesa_sync);
174int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); 175int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode);
175int tilcdc_crtc_max_width(struct drm_crtc *crtc); 176int tilcdc_crtc_max_width(struct drm_crtc *crtc);
176void tilcdc_crtc_off(struct drm_crtc *crtc); 177void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
177int tilcdc_crtc_update_fb(struct drm_crtc *crtc, 178int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
178 struct drm_framebuffer *fb, 179 struct drm_framebuffer *fb,
179 struct drm_pending_vblank_event *event); 180 struct drm_pending_vblank_event *event);