Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eeb75474 authored by Rob Clark's avatar Rob Clark
Browse files

drm/msm/gpu: use pm-runtime



We need to use pm-runtime properly when IOMMU is using device_link() to
control it's own clocks.

Signed-off-by: default avatarRob Clark <robdclark@gmail.com>
parent c3c3ab19
Loading
Loading
Loading
Loading
+26 −10
Original line number Diff line number Diff line
@@ -155,21 +155,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)

	if (gpu) {
		int ret;
		mutex_lock(&dev->struct_mutex);
		gpu->funcs->pm_resume(gpu);
		mutex_unlock(&dev->struct_mutex);

		disable_irq(gpu->irq);

		ret = gpu->funcs->hw_init(gpu);
		pm_runtime_get_sync(&pdev->dev);
		ret = msm_gpu_hw_init(gpu);
		pm_runtime_put_sync(&pdev->dev);
		if (ret) {
			dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
			gpu->funcs->destroy(gpu);
			gpu = NULL;
		} else {
			enable_irq(gpu->irq);
			/* give inactive pm a chance to kick in: */
			msm_gpu_retire(gpu);
		}
	}

@@ -296,12 +289,35 @@ static const struct of_device_id dt_match[] = {
	{}
};

#ifdef CONFIG_PM
static int adreno_resume(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_gpu *gpu = platform_get_drvdata(pdev);

	return gpu->funcs->pm_resume(gpu);
}

static int adreno_suspend(struct device *dev)
{
	struct platform_device *pdev = to_platform_device(dev);
	struct msm_gpu *gpu = platform_get_drvdata(pdev);

	return gpu->funcs->pm_suspend(gpu);
}
#endif

static const struct dev_pm_ops adreno_pm_ops = {
	SET_RUNTIME_PM_OPS(adreno_suspend, adreno_resume, NULL)
};

static struct platform_driver adreno_driver = {
	.probe = adreno_probe,
	.remove = adreno_remove,
	.driver = {
		.name = "adreno",
		.of_match_table = dt_match,
		.pm = &adreno_pm_ops,
	},
};

+8 −3
Original line number Diff line number Diff line
@@ -115,6 +115,9 @@ void adreno_recover(struct msm_gpu *gpu)
	struct drm_device *dev = gpu->dev;
	int ret;

	// XXX pm-runtime??  we *need* the device to be off after this
	// so maybe continuing to call ->pm_suspend/resume() is better?

	gpu->funcs->pm_suspend(gpu);

	/* reset ringbuffer: */
@@ -127,13 +130,11 @@ void adreno_recover(struct msm_gpu *gpu)

	gpu->funcs->pm_resume(gpu);

	disable_irq(gpu->irq);
	ret = gpu->funcs->hw_init(gpu);
	ret = msm_gpu_hw_init(gpu);
	if (ret) {
		dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
		/* hmm, oh well? */
	}
	enable_irq(gpu->irq);
}

void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
@@ -365,6 +366,10 @@ int adreno_gpu_init(struct drm_device *drm, struct platform_device *pdev,
	if (ret)
		return ret;

	pm_runtime_set_autosuspend_delay(&pdev->dev, DRM_MSM_INACTIVE_PERIOD);
	pm_runtime_use_autosuspend(&pdev->dev);
	pm_runtime_enable(&pdev->dev);

	ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
	if (ret) {
		dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
+2 −2
Original line number Diff line number Diff line
@@ -28,9 +28,9 @@ static int msm_gpu_show(struct drm_device *dev, struct seq_file *m)

	if (gpu) {
		seq_printf(m, "%s Status:\n", gpu->name);
		gpu->funcs->pm_resume(gpu);
		pm_runtime_get_sync(&gpu->pdev->dev);
		gpu->funcs->show(gpu, m);
		gpu->funcs->pm_suspend(gpu);
		pm_runtime_put_sync(&gpu->pdev->dev);
	}

	return 0;
+2 −0
Original line number Diff line number Diff line
@@ -265,6 +265,8 @@ static int msm_drm_uninit(struct device *dev)

	if (gpu) {
		mutex_lock(&ddev->struct_mutex);
		// XXX what do we do here?
		//pm_runtime_enable(&pdev->dev);
		gpu->funcs->pm_suspend(gpu);
		mutex_unlock(&ddev->struct_mutex);
		gpu->funcs->destroy(gpu);
+27 −72
Original line number Diff line number Diff line
@@ -152,18 +152,9 @@ static int disable_axi(struct msm_gpu *gpu)

int msm_gpu_pm_resume(struct msm_gpu *gpu)
{
	struct drm_device *dev = gpu->dev;
	int ret;

	DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);

	WARN_ON(!mutex_is_locked(&dev->struct_mutex));

	if (gpu->active_cnt++ > 0)
		return 0;

	if (WARN_ON(gpu->active_cnt <= 0))
		return -EINVAL;
	DBG("%s", gpu->name);

	ret = enable_pwrrail(gpu);
	if (ret)
@@ -177,23 +168,16 @@ int msm_gpu_pm_resume(struct msm_gpu *gpu)
	if (ret)
		return ret;

	gpu->needs_hw_init = true;

	return 0;
}

int msm_gpu_pm_suspend(struct msm_gpu *gpu)
{
	struct drm_device *dev = gpu->dev;
	int ret;

	DBG("%s: active_cnt=%d", gpu->name, gpu->active_cnt);

	WARN_ON(!mutex_is_locked(&dev->struct_mutex));

	if (--gpu->active_cnt > 0)
		return 0;

	if (WARN_ON(gpu->active_cnt < 0))
		return -EINVAL;
	DBG("%s", gpu->name);

	ret = disable_axi(gpu);
	if (ret)
@@ -210,53 +194,20 @@ int msm_gpu_pm_suspend(struct msm_gpu *gpu)
	return 0;
}

/*
 * Inactivity detection (for suspend):
 */

static void inactive_worker(struct work_struct *work)
{
	struct msm_gpu *gpu = container_of(work, struct msm_gpu, inactive_work);
	struct drm_device *dev = gpu->dev;

	if (gpu->inactive)
		return;

	DBG("%s: inactive!\n", gpu->name);
	mutex_lock(&dev->struct_mutex);
	if (!(msm_gpu_active(gpu) || gpu->inactive)) {
		disable_axi(gpu);
		disable_clk(gpu);
		gpu->inactive = true;
	}
	mutex_unlock(&dev->struct_mutex);
}

static void inactive_handler(unsigned long data)
int msm_gpu_hw_init(struct msm_gpu *gpu)
{
	struct msm_gpu *gpu = (struct msm_gpu *)data;
	struct msm_drm_private *priv = gpu->dev->dev_private;
	int ret;

	queue_work(priv->wq, &gpu->inactive_work);
}
	if (!gpu->needs_hw_init)
		return 0;

/* cancel inactive timer and make sure we are awake: */
static void inactive_cancel(struct msm_gpu *gpu)
{
	DBG("%s", gpu->name);
	del_timer(&gpu->inactive_timer);
	if (gpu->inactive) {
		enable_clk(gpu);
		enable_axi(gpu);
		gpu->inactive = false;
	}
}
	disable_irq(gpu->irq);
	ret = gpu->funcs->hw_init(gpu);
	if (!ret)
		gpu->needs_hw_init = false;
	enable_irq(gpu->irq);

static void inactive_start(struct msm_gpu *gpu)
{
	DBG("%s", gpu->name);
	mod_timer(&gpu->inactive_timer,
			round_jiffies_up(jiffies + DRM_MSM_INACTIVE_JIFFIES));
	return ret;
}

/*
@@ -296,8 +247,9 @@ static void recover_worker(struct work_struct *work)
		/* retire completed submits, plus the one that hung: */
		retire_submits(gpu);

		inactive_cancel(gpu);
		pm_runtime_get_sync(&gpu->pdev->dev);
		gpu->funcs->recover(gpu);
		pm_runtime_put_sync(&gpu->pdev->dev);

		/* replay the remaining submits after the one that hung: */
		list_for_each_entry(submit, &gpu->submit_list, node) {
@@ -400,6 +352,8 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
{
	unsigned long flags;

	pm_runtime_get_sync(&gpu->pdev->dev);

	spin_lock_irqsave(&gpu->perf_lock, flags);
	/* we could dynamically enable/disable perfcntr registers too.. */
	gpu->last_sample.active = msm_gpu_active(gpu);
@@ -413,6 +367,7 @@ void msm_gpu_perfcntr_start(struct msm_gpu *gpu)
void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
{
	gpu->perfcntr_active = false;
	pm_runtime_put_sync(&gpu->pdev->dev);
}

/* returns -errno or # of cntrs sampled */
@@ -458,6 +413,8 @@ static void retire_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit)
		drm_gem_object_unreference(&msm_obj->base);
	}

	pm_runtime_mark_last_busy(&gpu->pdev->dev);
	pm_runtime_put_autosuspend(&gpu->pdev->dev);
	msm_gem_submit_free(submit);
}

@@ -492,9 +449,6 @@ static void retire_worker(struct work_struct *work)
	mutex_lock(&dev->struct_mutex);
	retire_submits(gpu);
	mutex_unlock(&dev->struct_mutex);

	if (!msm_gpu_active(gpu))
		inactive_start(gpu);
}

/* call from irq handler to schedule work to retire bo's */
@@ -515,7 +469,9 @@ void msm_gpu_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,

	WARN_ON(!mutex_is_locked(&dev->struct_mutex));

	inactive_cancel(gpu);
	pm_runtime_get_sync(&gpu->pdev->dev);

	msm_gpu_hw_init(gpu);

	list_add_tail(&submit->node, &gpu->submit_list);

@@ -576,7 +532,6 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
	gpu->dev = drm;
	gpu->funcs = funcs;
	gpu->name = name;
	gpu->inactive = true;
	gpu->fctx = msm_fence_context_alloc(drm, name);
	if (IS_ERR(gpu->fctx)) {
		ret = PTR_ERR(gpu->fctx);
@@ -586,13 +541,10 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,

	INIT_LIST_HEAD(&gpu->active_list);
	INIT_WORK(&gpu->retire_work, retire_worker);
	INIT_WORK(&gpu->inactive_work, inactive_worker);
	INIT_WORK(&gpu->recover_work, recover_worker);

	INIT_LIST_HEAD(&gpu->submit_list);

	setup_timer(&gpu->inactive_timer, inactive_handler,
			(unsigned long)gpu);
	setup_timer(&gpu->hangcheck_timer, hangcheck_handler,
			(unsigned long)gpu);

@@ -684,6 +636,9 @@ int msm_gpu_init(struct drm_device *drm, struct platform_device *pdev,
		goto fail;
	}

	gpu->pdev = pdev;
	platform_set_drvdata(pdev, gpu);

	bs_init(gpu);

	return 0;
Loading