Commit 2d53a180 authored by Jyri Sarha's avatar Jyri Sarha
Browse files

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: default avatarJyri Sarha <jsarha@ti.com>
parent 9e79e062
Loading
Loading
Loading
Loading
+23 −6
Original line number Diff line number Diff line
@@ -33,7 +33,9 @@ struct tilcdc_crtc {
	struct drm_plane primary;
	const struct tilcdc_panel_info *info;
	struct drm_pending_vblank_event *event;
	struct mutex enable_lock;
	bool enabled;
	bool shutdown;
	wait_queue_head_t frame_done_wq;
	bool frame_done;
	spinlock_t irq_lock;
@@ -158,9 +160,11 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);

	WARN_ON(!drm_modeset_is_locked(&crtc->mutex));

	if (tilcdc_crtc->enabled)
	mutex_lock(&tilcdc_crtc->enable_lock);
	if (tilcdc_crtc->enabled || tilcdc_crtc->shutdown) {
		mutex_unlock(&tilcdc_crtc->enable_lock);
		return;
	}

	pm_runtime_get_sync(dev->dev);

@@ -175,17 +179,22 @@ static void tilcdc_crtc_enable(struct drm_crtc *crtc)
	drm_crtc_vblank_on(crtc);

	tilcdc_crtc->enabled = true;
	mutex_unlock(&tilcdc_crtc->enable_lock);
}

void tilcdc_crtc_off(struct drm_crtc *crtc)
static void tilcdc_crtc_off(struct drm_crtc *crtc, bool shutdown)
{
	struct tilcdc_crtc *tilcdc_crtc = to_tilcdc_crtc(crtc);
	struct drm_device *dev = crtc->dev;
	struct tilcdc_drm_private *priv = dev->dev_private;

	if (!tilcdc_crtc->enabled)
	mutex_lock(&tilcdc_crtc->enable_lock);
	if (shutdown)
		tilcdc_crtc->shutdown = true;
	if (!tilcdc_crtc->enabled) {
		mutex_unlock(&tilcdc_crtc->enable_lock);
		return;

	}
	tilcdc_crtc->frame_done = false;
	tilcdc_clear(dev, LCDC_RASTER_CTRL_REG, LCDC_RASTER_ENABLE);

@@ -224,12 +233,18 @@ void tilcdc_crtc_off(struct drm_crtc *crtc)
	tilcdc_crtc->last_vblank = ktime_set(0, 0);

	tilcdc_crtc->enabled = false;
	mutex_unlock(&tilcdc_crtc->enable_lock);
}

static void tilcdc_crtc_disable(struct drm_crtc *crtc)
{
	WARN_ON(!drm_modeset_is_locked(&crtc->mutex));
	tilcdc_crtc_off(crtc);
	tilcdc_crtc_off(crtc, false);
}

void tilcdc_crtc_shutdown(struct drm_crtc *crtc)
{
	tilcdc_crtc_off(crtc, true);
}

static bool tilcdc_crtc_is_on(struct drm_crtc *crtc)
@@ -857,6 +872,8 @@ struct drm_crtc *tilcdc_crtc_create(struct drm_device *dev)
	if (ret < 0)
		goto fail;

	mutex_init(&tilcdc_crtc->enable_lock);

	init_waitqueue_head(&tilcdc_crtc->frame_done_wq);

	drm_flip_work_init(&tilcdc_crtc->unref_work,
+1 −1
Original line number Diff line number Diff line
@@ -197,7 +197,7 @@ static void tilcdc_fini(struct drm_device *dev)
	struct tilcdc_drm_private *priv = dev->dev_private;

	if (priv->crtc)
		tilcdc_crtc_off(priv->crtc);
		tilcdc_crtc_shutdown(priv->crtc);

	if (priv->is_registered)
		drm_dev_unregister(dev);
+2 −1
Original line number Diff line number Diff line
@@ -33,6 +33,7 @@
#include <drm/drm_crtc_helper.h>
#include <drm/drm_gem_cma_helper.h>
#include <drm/drm_fb_cma_helper.h>
#include <drm/drm_bridge.h>

/* Defaulting to pixel clock defined on AM335x */
#define TILCDC_DEFAULT_MAX_PIXELCLOCK  126000
@@ -173,7 +174,7 @@ void tilcdc_crtc_set_simulate_vesa_sync(struct drm_crtc *crtc,
					bool simulate_vesa_sync);
int tilcdc_crtc_mode_valid(struct drm_crtc *crtc, struct drm_display_mode *mode);
int tilcdc_crtc_max_width(struct drm_crtc *crtc);
void tilcdc_crtc_off(struct drm_crtc *crtc);
void tilcdc_crtc_shutdown(struct drm_crtc *crtc);
int tilcdc_crtc_update_fb(struct drm_crtc *crtc,
		struct drm_framebuffer *fb,
		struct drm_pending_vblank_event *event);