};
+static void stop_podgov_workers(struct podgov_info_rec *podgov)
+{
+ /* idle_timer can rearm itself */
+ do {
+ cancel_delayed_work_sync(&podgov->idle_timer);
+ } while (delayed_work_pending(&podgov->idle_timer));
+
+ cancel_work_sync(&podgov->work);
+}
+
/*******************************************************************************
* scaling_limit(df, freq)
*
unsigned long freq;
/* make sure the device is alive before doing any scaling */
- nvhost_module_busy(pdev);
+ nvhost_module_busy_noresume(pdev);
+ if (!pm_runtime_active(&pdev->dev)) {
+ nvhost_module_idle(pdev);
+ return;
+ }
+
mutex_lock(&df->lock);
if (!podgov->enable)
mutex_unlock(&df->lock);
return;
}
- cancel_delayed_work(&podgov->idle_timer);
mutex_unlock(&df->lock);
- cancel_work_sync(&podgov->work);
+ stop_podgov_workers(podgov);
}
/*******************************************************************************
struct nvhost_device_data *pdata = platform_get_drvdata(d);
struct devfreq *df = pdata->power_manager;
struct podgov_info_rec *podgov;
- bool cancel = false;
if (!df)
return;
/* make sure the device is alive before doing any scaling */
- nvhost_module_busy(d);
+ nvhost_module_busy_noresume(d);
+
mutex_lock(&df->lock);
podgov = df->data;
trace_podgov_enabled(enable);
- if (enable && df->min_freq != df->max_freq) {
- podgov->enable = 1;
- } else {
- cancel = true;
- cancel_delayed_work(&podgov->idle_timer);
- podgov->enable = 0;
- podgov->adjustment_frequency = df->max_freq;
- podgov->adjustment_type = ADJUSTMENT_LOCAL;
- update_devfreq(df);
- }
+ /* bad configuration. quit. */
+ if (df->min_freq == df->max_freq)
+ goto exit_unlock;
+
+ /* store the enable information */
+ podgov->enable = enable;
+
+ /* skip local adjustment if we are enabling or the device is
+ * suspended */
+ if (enable || !pm_runtime_active(&d->dev))
+ goto exit_unlock;
+
+ /* full speed */
+ podgov->adjustment_frequency = df->max_freq;
+ podgov->adjustment_type = ADJUSTMENT_LOCAL;
+ update_devfreq(df);
mutex_unlock(&df->lock);
+
nvhost_module_idle(d);
- if (cancel)
- cancel_work_sync(&podgov->work);
+ stop_podgov_workers(podgov);
+
+ return;
+
+exit_unlock:
+ mutex_unlock(&df->lock);
+ nvhost_module_idle(d);
}
/*******************************************************************************
struct nvhost_device_data *pdata = platform_get_drvdata(d);
struct devfreq *df = pdata->power_manager;
struct podgov_info_rec *podgov;
- int cancel = 0;
+ int old_user;
if (!df)
return;
- nvhost_module_busy(d);
+ /* make sure the device is alive before doing any scaling */
+ nvhost_module_busy_noresume(d);
+
mutex_lock(&df->lock);
podgov = df->data;
trace_podgov_set_user_ctl(user);
- if (podgov->enable && user && !podgov->p_user) {
- cancel = 1;
- cancel_delayed_work(&podgov->idle_timer);
+ /* store the new user value */
+ old_user = podgov->p_user;
+ podgov->p_user = user;
- podgov->adjustment_frequency = podgov->p_freq_request;
- podgov->adjustment_type = ADJUSTMENT_LOCAL;
- update_devfreq(df);
- }
+ /* skip scaling, if scaling (or the whole device) is turned off
+ * - or the scaling already was in user mode */
+ if (!pm_runtime_active(&d->dev) || !podgov->enable ||
+ !(user && !old_user))
+ goto exit_unlock;
- podgov->p_user = user;
+ /* write request */
+ podgov->adjustment_frequency = podgov->p_freq_request;
+ podgov->adjustment_type = ADJUSTMENT_LOCAL;
+ update_devfreq(df);
mutex_unlock(&df->lock);
nvhost_module_idle(d);
- if (cancel)
- cancel_work_sync(&podgov->work);
+ stop_podgov_workers(podgov);
+
+ return;
+
+exit_unlock:
+ mutex_unlock(&df->lock);
+ nvhost_module_idle(d);
}
/*******************************************************************************
if (!df)
return;
- nvhost_module_busy(d);
+ /* make sure the device is alive before doing any scaling */
+ nvhost_module_busy_noresume(d);
+
mutex_lock(&df->lock);
podgov = df->data;
podgov->p_freq_request = freq_request;
- if (podgov->enable && podgov->p_user) {
-
+ /* update the request only if podgov is enabled, device is turned on
+ * and the scaling is in user mode */
+ if (podgov->enable && podgov->p_user &&
+ pm_runtime_active(&d->dev)) {
podgov->adjustment_frequency = freq_request;
podgov->adjustment_type = ADJUSTMENT_LOCAL;
update_devfreq(df);
}
if (podgov->last_event_type == DEVICE_IDLE &&
- df->previous_freq > df->min_freq)
+ df->previous_freq > df->min_freq &&
+ podgov->p_user == false)
notify_idle = 1;
mutex_unlock(&df->lock);
pdev = to_platform_device(df->dev.parent);
/* make sure the device is alive before doing any scaling */
- nvhost_module_busy(pdev);
+ nvhost_module_busy_noresume(pdev);
+ if (!pm_runtime_active(&pdev->dev)) {
+ nvhost_module_idle(pdev);
+ return 0;
+ }
+
mutex_lock(&podgov->power_manager->lock);
podgov->block--;