Merge "msm: kgsl: Do a midframe sampling of power stats if enabled"
This commit is contained in:
commit
2300bb89c0
5 changed files with 103 additions and 0 deletions
|
@ -143,6 +143,12 @@ Optional Properties:
|
|||
Specify the name of GPU temperature sensor. This name will be used
|
||||
to get the temperature from the thermal driver API.
|
||||
|
||||
- qcom,enable-midframe-timer:
|
||||
Boolean. Enables the use of midframe sampling timer. This timer
|
||||
samples the GPU powerstats if the cmdbatch expiry takes longer than
|
||||
the threshold set by KGSL_GOVERNOR_CALL_INTERVAL. Enable only if
|
||||
target has NAP state enabled.
|
||||
|
||||
GPU Quirks:
|
||||
- qcom,gpu-quirk-two-pass-use-wfi:
|
||||
Signal the GPU to set Set TWOPASSUSEWFI bit in
|
||||
|
|
|
@ -604,6 +604,16 @@ static int sendcmd(struct adreno_device *adreno_dev,
|
|||
if (!test_and_set_bit(ADRENO_DISPATCHER_ACTIVE,
|
||||
&dispatcher->priv))
|
||||
reinit_completion(&dispatcher->idle_gate);
|
||||
|
||||
/*
|
||||
* We update power stats generally at the expire of
|
||||
* cmdbatch. In cases where the cmdbatch takes a long
|
||||
* time to finish, it will delay power stats update,
|
||||
* in effect it will delay DCVS decision. Start a
|
||||
* timer to update power state on expire of this timer.
|
||||
*/
|
||||
kgsl_pwrscale_midframe_timer_restart(device);
|
||||
|
||||
} else {
|
||||
kgsl_active_count_put(device);
|
||||
clear_bit(ADRENO_DISPATCHER_POWER, &dispatcher->priv);
|
||||
|
|
|
@ -2355,6 +2355,7 @@ static int _init(struct kgsl_device *device)
|
|||
case KGSL_STATE_ACTIVE:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
del_timer_sync(&device->idle_timer);
|
||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||
device->ftbl->stop(device);
|
||||
/* fall through */
|
||||
case KGSL_STATE_AWARE:
|
||||
|
@ -2462,6 +2463,7 @@ _aware(struct kgsl_device *device)
|
|||
case KGSL_STATE_ACTIVE:
|
||||
kgsl_pwrctrl_irq(device, KGSL_PWRFLAGS_OFF);
|
||||
del_timer_sync(&device->idle_timer);
|
||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||
break;
|
||||
case KGSL_STATE_SLUMBER:
|
||||
status = kgsl_pwrctrl_enable(device);
|
||||
|
@ -2486,6 +2488,8 @@ _nap(struct kgsl_device *device)
|
|||
return -EBUSY;
|
||||
}
|
||||
|
||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||
|
||||
/*
|
||||
* Read HW busy counters before going to NAP state.
|
||||
* The data might be used by power scale governors
|
||||
|
@ -2522,6 +2526,7 @@ _slumber(struct kgsl_device *device)
|
|||
/* fall through */
|
||||
case KGSL_STATE_NAP:
|
||||
del_timer_sync(&device->idle_timer);
|
||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||
if (device->pwrctrl.thermal_cycle == CYCLE_ACTIVE) {
|
||||
device->pwrctrl.thermal_cycle = CYCLE_ENABLE;
|
||||
del_timer_sync(&device->pwrctrl.thermal_timer);
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <linux/export.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/hrtimer.h>
|
||||
|
||||
#include "kgsl.h"
|
||||
#include "kgsl_pwrscale.h"
|
||||
|
@ -37,6 +38,18 @@ static struct kgsl_popp popp_param[POPP_MAX] = {
|
|||
{0, 0},
|
||||
};
|
||||
|
||||
/**
|
||||
* struct kgsl_midframe_info - midframe power stats sampling info
|
||||
* @timer - midframe sampling timer
|
||||
* @timer_check_ws - Updates powerstats on midframe expiry
|
||||
* @device - pointer to kgsl_device
|
||||
*/
|
||||
static struct kgsl_midframe_info {
|
||||
struct hrtimer timer;
|
||||
struct work_struct timer_check_ws;
|
||||
struct kgsl_device *device;
|
||||
} *kgsl_midframe = NULL;
|
||||
|
||||
static void do_devfreq_suspend(struct work_struct *work);
|
||||
static void do_devfreq_resume(struct work_struct *work);
|
||||
static void do_devfreq_notify(struct work_struct *work);
|
||||
|
@ -183,9 +196,57 @@ void kgsl_pwrscale_update(struct kgsl_device *device)
|
|||
if (device->state != KGSL_STATE_SLUMBER)
|
||||
queue_work(device->pwrscale.devfreq_wq,
|
||||
&device->pwrscale.devfreq_notify_ws);
|
||||
|
||||
kgsl_pwrscale_midframe_timer_restart(device);
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrscale_update);
|
||||
|
||||
void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device)
|
||||
{
|
||||
if (kgsl_midframe) {
|
||||
WARN_ON(!mutex_is_locked(&device->mutex));
|
||||
|
||||
/* If the timer is already running, stop it */
|
||||
if (hrtimer_active(&kgsl_midframe->timer))
|
||||
hrtimer_cancel(
|
||||
&kgsl_midframe->timer);
|
||||
|
||||
hrtimer_start(&kgsl_midframe->timer,
|
||||
ns_to_ktime(KGSL_GOVERNOR_CALL_INTERVAL
|
||||
* NSEC_PER_USEC), HRTIMER_MODE_REL);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_restart);
|
||||
|
||||
void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device)
|
||||
{
|
||||
if (kgsl_midframe) {
|
||||
WARN_ON(!mutex_is_locked(&device->mutex));
|
||||
hrtimer_cancel(&kgsl_midframe->timer);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(kgsl_pwrscale_midframe_timer_cancel);
|
||||
|
||||
static void kgsl_pwrscale_midframe_timer_check(struct work_struct *work)
|
||||
{
|
||||
struct kgsl_device *device = kgsl_midframe->device;
|
||||
|
||||
mutex_lock(&device->mutex);
|
||||
if (device->state == KGSL_STATE_ACTIVE)
|
||||
kgsl_pwrscale_update(device);
|
||||
mutex_unlock(&device->mutex);
|
||||
}
|
||||
|
||||
static enum hrtimer_restart kgsl_pwrscale_midframe_timer(struct hrtimer *timer)
|
||||
{
|
||||
struct kgsl_device *device = kgsl_midframe->device;
|
||||
|
||||
queue_work(device->pwrscale.devfreq_wq,
|
||||
&kgsl_midframe->timer_check_ws);
|
||||
|
||||
return HRTIMER_NORESTART;
|
||||
}
|
||||
|
||||
/*
|
||||
* kgsl_pwrscale_disable - temporarily disable the governor
|
||||
* @device: The device
|
||||
|
@ -852,6 +913,17 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
|
|||
data->bin.ctxt_aware_busy_penalty = 12000;
|
||||
}
|
||||
|
||||
if (of_property_read_bool(device->pdev->dev.of_node,
|
||||
"qcom,enable-midframe-timer")) {
|
||||
kgsl_midframe = kzalloc(
|
||||
sizeof(struct kgsl_midframe_info), GFP_KERNEL);
|
||||
hrtimer_init(&kgsl_midframe->timer,
|
||||
CLOCK_MONOTONIC, HRTIMER_MODE_REL);
|
||||
kgsl_midframe->timer.function =
|
||||
kgsl_pwrscale_midframe_timer;
|
||||
kgsl_midframe->device = device;
|
||||
}
|
||||
|
||||
/*
|
||||
* If there is a separate GX power rail, allow
|
||||
* independent modification to its voltage through
|
||||
|
@ -900,6 +972,9 @@ int kgsl_pwrscale_init(struct device *dev, const char *governor)
|
|||
INIT_WORK(&pwrscale->devfreq_suspend_ws, do_devfreq_suspend);
|
||||
INIT_WORK(&pwrscale->devfreq_resume_ws, do_devfreq_resume);
|
||||
INIT_WORK(&pwrscale->devfreq_notify_ws, do_devfreq_notify);
|
||||
if (kgsl_midframe)
|
||||
INIT_WORK(&kgsl_midframe->timer_check_ws,
|
||||
kgsl_pwrscale_midframe_timer_check);
|
||||
|
||||
pwrscale->next_governor_call = ktime_add_us(ktime_get(),
|
||||
KGSL_GOVERNOR_CALL_INTERVAL);
|
||||
|
@ -940,9 +1015,13 @@ void kgsl_pwrscale_close(struct kgsl_device *device)
|
|||
pwrscale = &device->pwrscale;
|
||||
if (!pwrscale->devfreqptr)
|
||||
return;
|
||||
|
||||
kgsl_pwrscale_midframe_timer_cancel(device);
|
||||
flush_workqueue(pwrscale->devfreq_wq);
|
||||
destroy_workqueue(pwrscale->devfreq_wq);
|
||||
devfreq_remove_device(device->pwrscale.devfreqptr);
|
||||
kfree(kgsl_midframe);
|
||||
kgsl_midframe = NULL;
|
||||
device->pwrscale.devfreqptr = NULL;
|
||||
srcu_cleanup_notifier_head(&device->pwrscale.nh);
|
||||
for (i = 0; i < KGSL_PWREVENT_MAX; i++)
|
||||
|
|
|
@ -122,6 +122,9 @@ void kgsl_pwrscale_busy(struct kgsl_device *device);
|
|||
void kgsl_pwrscale_sleep(struct kgsl_device *device);
|
||||
void kgsl_pwrscale_wake(struct kgsl_device *device);
|
||||
|
||||
void kgsl_pwrscale_midframe_timer_restart(struct kgsl_device *device);
|
||||
void kgsl_pwrscale_midframe_timer_cancel(struct kgsl_device *device);
|
||||
|
||||
void kgsl_pwrscale_enable(struct kgsl_device *device);
|
||||
void kgsl_pwrscale_disable(struct kgsl_device *device, bool turbo);
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue