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 Original line Diff line number Diff line
@@ -155,21 +155,14 @@ struct msm_gpu *adreno_load_gpu(struct drm_device *dev)


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


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

		ret = msm_gpu_hw_init(gpu);
		ret = gpu->funcs->hw_init(gpu);
		pm_runtime_put_sync(&pdev->dev);
		if (ret) {
		if (ret) {
			dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
			dev_err(dev->dev, "gpu hw init failed: %d\n", ret);
			gpu->funcs->destroy(gpu);
			gpu->funcs->destroy(gpu);
			gpu = NULL;
			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 = {
static struct platform_driver adreno_driver = {
	.probe = adreno_probe,
	.probe = adreno_probe,
	.remove = adreno_remove,
	.remove = adreno_remove,
	.driver = {
	.driver = {
		.name = "adreno",
		.name = "adreno",
		.of_match_table = dt_match,
		.of_match_table = dt_match,
		.pm = &adreno_pm_ops,
	},
	},
};
};


+8 −3
Original line number Original line Diff line number Diff line
@@ -115,6 +115,9 @@ void adreno_recover(struct msm_gpu *gpu)
	struct drm_device *dev = gpu->dev;
	struct drm_device *dev = gpu->dev;
	int ret;
	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);
	gpu->funcs->pm_suspend(gpu);


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


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


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


void adreno_submit(struct msm_gpu *gpu, struct msm_gem_submit *submit,
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)
	if (ret)
		return 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);
	ret = request_firmware(&adreno_gpu->pm4, adreno_gpu->info->pm4fw, drm->dev);
	if (ret) {
	if (ret) {
		dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
		dev_err(drm->dev, "failed to load %s PM4 firmware: %d\n",
+2 −2
Original line number Original line Diff line number Diff line
@@ -28,9 +28,9 @@ static int msm_gpu_show(struct drm_device *dev, struct seq_file *m)


	if (gpu) {
	if (gpu) {
		seq_printf(m, "%s Status:\n", gpu->name);
		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->show(gpu, m);
		gpu->funcs->pm_suspend(gpu);
		pm_runtime_put_sync(&gpu->pdev->dev);
	}
	}


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


	if (gpu) {
	if (gpu) {
		mutex_lock(&ddev->struct_mutex);
		mutex_lock(&ddev->struct_mutex);
		// XXX what do we do here?
		//pm_runtime_enable(&pdev->dev);
		gpu->funcs->pm_suspend(gpu);
		gpu->funcs->pm_suspend(gpu);
		mutex_unlock(&ddev->struct_mutex);
		mutex_unlock(&ddev->struct_mutex);
		gpu->funcs->destroy(gpu);
		gpu->funcs->destroy(gpu);
+27 −72
Original line number Original line 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)
int msm_gpu_pm_resume(struct msm_gpu *gpu)
{
{
	struct drm_device *dev = gpu->dev;
	int ret;
	int ret;


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

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

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

	if (WARN_ON(gpu->active_cnt <= 0))
		return -EINVAL;


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


	gpu->needs_hw_init = true;

	return 0;
	return 0;
}
}


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


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

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

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

	if (WARN_ON(gpu->active_cnt < 0))
		return -EINVAL;


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


/*
int msm_gpu_hw_init(struct msm_gpu *gpu)
 * 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)
{
{
	struct msm_gpu *gpu = (struct msm_gpu *)data;
	int ret;
	struct msm_drm_private *priv = gpu->dev->dev_private;


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


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


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


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


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


		/* replay the remaining submits after the one that hung: */
		/* replay the remaining submits after the one that hung: */
		list_for_each_entry(submit, &gpu->submit_list, node) {
		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;
	unsigned long flags;


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

	spin_lock_irqsave(&gpu->perf_lock, flags);
	spin_lock_irqsave(&gpu->perf_lock, flags);
	/* we could dynamically enable/disable perfcntr registers too.. */
	/* we could dynamically enable/disable perfcntr registers too.. */
	gpu->last_sample.active = msm_gpu_active(gpu);
	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)
void msm_gpu_perfcntr_stop(struct msm_gpu *gpu)
{
{
	gpu->perfcntr_active = false;
	gpu->perfcntr_active = false;
	pm_runtime_put_sync(&gpu->pdev->dev);
}
}


/* returns -errno or # of cntrs sampled */
/* 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);
		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);
	msm_gem_submit_free(submit);
}
}


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

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


/* call from irq handler to schedule work to retire bo's */
/* 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));
	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);
	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->dev = drm;
	gpu->funcs = funcs;
	gpu->funcs = funcs;
	gpu->name = name;
	gpu->name = name;
	gpu->inactive = true;
	gpu->fctx = msm_fence_context_alloc(drm, name);
	gpu->fctx = msm_fence_context_alloc(drm, name);
	if (IS_ERR(gpu->fctx)) {
	if (IS_ERR(gpu->fctx)) {
		ret = PTR_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_LIST_HEAD(&gpu->active_list);
	INIT_WORK(&gpu->retire_work, retire_worker);
	INIT_WORK(&gpu->retire_work, retire_worker);
	INIT_WORK(&gpu->inactive_work, inactive_worker);
	INIT_WORK(&gpu->recover_work, recover_worker);
	INIT_WORK(&gpu->recover_work, recover_worker);


	INIT_LIST_HEAD(&gpu->submit_list);
	INIT_LIST_HEAD(&gpu->submit_list);


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


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


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

	bs_init(gpu);
	bs_init(gpu);


	return 0;
	return 0;
Loading