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

Commit 0fc2ce7e authored by Harshdeep Dhatt's avatar Harshdeep Dhatt
Browse files

msm: kgsl: Add suspend and resume for hwsched driver



Add the support for performing a driver wide suspend and resume
with hwsched driver.

Change-Id: I9bc47e714aaafd33f52ea618fdecf14cb512ea61
Signed-off-by: default avatarHarshdeep Dhatt <hdhatt@codeaurora.org>
parent 26b7004d
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -1881,11 +1881,11 @@ static int adreno_last_close(struct kgsl_device *device)
	 * Wait up to 1 second for the active count to go low
	 * and then start complaining about it
	 */
	if (kgsl_active_count_wait(device, 0)) {
	if (kgsl_active_count_wait(device, 0, HZ)) {
		dev_err(device->dev,
			"Waiting for the active count to become 0\n");

		while (kgsl_active_count_wait(device, 0))
		while (kgsl_active_count_wait(device, 0, HZ))
			dev_err(device->dev,
				"Still waiting for the active count\n");
	}
+3 −4
Original line number Diff line number Diff line
@@ -3201,7 +3201,7 @@ static int a6xx_gmu_pm_suspend(struct adreno_device *adreno_dev)
	reinit_completion(&device->halt_gate);

	/* wait for active count so device can be put in slumber */
	ret = kgsl_active_count_wait(device, 0);
	ret = kgsl_active_count_wait(device, 0, HZ);
	if (ret) {
		dev_err(device->dev,
			"Timed out waiting for the active count\n");
@@ -3232,10 +3232,9 @@ static void a6xx_gmu_pm_resume(struct adreno_device *adreno_dev)
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);

	if (!test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags)) {
		dev_err(device->dev, "resume invoked without a suspend\n");
	if (WARN(!test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags),
		"resume invoked without a suspend\n"))
		return;
	}

	adreno_dispatcher_unhalt(device);

+83 −0
Original line number Diff line number Diff line
@@ -672,12 +672,95 @@ static int a6xx_hwsched_bus_set(struct adreno_device *adreno_dev, int buslevel,
	return ret;
}

static int a6xx_hwsched_pm_suspend(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);
	int ret;

	if (test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags))
		return 0;

	trace_kgsl_pwr_request_state(device, KGSL_STATE_SUSPEND);

	/* Halt any new submissions */
	reinit_completion(&device->halt_gate);

	mutex_unlock(&device->mutex);

	/* Flush any currently running instances of the dispatcher */
	kthread_flush_worker(&kgsl_driver.worker);

	mutex_lock(&device->mutex);

	/* This ensures that dispatcher doesn't submit any new work */
	adreno_dispatcher_halt(device);

	/**
	 * Wait for the dispatcher to retire everything by waiting
	 * for the active count to go to zero.
	 */
	ret = kgsl_active_count_wait(device, 0, msecs_to_jiffies(100));
	if (ret) {
		dev_err(device->dev, "Timed out waiting for the active count\n");
		goto err;
	}

	if (test_bit(GMU_PRIV_GPU_STARTED, &gmu->flags)) {
		unsigned long wait = jiffies +
			msecs_to_jiffies(ADRENO_IDLE_TIMEOUT);

		do {
			if (a6xx_hw_isidle(adreno_dev))
				break;
		} while (time_before(jiffies, wait));

		if (!a6xx_hw_isidle(adreno_dev)) {
			dev_err(device->dev, "Timed out idling the gpu\n");
			ret = -ETIMEDOUT;
			goto err;
		}

		a6xx_hwsched_power_off(adreno_dev);
	}

	set_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags);

	trace_kgsl_pwr_set_state(device, KGSL_STATE_SUSPEND);

	return 0;

err:
	adreno_dispatcher_unhalt(device);
	adreno_hwsched_start(adreno_dev);

	return ret;
}

static void a6xx_hwsched_pm_resume(struct adreno_device *adreno_dev)
{
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct a6xx_gmu_device *gmu = to_a6xx_gmu(adreno_dev);

	if (WARN(!test_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags),
		"resume invoked without a suspend\n"))
		return;

	adreno_dispatcher_unhalt(device);

	adreno_hwsched_start(adreno_dev);

	clear_bit(GMU_PRIV_PM_SUSPEND, &gmu->flags);
}

const struct adreno_power_ops a6xx_hwsched_power_ops = {
	.first_open = a6xx_hwsched_first_open,
	.last_close = a6xx_hwsched_power_off,
	.active_count_get = a6xx_hwsched_active_count_get,
	.active_count_put = a6xx_hwsched_active_count_put,
	.touch_wakeup = a6xx_hwsched_touch_wakeup,
	.pm_suspend = a6xx_hwsched_pm_suspend,
	.pm_resume = a6xx_hwsched_pm_resume,
	.gpu_clock_set = a6xx_hwsched_clock_set,
	.gpu_bus_set = a6xx_hwsched_bus_set,
};
+3 −4
Original line number Diff line number Diff line
@@ -1153,7 +1153,7 @@ static int a6xx_rgmu_pm_suspend(struct adreno_device *adreno_dev)
	reinit_completion(&device->halt_gate);

	/* wait for active count so device can be put in slumber */
	ret = kgsl_active_count_wait(device, 0);
	ret = kgsl_active_count_wait(device, 0, HZ);
	if (ret) {
		dev_err(device->dev,
			"Timed out waiting for the active count\n");
@@ -1183,10 +1183,9 @@ static void a6xx_rgmu_pm_resume(struct adreno_device *adreno_dev)
	struct kgsl_device *device = KGSL_DEVICE(adreno_dev);
	struct a6xx_rgmu_device *rgmu = to_a6xx_rgmu(adreno_dev);

	if (!test_bit(RGMU_PRIV_PM_SUSPEND, &rgmu->flags)) {
		dev_err(device->dev, "resume invoked without a suspend\n");
	if (WARN(!test_bit(GMU_PRIV_PM_SUSPEND, &rgmu->flags),
		"resume invoked without a suspend\n"))
		return;
	}

	adreno_dispatcher_unhalt(device);

+7 −0
Original line number Diff line number Diff line
@@ -296,6 +296,13 @@ static int hwsched_sendcmd(struct adreno_device *adreno_dev,

	mutex_lock(&device->mutex);

	if (adreno_gpu_halt(adreno_dev) != 0) {
		mutex_unlock(&device->mutex);
		kmem_cache_free(obj_cache, obj);
		return -EBUSY;
	}


	if (kgsl_context_detached(context)) {
		mutex_unlock(&device->mutex);
		kmem_cache_free(obj_cache, obj);
Loading