Commit 658f4c82 authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm/devfreq: Add 1ms delay before clamping freq



Add a short delay before clamping to idle frequency on active->idle
transition.  It takes ~0.5ms to increase the freq again on the next
idle->active transition, so this helps avoid extra freq transitions
on workloads that bounce between CPU and GPU.

Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
Link: https://lore.kernel.org/r/20210927230455.1066297-2-robdclark@gmail.com


Signed-off-by: default avatarRob Clark <robdclark@chromium.org>
parent ddb6e37a
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -112,6 +112,13 @@ struct msm_gpu_devfreq {
	 * it is inactive.
	 */
	unsigned long idle_freq;

	/**
	 * idle_work:
	 *
	 * Used to delay clamping to idle freq on active->idle transition.
	 */
	struct msm_hrtimer_work idle_work;
};

struct msm_gpu {
+30 −8
Original line number Diff line number Diff line
@@ -88,8 +88,12 @@ static struct devfreq_dev_profile msm_devfreq_profile = {
	.get_cur_freq = msm_devfreq_get_cur_freq,
};

static void msm_devfreq_idle_work(struct kthread_work *work);

void msm_devfreq_init(struct msm_gpu *gpu)
{
	struct msm_gpu_devfreq *df = &gpu->devfreq;

	/* We need target support to do devfreq */
	if (!gpu->funcs->gpu_busy)
		return;
@@ -105,25 +109,27 @@ void msm_devfreq_init(struct msm_gpu *gpu)
	msm_devfreq_profile.freq_table = NULL;
	msm_devfreq_profile.max_state = 0;

	gpu->devfreq.devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
	df->devfreq = devm_devfreq_add_device(&gpu->pdev->dev,
			&msm_devfreq_profile, DEVFREQ_GOV_SIMPLE_ONDEMAND,
			NULL);

	if (IS_ERR(gpu->devfreq.devfreq)) {
	if (IS_ERR(df->devfreq)) {
		DRM_DEV_ERROR(&gpu->pdev->dev, "Couldn't initialize GPU devfreq\n");
		gpu->devfreq.devfreq = NULL;
		df->devfreq = NULL;
		return;
	}

	devfreq_suspend_device(gpu->devfreq.devfreq);
	devfreq_suspend_device(df->devfreq);

	gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node,
			gpu->devfreq.devfreq);
	gpu->cooling = of_devfreq_cooling_register(gpu->pdev->dev.of_node, df->devfreq);
	if (IS_ERR(gpu->cooling)) {
		DRM_DEV_ERROR(&gpu->pdev->dev,
				"Couldn't register GPU cooling device\n");
		gpu->cooling = NULL;
	}

	msm_hrtimer_work_init(&df->idle_work, gpu->worker, msm_devfreq_idle_work,
			      CLOCK_MONOTONIC, HRTIMER_MODE_REL);
}

void msm_devfreq_cleanup(struct msm_gpu *gpu)
@@ -154,6 +160,11 @@ void msm_devfreq_active(struct msm_gpu *gpu)
	if (!df->devfreq)
		return;

	/*
	 * Cancel any pending transition to idle frequency:
	 */
	hrtimer_cancel(&df->idle_work.timer);

	/*
	 * Hold devfreq lock to synchronize with get_dev_status()/
	 * target() callbacks
@@ -184,9 +195,12 @@ void msm_devfreq_active(struct msm_gpu *gpu)
	mutex_unlock(&df->devfreq->lock);
}

void msm_devfreq_idle(struct msm_gpu *gpu)

static void msm_devfreq_idle_work(struct kthread_work *work)
{
	struct msm_gpu_devfreq *df = &gpu->devfreq;
	struct msm_gpu_devfreq *df = container_of(work,
			struct msm_gpu_devfreq, idle_work.work);
	struct msm_gpu *gpu = container_of(df, struct msm_gpu, devfreq);
	unsigned long idle_freq, target_freq = 0;

	if (!df->devfreq)
@@ -207,3 +221,11 @@ void msm_devfreq_idle(struct msm_gpu *gpu)

	mutex_unlock(&df->devfreq->lock);
}

void msm_devfreq_idle(struct msm_gpu *gpu)
{
	struct msm_gpu_devfreq *df = &gpu->devfreq;

	msm_hrtimer_queue_work(&df->idle_work, ms_to_ktime(1),
			       HRTIMER_MODE_ABS);
}