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:
Sachit Kadle
2017-01-24 10:22:13 -08:00
committed by mobile promotions
parent 0eb5255e54
commit f871b52fd3
6 changed files with 183 additions and 7 deletions

View File

@@ -106,6 +106,7 @@ nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \
vgpu/dbg_vgpu.o \
vgpu/fecs_trace_vgpu.o \
vgpu/tsg_vgpu.o \
vgpu/clk_vgpu.o \
vgpu/css_vgpu.o \
vgpu/gk20a/vgpu_hal_gk20a.o \
vgpu/gk20a/vgpu_gr_gk20a.o \

View File

@@ -1,7 +1,7 @@
/*
* 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
* under the terms and conditions of the GNU General Public License,
@@ -18,6 +18,7 @@
#include "gk20a.h"
#include "hal_gk20a.h"
#include "platform_gk20a.h"
#include "vgpu/clk_vgpu.h"
static int gk20a_tegra_probe(struct device *dev)
{
@@ -65,5 +66,13 @@ struct gk20a_platform vgpu_tegra_platform = {
.probe = gk20a_tegra_probe,
.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,
};

View 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;
}

View 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

View File

@@ -23,6 +23,7 @@
#include "vgpu/vgpu.h"
#include "vgpu/fecs_trace_vgpu.h"
#include "vgpu/clk_vgpu.h"
#include "gk20a/debug_gk20a.h"
#include "gk20a/hal_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)
{
struct gk20a *g = get_gk20a(dev);
unsigned long *freqs;
int num_freqs;
int err = 0;
gk20a_dbg_fn("");
__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);
if (err)
return err;
@@ -588,12 +607,6 @@ int vgpu_probe(struct platform_device *pdev)
return err;
}
err = vgpu_pm_init(dev);
if (err) {
dev_err(dev, "pm init failed");
return err;
}
if (platform->late_probe) {
err = platform->late_probe(dev);
if (err) {
@@ -621,6 +634,12 @@ int vgpu_probe(struct platform_device *pdev)
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");
if (IS_ERR(priv->intr_handler))
return -ENOMEM;

View File

@@ -102,6 +102,8 @@ enum {
TEGRA_VGPU_CMD_SUSPEND_CONTEXTS = 66,
TEGRA_VGPU_CMD_RESUME_CONTEXTS = 67,
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 {
@@ -469,6 +471,13 @@ struct tegra_vgpu_clear_sm_error_state {
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 {
u32 cmd;
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 resume_contexts;
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];
} params;
};