Commit ac2ad73e authored by Dave Airlie's avatar Dave Airlie
Browse files

Merge tag 'exynos-drm-fixes-for-v6.16-rc4' of...

Merge tag 'exynos-drm-fixes-for-v6.16-rc4' of git://git.kernel.org/pub/scm/linux/kernel/git/daeinki/drm-exynos

 into drm-fixes

Fixups
- Fixed raw pointer leakage and unsafe behavior in printk()
  . Switch from %pK to %p for pointer formatting, as %p is now safer
    and prevents issues like raw pointer leakage and acquiring sleeping
    locks in atomic contexts.

- Fixed kernel panic during boot
  . A NULL pointer dereference issue occasionally occurred
    when the vblank interrupt handler was called before
    the DRM driver was fully initialized during boot.
    So this patch fixes the issue by adding a check in the interrupt handler
    to ensure the DRM driver is properly initialized.

- Fixed a lockup issue on Samsung Peach-Pit/Pi Chromebooks
  . The issue occurred after commit c9b1150a changed
    the call order of CRTC enable/disable and bridge pre_enable/post_disable
    methods, causing fimd_dp_clock_enable() to be called
    before the FIMD device was activated. To fix this,
    runtime PM guards were added to fimd_dp_clock_enable()
    to ensure proper operation even when CRTC is not enabled.

Signed-off-by: default avatarDave Airlie <airlied@redhat.com>

From: Inki Dae <inki.dae@samsung.com>
Link: https://lore.kernel.org/r/20250629083554.28628-1-inki.dae@samsung.com
parents afd30ace 5d91394f
Loading
Loading
Loading
Loading
+4 −0
Original line number Diff line number Diff line
@@ -636,6 +636,10 @@ static irqreturn_t decon_irq_handler(int irq, void *dev_id)
	if (!ctx->drm_dev)
		goto out;

	/* check if crtc and vblank have been initialized properly */
	if (!drm_dev_has_vblank(ctx->drm_dev))
		goto out;

	if (!ctx->i80_if) {
		drm_crtc_handle_vblank(&ctx->crtc->base);

+12 −0
Original line number Diff line number Diff line
@@ -187,6 +187,7 @@ struct fimd_context {
	u32				i80ifcon;
	bool				i80_if;
	bool				suspended;
	bool				dp_clk_enabled;
	wait_queue_head_t		wait_vsync_queue;
	atomic_t			wait_vsync_event;
	atomic_t			win_updated;
@@ -1047,7 +1048,18 @@ static void fimd_dp_clock_enable(struct exynos_drm_clk *clk, bool enable)
	struct fimd_context *ctx = container_of(clk, struct fimd_context,
						dp_clk);
	u32 val = enable ? DP_MIE_CLK_DP_ENABLE : DP_MIE_CLK_DISABLE;

	if (enable == ctx->dp_clk_enabled)
		return;

	if (enable)
		pm_runtime_resume_and_get(ctx->dev);

	ctx->dp_clk_enabled = enable;
	writel(val, ctx->regs + DP_MIE_CLKCON);

	if (!enable)
		pm_runtime_put(ctx->dev);
}

static const struct exynos_drm_crtc_ops fimd_crtc_ops = {
+1 −1
Original line number Diff line number Diff line
@@ -174,7 +174,7 @@ static struct exynos_drm_gem *exynos_drm_gem_init(struct drm_device *dev,
		return ERR_PTR(ret);
	}

	DRM_DEV_DEBUG_KMS(dev->dev, "created file object = %pK\n", obj->filp);
	DRM_DEV_DEBUG_KMS(dev->dev, "created file object = %p\n", obj->filp);

	return exynos_gem;
}
+16 −16
Original line number Diff line number Diff line
@@ -271,7 +271,7 @@ static inline struct exynos_drm_ipp_task *
	task->src.rect.h = task->dst.rect.h = UINT_MAX;
	task->transform.rotation = DRM_MODE_ROTATE_0;

	DRM_DEV_DEBUG_DRIVER(task->dev, "Allocated task %pK\n", task);
	DRM_DEV_DEBUG_DRIVER(task->dev, "Allocated task %p\n", task);

	return task;
}
@@ -339,7 +339,7 @@ static int exynos_drm_ipp_task_set(struct exynos_drm_ipp_task *task,
	}

	DRM_DEV_DEBUG_DRIVER(task->dev,
			     "Got task %pK configuration from userspace\n",
			     "Got task %p configuration from userspace\n",
			     task);
	return 0;
}
@@ -394,7 +394,7 @@ static void exynos_drm_ipp_task_release_buf(struct exynos_drm_ipp_buffer *buf)
static void exynos_drm_ipp_task_free(struct exynos_drm_ipp *ipp,
				 struct exynos_drm_ipp_task *task)
{
	DRM_DEV_DEBUG_DRIVER(task->dev, "Freeing task %pK\n", task);
	DRM_DEV_DEBUG_DRIVER(task->dev, "Freeing task %p\n", task);

	exynos_drm_ipp_task_release_buf(&task->src);
	exynos_drm_ipp_task_release_buf(&task->dst);
@@ -559,7 +559,7 @@ static int exynos_drm_ipp_check_format(struct exynos_drm_ipp_task *task,
					    DRM_EXYNOS_IPP_FORMAT_DESTINATION);
	if (!fmt) {
		DRM_DEV_DEBUG_DRIVER(task->dev,
				     "Task %pK: %s format not supported\n",
				     "Task %p: %s format not supported\n",
				     task, buf == src ? "src" : "dst");
		return -EINVAL;
	}
@@ -609,7 +609,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
	bool rotate = (rotation != DRM_MODE_ROTATE_0);
	bool scale = false;

	DRM_DEV_DEBUG_DRIVER(task->dev, "Checking task %pK\n", task);
	DRM_DEV_DEBUG_DRIVER(task->dev, "Checking task %p\n", task);

	if (src->rect.w == UINT_MAX)
		src->rect.w = src->buf.width;
@@ -625,7 +625,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
	    dst->rect.x + dst->rect.w > (dst->buf.width) ||
	    dst->rect.y + dst->rect.h > (dst->buf.height)) {
		DRM_DEV_DEBUG_DRIVER(task->dev,
				     "Task %pK: defined area is outside provided buffers\n",
				     "Task %p: defined area is outside provided buffers\n",
				     task);
		return -EINVAL;
	}
@@ -642,7 +642,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
	    (!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_SCALE) && scale) ||
	    (!(ipp->capabilities & DRM_EXYNOS_IPP_CAP_CONVERT) &&
	     src->buf.fourcc != dst->buf.fourcc)) {
		DRM_DEV_DEBUG_DRIVER(task->dev, "Task %pK: hw capabilities exceeded\n",
		DRM_DEV_DEBUG_DRIVER(task->dev, "Task %p: hw capabilities exceeded\n",
				     task);
		return -EINVAL;
	}
@@ -655,7 +655,7 @@ static int exynos_drm_ipp_task_check(struct exynos_drm_ipp_task *task)
	if (ret)
		return ret;

	DRM_DEV_DEBUG_DRIVER(ipp->dev, "Task %pK: all checks done.\n",
	DRM_DEV_DEBUG_DRIVER(ipp->dev, "Task %p: all checks done.\n",
			     task);

	return ret;
@@ -667,25 +667,25 @@ static int exynos_drm_ipp_task_setup_buffers(struct exynos_drm_ipp_task *task,
	struct exynos_drm_ipp_buffer *src = &task->src, *dst = &task->dst;
	int ret = 0;

	DRM_DEV_DEBUG_DRIVER(task->dev, "Setting buffer for task %pK\n",
	DRM_DEV_DEBUG_DRIVER(task->dev, "Setting buffer for task %p\n",
			     task);

	ret = exynos_drm_ipp_task_setup_buffer(src, filp);
	if (ret) {
		DRM_DEV_DEBUG_DRIVER(task->dev,
				     "Task %pK: src buffer setup failed\n",
				     "Task %p: src buffer setup failed\n",
				     task);
		return ret;
	}
	ret = exynos_drm_ipp_task_setup_buffer(dst, filp);
	if (ret) {
		DRM_DEV_DEBUG_DRIVER(task->dev,
				     "Task %pK: dst buffer setup failed\n",
				     "Task %p: dst buffer setup failed\n",
				     task);
		return ret;
	}

	DRM_DEV_DEBUG_DRIVER(task->dev, "Task %pK: buffers prepared.\n",
	DRM_DEV_DEBUG_DRIVER(task->dev, "Task %p: buffers prepared.\n",
			     task);

	return ret;
@@ -764,7 +764,7 @@ void exynos_drm_ipp_task_done(struct exynos_drm_ipp_task *task, int ret)
	struct exynos_drm_ipp *ipp = task->ipp;
	unsigned long flags;

	DRM_DEV_DEBUG_DRIVER(task->dev, "ipp: %d, task %pK done: %d\n",
	DRM_DEV_DEBUG_DRIVER(task->dev, "ipp: %d, task %p done: %d\n",
			     ipp->id, task, ret);

	spin_lock_irqsave(&ipp->lock, flags);
@@ -807,7 +807,7 @@ static void exynos_drm_ipp_next_task(struct exynos_drm_ipp *ipp)
	spin_unlock_irqrestore(&ipp->lock, flags);

	DRM_DEV_DEBUG_DRIVER(ipp->dev,
			     "ipp: %d, selected task %pK to run\n", ipp->id,
			     "ipp: %d, selected task %p to run\n", ipp->id,
			     task);

	ret = ipp->funcs->commit(ipp, task);
@@ -917,14 +917,14 @@ int exynos_drm_ipp_commit_ioctl(struct drm_device *dev, void *data,
	 */
	if (arg->flags & DRM_EXYNOS_IPP_FLAG_NONBLOCK) {
		DRM_DEV_DEBUG_DRIVER(ipp->dev,
				     "ipp: %d, nonblocking processing task %pK\n",
				     "ipp: %d, nonblocking processing task %p\n",
				     ipp->id, task);

		task->flags |= DRM_EXYNOS_IPP_TASK_ASYNC;
		exynos_drm_ipp_schedule_task(task->ipp, task);
		ret = 0;
	} else {
		DRM_DEV_DEBUG_DRIVER(ipp->dev, "ipp: %d, processing task %pK\n",
		DRM_DEV_DEBUG_DRIVER(ipp->dev, "ipp: %d, processing task %p\n",
				     ipp->id, task);
		exynos_drm_ipp_schedule_task(ipp, task);
		ret = wait_event_interruptible(ipp->done_wq,