mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: register pm_qos min & max frequency notifiers
nvpmodel updates the devfreq frequency limits as per power requirements
for specific chip. Clock arbiter ignored these limits and set clock
to maximum supported frequency which may lead to leaking power and
over heating.
Add support to get the devfreq limits by registering PM_QOS notifiers.
Note that with this patch we enable CONFIG_GK20A_PM_QOS when PM_DEVFREQ
is enabled. So it will be enabled for all supported kernels (4.9, 4.14
kernels continue to support this. For 5.10+ kernels notifiers added in
this patch will be used. Thermal framework related notifiers for kernels
after 4.14 will not be registered as those use downstream interfaces
that are not available.)
We maintain devfreq min/max limits in the scale profile and update those
in the notifier calls. We use these limits to clamp the frequency in the
clock arbiter.
Bug 3852824
Change-Id: I734a9fb080fee1a91e9b5da071b662dbd9a18682
Signed-off-by: Sagar Kamble <skamble@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2822686
(cherry picked from commit eacaf8cec2)
Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvgpu/+/2822682
Reviewed-by: svc-mobile-coverity <svc-mobile-coverity@nvidia.com>
Reviewed-by: Rajesh Devaraj <rdevaraj@nvidia.com>
Reviewed-by: Vaibhav Kachore <vkachore@nvidia.com>
GVS: Gerrit_Virtual_Submit <buildbot_gerritrpt@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
01eb416745
commit
9726ae3ba8
@@ -72,8 +72,8 @@ ifeq ($(CONFIG_PM_DEVFREQ),y)
|
|||||||
# Select this entry to enable gk20a scaling
|
# Select this entry to enable gk20a scaling
|
||||||
CONFIG_GK20A_DEVFREQ := y
|
CONFIG_GK20A_DEVFREQ := y
|
||||||
|
|
||||||
# Disable support to pass PM_QOS constraints to devfreq based scaling.
|
# Enable support to pass PM_QOS constraints to devfreq based scaling.
|
||||||
CONFIG_GK20A_PM_QOS := n
|
CONFIG_GK20A_PM_QOS := y
|
||||||
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
@@ -190,17 +190,11 @@ CONFIG_NVS_ROUND_ROBIN_SCHEDULER_DISABLE := y
|
|||||||
ccflags-y += -DCONFIG_NVS_ROUND_ROBIN_SCHEDULER_DISABLE
|
ccflags-y += -DCONFIG_NVS_ROUND_ROBIN_SCHEDULER_DISABLE
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(filter 4.9 4.14,$(patsubst -,$(space),$(NV_BUILD_KERNEL_OPTIONS))),)
|
|
||||||
# Enable support to pass PM_QOS constraints to devfreq based scaling.
|
|
||||||
CONFIG_GK20A_PM_QOS := y
|
|
||||||
endif
|
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# Set config for OOT module build
|
# Set config for OOT module build
|
||||||
ifeq ($(CONFIG_TEGRA_OOT_MODULE),m)
|
ifeq ($(CONFIG_TEGRA_OOT_MODULE),m)
|
||||||
CONFIG_GK20A_DEVFREQ := y
|
CONFIG_GK20A_DEVFREQ := y
|
||||||
CONFIG_GK20A_PM_QOS := n
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_TEGRA_HSIERRRPTINJ),y)
|
ifeq ($(CONFIG_TEGRA_HSIERRRPTINJ),y)
|
||||||
|
|||||||
@@ -24,6 +24,13 @@
|
|||||||
#include <nvgpu/clk_arb.h>
|
#include <nvgpu/clk_arb.h>
|
||||||
#include <nvgpu/pmu/clk/clk.h>
|
#include <nvgpu/pmu/clk/clk.h>
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/version.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
#include "os/linux/scale.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "clk_arb_gp10b.h"
|
#include "clk_arb_gp10b.h"
|
||||||
|
|
||||||
bool gp10b_check_clk_arb_support(struct gk20a *g)
|
bool gp10b_check_clk_arb_support(struct gk20a *g)
|
||||||
@@ -304,6 +311,12 @@ void gp10b_clk_arb_run_arbiter_cb(struct nvgpu_clk_arb *arb)
|
|||||||
gpc2clk_target = arb->gpc2clk_max;
|
gpc2clk_target = arb->gpc2clk_max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
gpc2clk_target = gk20a_scale_clamp_clk_target(g, gpc2clk_target);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
gpc2clk_session_target = gpc2clk_target;
|
gpc2clk_session_target = gpc2clk_target;
|
||||||
|
|
||||||
/* When DVFS is enabled, there is a mismatch between
|
/* When DVFS is enabled, there is a mismatch between
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2016-2021, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
|
||||||
*
|
*
|
||||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
* copy of this software and associated documentation files (the "Software"),
|
* copy of this software and associated documentation files (the "Software"),
|
||||||
@@ -27,6 +27,13 @@
|
|||||||
#include <nvgpu/boardobjgrp_e255.h>
|
#include <nvgpu/boardobjgrp_e255.h>
|
||||||
#include <nvgpu/pmu/perf.h>
|
#include <nvgpu/pmu/perf.h>
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#include <linux/version.h>
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
#include "os/linux/scale.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "clk_arb_gv100.h"
|
#include "clk_arb_gv100.h"
|
||||||
|
|
||||||
bool gv100_check_clk_arb_support(struct gk20a *g)
|
bool gv100_check_clk_arb_support(struct gk20a *g)
|
||||||
@@ -427,6 +434,12 @@ void gv100_clk_arb_run_arbiter_cb(struct nvgpu_clk_arb *arb)
|
|||||||
gpc2clk_target = arb->gpc_cap_clkmhz;
|
gpc2clk_target = arb->gpc_cap_clkmhz;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef __KERNEL__
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
gpc2clk_target = gk20a_scale_clamp_clk_target(g, gpc2clk_target);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
vf_point.gpc_mhz = gpc2clk_target;
|
vf_point.gpc_mhz = gpc2clk_target;
|
||||||
(void)nvgpu_clk_arb_find_slave_points(arb, &vf_point);
|
(void)nvgpu_clk_arb_find_slave_points(arb, &vf_point);
|
||||||
if (status != 0) {
|
if (status != 0) {
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include <linux/dma-mapping.h>
|
#include <linux/dma-mapping.h>
|
||||||
#include <linux/mm.h>
|
#include <linux/mm.h>
|
||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
|
#include <linux/version.h>
|
||||||
#include <linux/pm_runtime.h>
|
#include <linux/pm_runtime.h>
|
||||||
#include <linux/of_platform.h>
|
#include <linux/of_platform.h>
|
||||||
#include <uapi/linux/nvgpu.h>
|
#include <uapi/linux/nvgpu.h>
|
||||||
@@ -205,7 +206,12 @@ static void nvgpu_init_pm_vars(struct gk20a *g)
|
|||||||
/* disable devfreq for pre-silicon */
|
/* disable devfreq for pre-silicon */
|
||||||
if (!nvgpu_platform_is_silicon(g)) {
|
if (!nvgpu_platform_is_silicon(g)) {
|
||||||
platform->devfreq_governor = NULL;
|
platform->devfreq_governor = NULL;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
platform->qos_min_notify = NULL;
|
||||||
|
platform->qos_max_notify = NULL;
|
||||||
|
#else
|
||||||
platform->qos_notify = NULL;
|
platform->qos_notify = NULL;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
nvgpu_set_enabled(g, NVGPU_GPU_CAN_ELCG,
|
nvgpu_set_enabled(g, NVGPU_GPU_CAN_ELCG,
|
||||||
@@ -228,7 +234,12 @@ static void nvgpu_init_pm_vars(struct gk20a *g)
|
|||||||
platform->can_railgate_init = false;
|
platform->can_railgate_init = false;
|
||||||
/* Disable frequency scaling for hypervisor platforms */
|
/* Disable frequency scaling for hypervisor platforms */
|
||||||
platform->devfreq_governor = NULL;
|
platform->devfreq_governor = NULL;
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
platform->qos_min_notify = NULL;
|
||||||
|
platform->qos_max_notify = NULL;
|
||||||
|
#else
|
||||||
platform->qos_notify = NULL;
|
platform->qos_notify = NULL;
|
||||||
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* Always enable railgating on simulation platform */
|
/* Always enable railgating on simulation platform */
|
||||||
platform->can_railgate_init = nvgpu_platform_is_simulation(g) ?
|
platform->can_railgate_init = nvgpu_platform_is_simulation(g) ?
|
||||||
|
|||||||
@@ -775,7 +775,12 @@ struct gk20a_platform ga10b_tegra_platform = {
|
|||||||
.postscale = ga10b_tegra_postscale,
|
.postscale = ga10b_tegra_postscale,
|
||||||
.devfreq_governor = "nvhost_podgov",
|
.devfreq_governor = "nvhost_podgov",
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
.qos_min_notify = gk20a_scale_qos_min_notify,
|
||||||
|
.qos_max_notify = gk20a_scale_qos_max_notify,
|
||||||
|
#else
|
||||||
.qos_notify = gk20a_scale_qos_notify,
|
.qos_notify = gk20a_scale_qos_notify,
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
||||||
|
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
#define _GK20A_PLATFORM_H_
|
#define _GK20A_PLATFORM_H_
|
||||||
|
|
||||||
#include <linux/device.h>
|
#include <linux/device.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
#include <nvgpu/lock.h>
|
#include <nvgpu/lock.h>
|
||||||
#include <nvgpu/gk20a.h>
|
#include <nvgpu/gk20a.h>
|
||||||
@@ -269,11 +270,21 @@ struct gk20a_platform {
|
|||||||
* this governor to be used in scaling */
|
* this governor to be used in scaling */
|
||||||
const char *devfreq_governor;
|
const char *devfreq_governor;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
/* Quality of service notifier callback for min frequency limit. */
|
||||||
|
int (*qos_min_notify)(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p);
|
||||||
|
|
||||||
|
/* Quality of service notifier callback for max frequency limit. */
|
||||||
|
int (*qos_max_notify)(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p);
|
||||||
|
#else
|
||||||
/* Quality of service notifier callback. If this is set, the scaling
|
/* Quality of service notifier callback. If this is set, the scaling
|
||||||
* routines will register a callback to Qos. Each time we receive
|
* routines will register a callback to Qos. Each time we receive
|
||||||
* a new value, this callback gets called. */
|
* a new value, this callback gets called. */
|
||||||
int (*qos_notify)(struct notifier_block *nb,
|
int (*qos_notify)(struct notifier_block *nb,
|
||||||
unsigned long n, void *p);
|
unsigned long n, void *p);
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
/* Called as part of debug dump. If the gpu gets hung, this function
|
/* Called as part of debug dump. If the gpu gets hung, this function
|
||||||
* is responsible for delivering all necessary debug data of other
|
* is responsible for delivering all necessary debug data of other
|
||||||
|
|||||||
@@ -1065,7 +1065,12 @@ struct gk20a_platform gm20b_tegra_platform = {
|
|||||||
.postscale = gm20b_tegra_postscale,
|
.postscale = gm20b_tegra_postscale,
|
||||||
#endif
|
#endif
|
||||||
.devfreq_governor = "nvhost_podgov",
|
.devfreq_governor = "nvhost_podgov",
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
.qos_min_notify = gk20a_scale_qos_min_notify,
|
||||||
|
.qos_max_notify = gk20a_scale_qos_max_notify,
|
||||||
|
#else
|
||||||
.qos_notify = gk20a_scale_qos_notify,
|
.qos_notify = gk20a_scale_qos_notify,
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
||||||
|
|
||||||
|
|||||||
@@ -301,7 +301,12 @@ struct gk20a_platform gv11b_tegra_platform = {
|
|||||||
.postscale = gp10b_tegra_postscale,
|
.postscale = gp10b_tegra_postscale,
|
||||||
.devfreq_governor = "nvhost_podgov",
|
.devfreq_governor = "nvhost_podgov",
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
.qos_min_notify = gk20a_scale_qos_min_notify,
|
||||||
|
.qos_max_notify = gk20a_scale_qos_max_notify,
|
||||||
|
#else
|
||||||
.qos_notify = gk20a_scale_qos_notify,
|
.qos_notify = gk20a_scale_qos_notify,
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
.dump_platform_dependencies = gk20a_tegra_debug_dump,
|
||||||
|
|
||||||
|
|||||||
@@ -49,6 +49,82 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#if defined(CONFIG_GK20A_PM_QOS) && defined(CONFIG_COMMON_CLK)
|
#if defined(CONFIG_GK20A_PM_QOS) && defined(CONFIG_COMMON_CLK)
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
int gk20a_scale_qos_min_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p)
|
||||||
|
{
|
||||||
|
struct gk20a_scale_profile *profile =
|
||||||
|
container_of(nb, struct gk20a_scale_profile,
|
||||||
|
qos_min_notify_block);
|
||||||
|
struct gk20a *g = get_gk20a(profile->dev);
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
|
struct devfreq *devfreq = l->devfreq;
|
||||||
|
|
||||||
|
if (!devfreq)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
nvgpu_mutex_acquire(&profile->lock);
|
||||||
|
|
||||||
|
profile->qos_min_freq = (unsigned long)n * 1000UL;
|
||||||
|
|
||||||
|
nvgpu_mutex_release(&profile->lock);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int gk20a_scale_qos_max_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p)
|
||||||
|
{
|
||||||
|
struct gk20a_scale_profile *profile =
|
||||||
|
container_of(nb, struct gk20a_scale_profile,
|
||||||
|
qos_max_notify_block);
|
||||||
|
struct gk20a *g = get_gk20a(profile->dev);
|
||||||
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
|
struct devfreq *devfreq = l->devfreq;
|
||||||
|
|
||||||
|
if (!devfreq)
|
||||||
|
return NOTIFY_OK;
|
||||||
|
|
||||||
|
nvgpu_mutex_acquire(&profile->lock);
|
||||||
|
|
||||||
|
profile->qos_max_freq = (unsigned long)n * 1000UL;
|
||||||
|
|
||||||
|
nvgpu_mutex_release(&profile->lock);
|
||||||
|
|
||||||
|
return NOTIFY_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
u16 gk20a_scale_clamp_clk_target(struct gk20a *g,
|
||||||
|
u16 gpc2clk_target)
|
||||||
|
{
|
||||||
|
struct gk20a_scale_profile *profile = g->scale_profile;
|
||||||
|
u16 min_freq_mhz, max_freq_mhz;
|
||||||
|
|
||||||
|
if (!profile)
|
||||||
|
return gpc2clk_target;
|
||||||
|
|
||||||
|
nvgpu_mutex_acquire(&profile->lock);
|
||||||
|
|
||||||
|
min_freq_mhz = (u16) (profile->qos_min_freq / 1000000UL);
|
||||||
|
max_freq_mhz = (u16) (profile->qos_max_freq / 1000000UL);
|
||||||
|
|
||||||
|
nvgpu_log_info(g, "target %u qos_min %u qos_max %u", gpc2clk_target,
|
||||||
|
min_freq_mhz, max_freq_mhz);
|
||||||
|
|
||||||
|
if (gpc2clk_target < min_freq_mhz) {
|
||||||
|
gpc2clk_target = min_freq_mhz;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gpc2clk_target > max_freq_mhz) {
|
||||||
|
gpc2clk_target = max_freq_mhz;
|
||||||
|
}
|
||||||
|
|
||||||
|
nvgpu_mutex_release(&profile->lock);
|
||||||
|
|
||||||
|
return gpc2clk_target;
|
||||||
|
}
|
||||||
|
#else
|
||||||
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
||||||
unsigned long n, void *p)
|
unsigned long n, void *p)
|
||||||
{
|
{
|
||||||
@@ -81,6 +157,7 @@ int gk20a_scale_qos_notify(struct notifier_block *nb,
|
|||||||
|
|
||||||
return NOTIFY_OK;
|
return NOTIFY_OK;
|
||||||
}
|
}
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
#elif defined(CONFIG_GK20A_PM_QOS)
|
#elif defined(CONFIG_GK20A_PM_QOS)
|
||||||
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
||||||
unsigned long n, void *p)
|
unsigned long n, void *p)
|
||||||
@@ -397,21 +474,34 @@ void gk20a_scale_init(struct device *dev)
|
|||||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||||
struct thermal_cooling_device *cooling;
|
struct thermal_cooling_device *cooling;
|
||||||
#endif
|
#endif
|
||||||
|
struct devfreq *devfreq;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (g->scale_profile)
|
if (g->scale_profile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!platform->devfreq_governor && !platform->qos_notify)
|
if (!platform->devfreq_governor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
if (!platform->qos_min_notify && !platform->qos_max_notify) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!platform->qos_notify) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
profile = nvgpu_kzalloc(g, sizeof(*profile));
|
profile = nvgpu_kzalloc(g, sizeof(*profile));
|
||||||
if (!profile)
|
if (!profile)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
profile->dev = dev;
|
profile->dev = dev;
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||||
profile->dev_stat.busy = false;
|
profile->dev_stat.busy = false;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Create frequency table */
|
/* Create frequency table */
|
||||||
@@ -427,7 +517,6 @@ void gk20a_scale_init(struct device *dev)
|
|||||||
g->scale_profile = profile;
|
g->scale_profile = profile;
|
||||||
|
|
||||||
if (platform->devfreq_governor) {
|
if (platform->devfreq_governor) {
|
||||||
struct devfreq *devfreq;
|
|
||||||
int error = 0;
|
int error = 0;
|
||||||
|
|
||||||
register_gpu_opp(dev);
|
register_gpu_opp(dev);
|
||||||
@@ -474,6 +563,35 @@ void gk20a_scale_init(struct device *dev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
nvgpu_mutex_init(&profile->lock);
|
||||||
|
|
||||||
|
/* Should we register min frequency QoS callback for this device? */
|
||||||
|
if (devfreq && platform->qos_min_notify) {
|
||||||
|
profile->qos_min_notify_block.notifier_call =
|
||||||
|
platform->qos_min_notify;
|
||||||
|
|
||||||
|
err = dev_pm_qos_add_notifier(devfreq->dev.parent,
|
||||||
|
&profile->qos_min_notify_block,
|
||||||
|
DEV_PM_QOS_MIN_FREQUENCY);
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(g, "failed to add min freq notifier %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Should we register max frequency QoS callback for this device? */
|
||||||
|
if (devfreq && platform->qos_max_notify) {
|
||||||
|
profile->qos_max_notify_block.notifier_call =
|
||||||
|
platform->qos_max_notify;
|
||||||
|
|
||||||
|
err = dev_pm_qos_add_notifier(devfreq->dev.parent,
|
||||||
|
&profile->qos_max_notify_block,
|
||||||
|
DEV_PM_QOS_MAX_FREQUENCY);
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(g, "failed to add max freq notifier %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
/* Should we register QoS callback for this device? */
|
/* Should we register QoS callback for this device? */
|
||||||
if (platform->qos_notify) {
|
if (platform->qos_notify) {
|
||||||
profile->qos_notify_block.notifier_call =
|
profile->qos_notify_block.notifier_call =
|
||||||
@@ -484,6 +602,7 @@ void gk20a_scale_init(struct device *dev)
|
|||||||
pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
||||||
&profile->qos_notify_block);
|
&profile->qos_notify_block);
|
||||||
}
|
}
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@@ -497,18 +616,54 @@ void gk20a_scale_exit(struct device *dev)
|
|||||||
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
struct gk20a_platform *platform = dev_get_drvdata(dev);
|
||||||
struct gk20a *g = platform->g;
|
struct gk20a *g = platform->g;
|
||||||
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
struct nvgpu_os_linux *l = nvgpu_os_linux_from_gk20a(g);
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
struct devfreq *devfreq = l->devfreq;
|
||||||
|
struct gk20a_scale_profile *profile;
|
||||||
|
#endif
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
if (!platform->devfreq_governor && !platform->qos_notify)
|
if (!platform->devfreq_governor)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
if (!platform->qos_min_notify && !platform->qos_max_notify) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (!platform->qos_notify) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
if (devfreq) {
|
||||||
|
profile = g->scale_profile;
|
||||||
|
|
||||||
|
err = dev_pm_qos_remove_notifier(devfreq->dev.parent,
|
||||||
|
&profile->qos_min_notify_block,
|
||||||
|
DEV_PM_QOS_MIN_FREQUENCY);
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(g, "failed to remove min freq notifier %d", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
err = dev_pm_qos_remove_notifier(devfreq->dev.parent,
|
||||||
|
&profile->qos_max_notify_block,
|
||||||
|
DEV_PM_QOS_MAX_FREQUENCY);
|
||||||
|
if (err) {
|
||||||
|
nvgpu_err(g, "failed to remove max freq notifier %d", err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
nvgpu_mutex_destroy(&profile->lock);
|
||||||
|
#else
|
||||||
if (platform->qos_notify) {
|
if (platform->qos_notify) {
|
||||||
pm_qos_remove_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
pm_qos_remove_min_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
||||||
&g->scale_profile->qos_notify_block);
|
&g->scale_profile->qos_notify_block);
|
||||||
pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
pm_qos_remove_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
|
||||||
&g->scale_profile->qos_notify_block);
|
&g->scale_profile->qos_notify_block);
|
||||||
}
|
}
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef CONFIG_DEVFREQ_THERMAL
|
#ifdef CONFIG_DEVFREQ_THERMAL
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* gk20a clock scaling profile
|
* gk20a clock scaling profile
|
||||||
*
|
*
|
||||||
* Copyright (c) 2013-2016, NVIDIA Corporation. All rights reserved.
|
* Copyright (c) 2013-2022, NVIDIA Corporation. All rights reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -20,6 +20,7 @@
|
|||||||
#define GK20A_SCALE_H
|
#define GK20A_SCALE_H
|
||||||
|
|
||||||
#include <linux/devfreq.h>
|
#include <linux/devfreq.h>
|
||||||
|
#include <linux/version.h>
|
||||||
|
|
||||||
struct clk;
|
struct clk;
|
||||||
|
|
||||||
@@ -29,9 +30,12 @@ struct gk20a_scale_profile {
|
|||||||
struct devfreq_dev_profile devfreq_profile;
|
struct devfreq_dev_profile devfreq_profile;
|
||||||
struct devfreq_dev_status dev_stat;
|
struct devfreq_dev_status dev_stat;
|
||||||
struct notifier_block qos_notify_block;
|
struct notifier_block qos_notify_block;
|
||||||
|
struct notifier_block qos_min_notify_block;
|
||||||
|
struct notifier_block qos_max_notify_block;
|
||||||
unsigned long qos_min_freq;
|
unsigned long qos_min_freq;
|
||||||
unsigned long qos_max_freq;
|
unsigned long qos_max_freq;
|
||||||
void *private_data;
|
void *private_data;
|
||||||
|
struct nvgpu_mutex lock;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Initialization and de-initialization for module */
|
/* Initialization and de-initialization for module */
|
||||||
@@ -49,18 +53,49 @@ void gk20a_scale_notify_idle(struct device *);
|
|||||||
|
|
||||||
void gk20a_scale_suspend(struct device *);
|
void gk20a_scale_suspend(struct device *);
|
||||||
void gk20a_scale_resume(struct device *);
|
void gk20a_scale_resume(struct device *);
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
int gk20a_scale_qos_min_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p);
|
||||||
|
int gk20a_scale_qos_max_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p);
|
||||||
|
u16 gk20a_scale_clamp_clk_target(struct gk20a *g,
|
||||||
|
u16 gpc2clk_target);
|
||||||
|
#else
|
||||||
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
int gk20a_scale_qos_notify(struct notifier_block *nb,
|
||||||
unsigned long n, void *p);
|
unsigned long n, void *p);
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
#else
|
#else
|
||||||
static inline void gk20a_scale_notify_busy(struct device *dev) {}
|
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_notify_idle(struct device *dev) {}
|
||||||
static inline void gk20a_scale_suspend(struct device *dev) {}
|
static inline void gk20a_scale_suspend(struct device *dev) {}
|
||||||
static inline void gk20a_scale_resume(struct device *dev) {}
|
static inline void gk20a_scale_resume(struct device *dev) {}
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0)
|
||||||
|
static inline int gk20a_scale_qos_min_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
static inline int gk20a_scale_qos_max_notify(struct notifier_block *nb,
|
||||||
|
unsigned long n, void *p)
|
||||||
|
{
|
||||||
|
return -ENOSYS;
|
||||||
|
}
|
||||||
|
static inline u16 gk20a_scale_clamp_clk_target(struct gk20a *g,
|
||||||
|
u16 gpc2clk_target)
|
||||||
|
{
|
||||||
|
return gpc2clk_target;
|
||||||
|
}
|
||||||
|
#else
|
||||||
static inline int gk20a_scale_qos_notify(struct notifier_block *nb,
|
static inline int gk20a_scale_qos_notify(struct notifier_block *nb,
|
||||||
unsigned long n, void *p)
|
unsigned long n, void *p)
|
||||||
{
|
{
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
#endif /* LINUX_VERSION_CODE >= KERNEL_VERSION(5, 10, 0) */
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -247,6 +247,8 @@ done:
|
|||||||
|
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||||
|
|
||||||
static int vgpu_qos_notify(struct notifier_block *nb,
|
static int vgpu_qos_notify(struct notifier_block *nb,
|
||||||
unsigned long n, void *data)
|
unsigned long n, void *data)
|
||||||
{
|
{
|
||||||
@@ -299,6 +301,7 @@ static void vgpu_pm_qos_remove(struct device *dev)
|
|||||||
g->scale_profile = NULL;
|
g->scale_profile = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static int vgpu_pm_init(struct device *dev)
|
static int vgpu_pm_init(struct device *dev)
|
||||||
@@ -317,9 +320,11 @@ static int vgpu_pm_init(struct device *dev)
|
|||||||
gk20a_scale_init(dev);
|
gk20a_scale_init(dev);
|
||||||
|
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||||
err = vgpu_pm_qos_init(dev);
|
err = vgpu_pm_qos_init(dev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
@@ -519,7 +524,9 @@ int vgpu_remove(struct platform_device *pdev)
|
|||||||
nvgpu_mutex_destroy(&l->dmabuf_priv_list_lock);
|
nvgpu_mutex_destroy(&l->dmabuf_priv_list_lock);
|
||||||
|
|
||||||
#ifdef CONFIG_GK20A_PM_QOS
|
#ifdef CONFIG_GK20A_PM_QOS
|
||||||
|
#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 10, 0)
|
||||||
vgpu_pm_qos_remove(dev);
|
vgpu_pm_qos_remove(dev);
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
if (g->remove_support)
|
if (g->remove_support)
|
||||||
g->remove_support(g);
|
g->remove_support(g);
|
||||||
|
|||||||
Reference in New Issue
Block a user