From 78e3d22da3c2513d425c8c2560468ce854a982dd Mon Sep 17 00:00:00 2001 From: Aparna Das Date: Tue, 11 Sep 2018 17:11:44 -0700 Subject: gpu: nvgpu: vgpu: support clk-arb 1. Implement the following vgpu functions to support clk-arb: - vgpu_clk_get_range() to return min and max freqs from supported frequencies - implement vgpu_clk_get_round_rate() which sets rounded rate to input rate. Rounding is handled in RM Server - modify vgpu_clk_get_freqs() to retrieve freq table in IVM memory instead of copying the value in array as part of cmd message. 2. Add support for clk-arb related HALs for vgpu. 3. support_clk_freq_controller is assigned true for vgpu provided guest VM has the privilege to set clock frequency. Bug 200422845 Bug 2363882 Jira EVLR-3254 Change-Id: I91fc392db381c5db1d52b19d45ec0481fdc27554 Signed-off-by: Aparna Das Reviewed-on: https://git-master.nvidia.com/r/1812379 Reviewed-by: mobile promotions Tested-by: mobile promotions --- drivers/gpu/nvgpu/vgpu/clk_vgpu.c | 174 ++++++++++++++++++++++++++++++++++---- 1 file changed, 159 insertions(+), 15 deletions(-) (limited to 'drivers/gpu/nvgpu/vgpu/clk_vgpu.c') diff --git a/drivers/gpu/nvgpu/vgpu/clk_vgpu.c b/drivers/gpu/nvgpu/vgpu/clk_vgpu.c index efcb4fb0..6aea7c8f 100644 --- a/drivers/gpu/nvgpu/vgpu/clk_vgpu.c +++ b/drivers/gpu/nvgpu/vgpu/clk_vgpu.c @@ -21,14 +21,12 @@ */ #include +#include #include "gk20a/gk20a.h" #include "clk_vgpu.h" #include "ctrl/ctrlclk.h" -static unsigned long -vgpu_freq_table[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE]; - static unsigned long vgpu_clk_get_rate(struct gk20a *g, u32 api_domain) { struct tegra_vgpu_cmd_msg msg = {}; @@ -95,9 +93,117 @@ static int vgpu_clk_set_rate(struct gk20a *g, static unsigned long vgpu_clk_get_maxrate(struct gk20a *g, u32 api_domain) { - struct vgpu_priv_data *priv = vgpu_get_priv_data(g); + unsigned long *freqs; + int num_freqs = 0; + int err; + unsigned long ret = 0; + + nvgpu_log_fn(g, " "); + + switch (api_domain) { + case CTRL_CLK_DOMAIN_GPCCLK: + err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); + if (err == 0) { + /* return freq in Hz */ + ret = freqs[num_freqs - 1]; + } + break; + default: + nvgpu_err(g, "unknown clock: %u", api_domain); + break; + } + + return ret; +} + +static int vgpu_clk_get_round_rate(struct gk20a *g, u32 api_domain, + unsigned long rate_target, unsigned long *rounded_rate) +{ + int err = -EINVAL; + + nvgpu_log_fn(g, " "); - return priv->constants.max_freq; + switch (api_domain) { + case CTRL_CLK_DOMAIN_GPCCLK: + *rounded_rate = rate_target; + err = 0; + break; + default: + nvgpu_err(g, "unknown clock: %u", api_domain); + break; + } + + return err; +} + +static int vgpu_clk_get_range(struct gk20a *g, u32 api_domain, + u16 *min_mhz, u16 *max_mhz) +{ + unsigned long *freqs; + int num_freqs = 0; + int err = -EINVAL; + + nvgpu_log_fn(g, " "); + + switch (api_domain) { + case CTRL_CLK_DOMAIN_GPCCLK: + err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); + if (err == 0) { + /* return freq in MHz */ + *min_mhz = (u16)(freqs[0] / 1000000); + *max_mhz = (u16)(freqs[num_freqs - 1] / 1000000); + } + break; + default: + nvgpu_err(g, "unknown clock: %u", api_domain); + break; + } + + return err; +} + +static int vgpu_clk_get_f_points(struct gk20a *g, + u32 api_domain, u32 *num_points, u16 *freqs_mhz) +{ + unsigned long *freqs; + int num_freqs = 0; + u32 i; + int err = -EINVAL; + + nvgpu_log_fn(g, " "); + + switch (api_domain) { + case CTRL_CLK_DOMAIN_GPCCLK: + err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); + if (err) { + return err; + } + + if (num_points == NULL) { + return -EINVAL; + } + + if (*num_points != 0U) { + if (freqs == NULL || (*num_points > (u32)num_freqs)) { + return -EINVAL; + } + } + + if (*num_points == 0) { + *num_points = num_freqs; + } else { + for (i = 0; i < *num_points; i++) { + /* return freq in MHz */ + freqs_mhz[i] = (u16)(freqs[i] / 1000000); + } + } + break; + default: + nvgpu_err(g, "unknown clock: %u", api_domain); + break; + } + + return err; } void vgpu_init_clk_support(struct gk20a *g) @@ -105,37 +211,75 @@ void vgpu_init_clk_support(struct gk20a *g) g->ops.clk.get_rate = vgpu_clk_get_rate; g->ops.clk.set_rate = vgpu_clk_set_rate; g->ops.clk.get_maxrate = vgpu_clk_get_maxrate; + g->ops.clk.clk_get_round_rate = vgpu_clk_get_round_rate; + g->ops.clk.get_clk_range = vgpu_clk_get_range; + g->ops.clk.clk_domain_get_f_points = vgpu_clk_get_f_points; } -int vgpu_clk_get_freqs(struct gk20a *g, unsigned long **freqs, int *num_freqs) +int vgpu_clk_get_freqs(struct gk20a *g, unsigned long **freqs_out, + int *num_freqs) { struct tegra_vgpu_cmd_msg msg = {}; struct tegra_vgpu_get_gpu_freq_table_params *p = &msg.params.get_gpu_freq_table; + struct vgpu_priv_data *priv = vgpu_get_priv_data(g); + u32 *freqs; + int err = 0; + void *handle = NULL; + size_t oob_size; unsigned int i; - int err; nvgpu_log_fn(g, " "); + nvgpu_mutex_acquire(&priv->vgpu_clk_get_freq_lock); + + if (priv->freqs != NULL) { + goto done; + } + 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) { nvgpu_err(g, "%s failed - %d", __func__, err); - return err; + goto done; } - /* return frequency in Hz */ - for (i = 0; i < p->num_freqs; i++) - vgpu_freq_table[i] = p->freqs[i] * 1000; + handle = vgpu_ivc_oob_get_ptr(vgpu_ivc_get_server_vmid(), + TEGRA_VGPU_QUEUE_CMD, (void **)&freqs, &oob_size); + if (!handle) { + nvgpu_err(g, "failed to get ivm handle"); + err = -EINVAL; + goto done; + } - *freqs = vgpu_freq_table; - *num_freqs = p->num_freqs; + priv->freqs = nvgpu_kzalloc(g, sizeof(*priv->freqs) * (p->num_freqs)); + if (!priv->freqs) { + nvgpu_err(g, "failed to allocate memory"); + vgpu_ivc_oob_put_ptr(handle); + err = -ENOMEM; + goto done; + } + priv->num_freqs = p->num_freqs; - return 0; + for (i = 0; i < priv->num_freqs; i++) { + /* store frequency in Hz */ + priv->freqs[i] = (unsigned long)(freqs[i] * 1000); + } + + vgpu_ivc_oob_put_ptr(handle); + +done: + if (err == 0) { + *num_freqs = priv->num_freqs; + *freqs_out = priv->freqs; + } + + nvgpu_mutex_release(&priv->vgpu_clk_get_freq_lock); + + return err; } int vgpu_clk_cap_rate(struct gk20a *g, unsigned long rate) -- cgit v1.2.2