mirror of
git://nv-tegra.nvidia.com/linux-nvgpu.git
synced 2025-12-22 09:12:24 +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/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 \
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
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/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;
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user