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: Harshdeep Dhatt <hdhatt@codeaurora.org>
This commit is contained in:
Harshdeep Dhatt 2020-07-24 12:45:10 -06:00
commit 0fc2ce7e40
7 changed files with 111 additions and 21 deletions

View file

@ -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");
}

View file

@ -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);

View file

@ -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,
};

View file

@ -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);

View file

@ -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);

View file

@ -2026,7 +2026,7 @@ static int _suspend(struct kgsl_device *device)
/* drain to prevent from more commands being submitted */
device->ftbl->drain(device);
/* 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)
goto err;
@ -2155,17 +2155,10 @@ static int _check_active_count(struct kgsl_device *device, int count)
return atomic_read(&device->active_cnt) > count ? 0 : 1;
}
/**
* kgsl_active_count_wait() - Wait for activity to finish.
* @device: Pointer to a KGSL device
* @count: Active count value to wait for
*
* Block until the active_cnt value hits the desired value
*/
int kgsl_active_count_wait(struct kgsl_device *device, int count)
int kgsl_active_count_wait(struct kgsl_device *device, int count,
unsigned long wait_jiffies)
{
int result = 0;
long wait_jiffies = HZ;
if (WARN_ON(!mutex_is_locked(&device->mutex)))
return -EINVAL;

View file

@ -198,7 +198,16 @@ kgsl_pwrctrl_active_freq(struct kgsl_pwrctrl *pwr)
return pwr->pwrlevels[pwr->active_pwrlevel].gpu_freq;
}
int kgsl_active_count_wait(struct kgsl_device *device, int count);
/**
* kgsl_active_count_wait() - Wait for activity to finish.
* @device: Pointer to a KGSL device
* @count: Active count value to wait for
* @wait_jiffies: Jiffies to wait
*
* Block until the active_cnt value hits the desired value
*/
int kgsl_active_count_wait(struct kgsl_device *device, int count,
unsigned long wait_jiffies);
void kgsl_pwrctrl_busy_time(struct kgsl_device *device, u64 time, u64 busy);
void kgsl_pwrctrl_set_constraint(struct kgsl_device *device,
struct kgsl_pwr_constraint *pwrc, uint32_t id);