mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 17:36:20 +03:00
gpu: nvgpu: vgpu: add devfreq support
Add devfreq governor support in order to allow frequency scaling in virtualization config. GPU clock frequency operations are re-directed to the server over RPC. Bug 200237433 Change-Id: I1c8e565a4fff36d3456dc72ebb20795b7822650e Signed-off-by: Sachit Kadle <skadle@nvidia.com> Reviewed-on: http://git-master/r/1295542 (cherry picked from commit d5c956fc06697eda3829c67cb22987e538213b29) Reviewed-on: http://git-master/r/1280968 (cherry picked from commit 25e2b3cf7cb5559a6849c0024d42c157564a9be2) Reviewed-on: http://git-master/r/1321835 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
This commit is contained in:
committed by
mobile promotions
parent
0eb5255e54
commit
f871b52fd3
@@ -106,6 +106,7 @@ nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \
|
|||||||
vgpu/dbg_vgpu.o \
|
vgpu/dbg_vgpu.o \
|
||||||
vgpu/fecs_trace_vgpu.o \
|
vgpu/fecs_trace_vgpu.o \
|
||||||
vgpu/tsg_vgpu.o \
|
vgpu/tsg_vgpu.o \
|
||||||
|
vgpu/clk_vgpu.o \
|
||||||
vgpu/css_vgpu.o \
|
vgpu/css_vgpu.o \
|
||||||
vgpu/gk20a/vgpu_hal_gk20a.o \
|
vgpu/gk20a/vgpu_hal_gk20a.o \
|
||||||
vgpu/gk20a/vgpu_gr_gk20a.o \
|
vgpu/gk20a/vgpu_gr_gk20a.o \
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Tegra Virtualized GPU Platform Interface
|
* Tegra Virtualized GPU Platform Interface
|
||||||
*
|
*
|
||||||
* Copyright (c) 2014-2016, NVIDIA CORPORATION. All rights reserved.
|
* Copyright (c) 2014-2017, 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,
|
||||||
@@ -18,6 +18,7 @@
|
|||||||
#include "gk20a.h"
|
#include "gk20a.h"
|
||||||
#include "hal_gk20a.h"
|
#include "hal_gk20a.h"
|
||||||
#include "platform_gk20a.h"
|
#include "platform_gk20a.h"
|
||||||
|
#include "vgpu/clk_vgpu.h"
|
||||||
|
|
||||||
static int gk20a_tegra_probe(struct device *dev)
|
static int gk20a_tegra_probe(struct device *dev)
|
||||||
{
|
{
|
||||||
@@ -65,5 +66,13 @@ struct gk20a_platform vgpu_tegra_platform = {
|
|||||||
.probe = gk20a_tegra_probe,
|
.probe = gk20a_tegra_probe,
|
||||||
.default_big_page_size = SZ_128K,
|
.default_big_page_size = SZ_128K,
|
||||||
|
|
||||||
|
.clk_get_rate = vgpu_clk_get_rate,
|
||||||
|
.clk_round_rate = vgpu_clk_round_rate,
|
||||||
|
.clk_set_rate = vgpu_clk_set_rate,
|
||||||
|
.get_clk_freqs = vgpu_clk_get_freqs,
|
||||||
|
|
||||||
|
/* frequency scaling configuration */
|
||||||
|
.devfreq_governor = "userspace",
|
||||||
|
|
||||||
.virtual_dev = true,
|
.virtual_dev = true,
|
||||||
};
|
};
|
||||||
|
|||||||
113
drivers/gpu/nvgpu/vgpu/clk_vgpu.c
Normal file
113
drivers/gpu/nvgpu/vgpu/clk_vgpu.c
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Virtualized GPU Clock Interface
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "vgpu/vgpu.h"
|
||||||
|
#include "vgpu/clk_vgpu.h"
|
||||||
|
|
||||||
|
static unsigned long
|
||||||
|
vgpu_freq_table[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE];
|
||||||
|
|
||||||
|
unsigned long vgpu_clk_get_rate(struct device *dev)
|
||||||
|
{
|
||||||
|
struct gk20a_platform *platform = gk20a_get_platform(dev);
|
||||||
|
struct gk20a *g = platform->g;
|
||||||
|
struct tegra_vgpu_cmd_msg msg = {};
|
||||||
|
struct tegra_vgpu_gpu_clk_rate_params *p = &msg.params.gpu_clk_rate;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
|
||||||
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
|
msg.cmd = TEGRA_VGPU_CMD_GET_GPU_CLK_RATE;
|
||||||
|
msg.handle = vgpu_get_handle(g);
|
||||||
|
err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
|
||||||
|
err = err ? err : msg.ret;
|
||||||
|
if (err) {
|
||||||
|
gk20a_err(dev_from_gk20a(g),
|
||||||
|
"%s failed - %d", __func__, err);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return frequency in Hz */
|
||||||
|
return p->rate * 1000;
|
||||||
|
}
|
||||||
|
|
||||||
|
long vgpu_clk_round_rate(struct device *dev, unsigned long rate)
|
||||||
|
{
|
||||||
|
/* server will handle frequency rounding */
|
||||||
|
return rate;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vgpu_clk_set_rate(struct device *dev, unsigned long rate)
|
||||||
|
{
|
||||||
|
struct gk20a_platform *platform = gk20a_get_platform(dev);
|
||||||
|
struct gk20a *g = platform->g;
|
||||||
|
struct tegra_vgpu_cmd_msg msg = {};
|
||||||
|
struct tegra_vgpu_gpu_clk_rate_params *p = &msg.params.gpu_clk_rate;
|
||||||
|
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
|
msg.cmd = TEGRA_VGPU_CMD_SET_GPU_CLK_RATE;
|
||||||
|
msg.handle = vgpu_get_handle(g);
|
||||||
|
|
||||||
|
/* server dvfs framework requires frequency in kHz */
|
||||||
|
p->rate = (u32)(rate / 1000);
|
||||||
|
err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
|
||||||
|
err = err ? err : msg.ret;
|
||||||
|
if (err) {
|
||||||
|
gk20a_err(dev_from_gk20a(g),
|
||||||
|
"%s failed - %d", __func__, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int vgpu_clk_get_freqs(struct device *dev,
|
||||||
|
unsigned long **freqs, int *num_freqs)
|
||||||
|
{
|
||||||
|
struct gk20a_platform *platform = gk20a_get_platform(dev);
|
||||||
|
struct gk20a *g = platform->g;
|
||||||
|
struct tegra_vgpu_cmd_msg msg = {};
|
||||||
|
struct tegra_vgpu_get_gpu_freq_table_params *p =
|
||||||
|
&msg.params.get_gpu_freq_table;
|
||||||
|
unsigned int i;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
|
msg.cmd = TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE;
|
||||||
|
msg.handle = vgpu_get_handle(g);
|
||||||
|
|
||||||
|
p->num_freqs = TEGRA_VGPU_GPU_FREQ_TABLE_SIZE;
|
||||||
|
err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
|
||||||
|
err = err ? err : msg.ret;
|
||||||
|
if (err) {
|
||||||
|
gk20a_err(dev_from_gk20a(g),
|
||||||
|
"%s failed - %d", __func__, err);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return frequency in Hz */
|
||||||
|
for (i = 0; i < p->num_freqs; i++)
|
||||||
|
vgpu_freq_table[i] = p->freqs[i] * 1000;
|
||||||
|
|
||||||
|
*freqs = vgpu_freq_table;
|
||||||
|
*num_freqs = p->num_freqs;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
24
drivers/gpu/nvgpu/vgpu/clk_vgpu.h
Normal file
24
drivers/gpu/nvgpu/vgpu/clk_vgpu.h
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/*
|
||||||
|
* Virtualized GPU Clock Interface
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||||
|
* more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _CLK_VIRT_H_
|
||||||
|
#define _CLK_VIRT_H_
|
||||||
|
|
||||||
|
unsigned long vgpu_clk_get_rate(struct device *dev);
|
||||||
|
long vgpu_clk_round_rate(struct device *dev, unsigned long rate);
|
||||||
|
int vgpu_clk_set_rate(struct device *dev, unsigned long rate);
|
||||||
|
int vgpu_clk_get_freqs(struct device *dev,
|
||||||
|
unsigned long **freqs, int *num_freqs);
|
||||||
|
#endif
|
||||||
@@ -23,6 +23,7 @@
|
|||||||
|
|
||||||
#include "vgpu/vgpu.h"
|
#include "vgpu/vgpu.h"
|
||||||
#include "vgpu/fecs_trace_vgpu.h"
|
#include "vgpu/fecs_trace_vgpu.h"
|
||||||
|
#include "vgpu/clk_vgpu.h"
|
||||||
#include "gk20a/debug_gk20a.h"
|
#include "gk20a/debug_gk20a.h"
|
||||||
#include "gk20a/hal_gk20a.h"
|
#include "gk20a/hal_gk20a.h"
|
||||||
#include "gk20a/ctxsw_trace_gk20a.h"
|
#include "gk20a/ctxsw_trace_gk20a.h"
|
||||||
@@ -498,11 +499,29 @@ static void vgpu_pm_qos_remove(struct device *dev)
|
|||||||
|
|
||||||
static int vgpu_pm_init(struct device *dev)
|
static int vgpu_pm_init(struct device *dev)
|
||||||
{
|
{
|
||||||
|
struct gk20a *g = get_gk20a(dev);
|
||||||
|
unsigned long *freqs;
|
||||||
|
int num_freqs;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
gk20a_dbg_fn("");
|
gk20a_dbg_fn("");
|
||||||
|
|
||||||
__pm_runtime_disable(dev, false);
|
__pm_runtime_disable(dev, false);
|
||||||
|
|
||||||
|
if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
|
||||||
|
gk20a_scale_init(dev);
|
||||||
|
|
||||||
|
/* set min/max frequency based on frequency table */
|
||||||
|
err = vgpu_clk_get_freqs(dev, &freqs, &num_freqs);
|
||||||
|
if (err)
|
||||||
|
return err;
|
||||||
|
|
||||||
|
if (num_freqs < 1)
|
||||||
|
return -EINVAL;
|
||||||
|
|
||||||
|
g->devfreq->min_freq = freqs[0];
|
||||||
|
g->devfreq->max_freq = freqs[num_freqs - 1];
|
||||||
|
|
||||||
err = vgpu_pm_qos_init(dev);
|
err = vgpu_pm_qos_init(dev);
|
||||||
if (err)
|
if (err)
|
||||||
return err;
|
return err;
|
||||||
@@ -588,12 +607,6 @@ int vgpu_probe(struct platform_device *pdev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = vgpu_pm_init(dev);
|
|
||||||
if (err) {
|
|
||||||
dev_err(dev, "pm init failed");
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (platform->late_probe) {
|
if (platform->late_probe) {
|
||||||
err = platform->late_probe(dev);
|
err = platform->late_probe(dev);
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -621,6 +634,12 @@ int vgpu_probe(struct platform_device *pdev)
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = vgpu_pm_init(dev);
|
||||||
|
if (err) {
|
||||||
|
dev_err(dev, "pm init failed");
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
priv->intr_handler = kthread_run(vgpu_intr_thread, gk20a, "gk20a");
|
priv->intr_handler = kthread_run(vgpu_intr_thread, gk20a, "gk20a");
|
||||||
if (IS_ERR(priv->intr_handler))
|
if (IS_ERR(priv->intr_handler))
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|||||||
@@ -102,6 +102,8 @@ enum {
|
|||||||
TEGRA_VGPU_CMD_SUSPEND_CONTEXTS = 66,
|
TEGRA_VGPU_CMD_SUSPEND_CONTEXTS = 66,
|
||||||
TEGRA_VGPU_CMD_RESUME_CONTEXTS = 67,
|
TEGRA_VGPU_CMD_RESUME_CONTEXTS = 67,
|
||||||
TEGRA_VGPU_CMD_CLEAR_SM_ERROR_STATE = 68,
|
TEGRA_VGPU_CMD_CLEAR_SM_ERROR_STATE = 68,
|
||||||
|
TEGRA_VGPU_CMD_GET_GPU_CLK_RATE = 69,
|
||||||
|
TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE = 70,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct tegra_vgpu_connect_params {
|
struct tegra_vgpu_connect_params {
|
||||||
@@ -469,6 +471,13 @@ struct tegra_vgpu_clear_sm_error_state {
|
|||||||
u32 sm_id;
|
u32 sm_id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define TEGRA_VGPU_GPU_FREQ_TABLE_SIZE 25
|
||||||
|
|
||||||
|
struct tegra_vgpu_get_gpu_freq_table_params {
|
||||||
|
u32 num_freqs; /* in/out */
|
||||||
|
u32 freqs[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE]; /* in kHz */
|
||||||
|
};
|
||||||
|
|
||||||
struct tegra_vgpu_cmd_msg {
|
struct tegra_vgpu_cmd_msg {
|
||||||
u32 cmd;
|
u32 cmd;
|
||||||
int ret;
|
int ret;
|
||||||
@@ -518,6 +527,7 @@ struct tegra_vgpu_cmd_msg {
|
|||||||
struct tegra_vgpu_suspend_resume_contexts suspend_contexts;
|
struct tegra_vgpu_suspend_resume_contexts suspend_contexts;
|
||||||
struct tegra_vgpu_suspend_resume_contexts resume_contexts;
|
struct tegra_vgpu_suspend_resume_contexts resume_contexts;
|
||||||
struct tegra_vgpu_clear_sm_error_state clear_sm_error_state;
|
struct tegra_vgpu_clear_sm_error_state clear_sm_error_state;
|
||||||
|
struct tegra_vgpu_get_gpu_freq_table_params get_gpu_freq_table;
|
||||||
char padding[192];
|
char padding[192];
|
||||||
} params;
|
} params;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user