mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-24 10:34:43 +03:00
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:
committed by
Terje Bergstrom
parent
a445a678bc
commit
61d4e27607
@@ -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;
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user