gpu: nvgpu: add QoS notifier for common clk framework

Define specific QoS notifier for common clk framework
and protect it with CONFIG_COMMON_CLK

This new API will first get min/max requirements from
pm_qos and set min/max freq values in devfreq

A call to update_devfreq() will then ensure that
new estimated frequency is clipped appropriately
between min and max values
This also ensures that frequency is set along with
all the book-keeping

Add below platform specific notifier callback and use it
with pm_qos_add_notifier()
int (*qos_notify)()
If qos_notify is set, then only register the callback

We currently support only one qos_id which is treated
as notifier for min frequency
Remove dependency on qos_id, and use appropriate QoS
APIs like pm_qos_read_min/max_bound()

Store devfreq's min/max frequency in struct gk20a
for reference

Bug 1772462

Change-Id: I63d6d17451d19c9d376b67df7db775b38929287d
Signed-off-by: Deepak Nibade <dnibade@nvidia.com>
Reviewed-on: http://git-master/r/1161161
Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com>
Tested-by: Terje Bergstrom <tbergstrom@nvidia.com>
This commit is contained in:
Deepak Nibade
2016-06-08 17:52:30 +05:30
committed by Terje Bergstrom
parent a445a678bc
commit 61d4e27607
5 changed files with 69 additions and 19 deletions

View File

@@ -815,6 +815,8 @@ struct gk20a {
wait_queue_head_t sw_irq_nonstall_last_handled_wq;
struct devfreq *devfreq;
u32 devfreq_max_freq;
u32 devfreq_min_freq;
struct gk20a_scale_profile *scale_profile;

View File

@@ -41,8 +41,44 @@
* has changed. The function calls postscaling callback if it is defined.
*/
static int gk20a_scale_qos_notify(struct notifier_block *nb,
unsigned long n, void *p)
#if defined(CONFIG_COMMON_CLK)
int gk20a_scale_qos_notify(struct notifier_block *nb,
unsigned long n, void *p)
{
struct gk20a_scale_profile *profile =
container_of(nb, struct gk20a_scale_profile,
qos_notify_block);
struct gk20a *g = get_gk20a(profile->dev);
struct devfreq *devfreq = g->devfreq;
s32 min_qos_freq, max_qos_freq;
if (!devfreq)
return NOTIFY_OK;
/* check for pm_qos min and max frequency requirement */
min_qos_freq = pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000;
max_qos_freq = pm_qos_read_max_bound(PM_QOS_GPU_FREQ_BOUNDS) * 1000;
mutex_lock(&devfreq->lock);
devfreq->min_freq = max_t(u32, g->devfreq_min_freq, min_qos_freq);
devfreq->max_freq = min_t(u32, g->devfreq_max_freq, max_qos_freq);
WARN_ON(devfreq->min_freq > devfreq->max_freq);
/*
* update_devfreq() will adjust the current (or newly estimated)
* frequency based on devfreq->min_freq/max_freq
*/
update_devfreq(devfreq);
mutex_unlock(&devfreq->lock);
return NOTIFY_OK;
}
#else
int gk20a_scale_qos_notify(struct notifier_block *nb,
unsigned long n, void *p)
{
struct gk20a_scale_profile *profile =
container_of(nb, struct gk20a_scale_profile,
@@ -57,7 +93,7 @@ static int gk20a_scale_qos_notify(struct notifier_block *nb,
/* get the frequency requirement. if devfreq is enabled, check if it
* has higher demand than qos */
freq = platform->clk_round_rate(profile->dev,
pm_qos_request(platform->qos_id));
(u32)pm_qos_read_min_bound(PM_QOS_GPU_FREQ_BOUNDS));
if (g->devfreq)
freq = max(g->devfreq->previous_freq, freq);
@@ -68,6 +104,7 @@ static int gk20a_scale_qos_notify(struct notifier_block *nb,
return NOTIFY_OK;
}
#endif
/*
* gk20a_scale_make_freq_table(profile)
@@ -311,16 +348,19 @@ void gk20a_scale_init(struct device *dev)
devfreq = NULL;
g->devfreq = devfreq;
g->devfreq_max_freq = devfreq->max_freq;
g->devfreq_min_freq = devfreq->min_freq;
}
/* Should we register QoS callback for this device? */
if (platform->qos_id < PM_QOS_NUM_CLASSES &&
platform->qos_id != PM_QOS_RESERVED &&
platform->postscale) {
if (platform->qos_notify) {
profile->qos_notify_block.notifier_call =
&gk20a_scale_qos_notify;
pm_qos_add_notifier(platform->qos_id,
&profile->qos_notify_block);
platform->qos_notify;
pm_qos_add_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
&profile->qos_notify_block);
pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
&profile->qos_notify_block);
}
return;
@@ -335,10 +375,10 @@ void gk20a_scale_exit(struct device *dev)
struct gk20a *g = platform->g;
int err;
if (platform->qos_id < PM_QOS_NUM_CLASSES &&
platform->qos_id != PM_QOS_RESERVED &&
platform->postscale) {
pm_qos_remove_notifier(platform->qos_id,
if (platform->qos_notify) {
pm_qos_remove_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
&g->scale_profile->qos_notify_block);
pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
&g->scale_profile->qos_notify_block);
}

View File

@@ -47,11 +47,18 @@ void gk20a_scale_notify_idle(struct device *);
void gk20a_scale_suspend(struct device *);
void gk20a_scale_resume(struct device *);
int gk20a_scale_qos_notify(struct notifier_block *nb,
unsigned long n, void *p);
#else
static inline void gk20a_scale_notify_busy(struct device *dev) {}
static inline void gk20a_scale_notify_idle(struct device *dev) {}
static inline void gk20a_scale_suspend(struct device *dev) {}
static inline void gk20a_scale_resume(struct device *dev) {}
static inline int gk20a_scale_qos_notify(struct notifier_block *nb,
unsigned long n, void *p)
{
return -ENOSYS;
}
#endif
#endif

View File

@@ -181,10 +181,11 @@ struct gk20a_platform {
* this governor to be used in scaling */
const char *devfreq_governor;
/* Quality of service id. If this is set, the scaling routines
* will register a callback to id. Each time we receive a new value,
* the postscale callback gets called. */
int qos_id;
/* Quality of service notifier callback. If this is set, the scaling
* routines will register a callback to Qos. Each time we receive
* a new value, this callback gets called. */
int (*qos_notify)(struct notifier_block *nb,
unsigned long n, void *p);
/* Called as part of debug dump. If the gpu gets hung, this function
* is responsible for delivering all necessary debug data of other

View File

@@ -896,7 +896,7 @@ struct gk20a_platform gk20a_tegra_platform = {
.prescale = gk20a_tegra_prescale,
.postscale = gk20a_tegra_postscale,
.devfreq_governor = "nvhost_podgov",
.qos_id = PM_QOS_GPU_FREQ_MIN,
.qos_notify = gk20a_scale_qos_notify,
.secure_alloc = gk20a_tegra_secure_alloc,
.secure_page_alloc = gk20a_tegra_secure_page_alloc,
@@ -956,7 +956,7 @@ struct gk20a_platform gm20b_tegra_platform = {
.prescale = gk20a_tegra_prescale,
.postscale = gk20a_tegra_postscale,
.devfreq_governor = "nvhost_podgov",
.qos_id = PM_QOS_GPU_FREQ_MIN,
.qos_notify = gk20a_scale_qos_notify,
.secure_alloc = gk20a_tegra_secure_alloc,
.secure_page_alloc = gk20a_tegra_secure_page_alloc,