From 61d4e27607c0ce4080ef02daeb09200181662337 Mon Sep 17 00:00:00 2001 From: Deepak Nibade Date: Wed, 8 Jun 2016 17:52:30 +0530 Subject: 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 Reviewed-on: http://git-master/r/1161161 Reviewed-by: Terje Bergstrom Tested-by: Terje Bergstrom --- drivers/gpu/nvgpu/gk20a/gk20a.h | 2 + drivers/gpu/nvgpu/gk20a/gk20a_scale.c | 66 +++++++++++++++++++++----- drivers/gpu/nvgpu/gk20a/gk20a_scale.h | 7 +++ drivers/gpu/nvgpu/gk20a/platform_gk20a.h | 9 ++-- drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c | 4 +- 5 files changed, 69 insertions(+), 19 deletions(-) (limited to 'drivers/gpu/nvgpu') diff --git a/drivers/gpu/nvgpu/gk20a/gk20a.h b/drivers/gpu/nvgpu/gk20a/gk20a.h index 997da125..9acaa007 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a.h @@ -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; diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c b/drivers/gpu/nvgpu/gk20a/gk20a_scale.c index 6d60d899..eeabd919 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_scale.c +++ b/drivers/gpu/nvgpu/gk20a/gk20a_scale.c @@ -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); } diff --git a/drivers/gpu/nvgpu/gk20a/gk20a_scale.h b/drivers/gpu/nvgpu/gk20a/gk20a_scale.h index 5c8618eb..025c2070 100644 --- a/drivers/gpu/nvgpu/gk20a/gk20a_scale.h +++ b/drivers/gpu/nvgpu/gk20a/gk20a_scale.h @@ -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 diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h index 66d97915..a753201b 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a.h +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a.h @@ -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 diff --git a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c index 618b1716..b8f70ab3 100644 --- a/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c +++ b/drivers/gpu/nvgpu/gk20a/platform_gk20a_tegra.c @@ -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, -- cgit v1.2.2