diff options
author | Jyri Sarha <jsarha@ti.com> | 2016-10-25 05:27:31 -0400 |
---|---|---|
committer | Jyri Sarha <jsarha@ti.com> | 2016-11-29 14:03:20 -0500 |
commit | 2d53a18098e5a03a30b1b1419ab4103357b69f0d (patch) | |
tree | 0f06ec73b1cdb5bf4f2e6bcde30fd59d0b1c403f | |
parent | 9e79e062dc9b3aed541d6e47ac178aff815ab0e8 (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.c | 29 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.c | 2 | ||||
-rw-r--r-- | drivers/gpu/drm/tilcdc/tilcdc_drv.h | 3 |
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 | ||
180 | void tilcdc_crtc_off(struct drm_crtc *crtc) | 185 | static 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 | ||
229 | static void tilcdc_crtc_disable(struct drm_crtc *crtc) | 239 | static 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 | |||
245 | void tilcdc_crtc_shutdown(struct drm_crtc *crtc) | ||
246 | { | ||
247 | tilcdc_crtc_off(crtc, true); | ||
233 | } | 248 | } |
234 | 249 | ||
235 | static bool tilcdc_crtc_is_on(struct drm_crtc *crtc) | 250 | static 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); |
174 | int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); | 175 | int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode); |
175 | int tilcdc_crtc_max_width(struct drm_crtc *crtc); | 176 | int tilcdc_crtc_max_width(struct drm_crtc *crtc); |
176 | void tilcdc_crtc_off(struct drm_crtc *crtc); | 177 | void tilcdc_crtc_shutdown(struct drm_crtc *crtc); |
177 | int tilcdc_crtc_update_fb(struct drm_crtc *crtc, | 178 | int 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); |