summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSachit Kadle <skadle@nvidia.com>2017-01-24 13:22:13 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2017-06-19 19:36:26 -0400
commitb3a7c2b305ec6f895dc236f0c5f163bd4cbeb248 (patch)
treea1df93a947d7f5d60a9e57a69d0058d430844c92
parent2535c81c6c916f9f2e1224e17e80d240df569e49 (diff)
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 (cherry picked from commit f871b52fd3f553d6b6375a3c848fbca272ed8e29) Reviewed-on: http://git-master/r/1313468 Tested-by: Aparna Das <aparnad@nvidia.com> Reviewed-by: Terje Bergstrom <tbergstrom@nvidia.com> Reviewed-by: Richard Zhao <rizhao@nvidia.com> GVS: Gerrit_Virtual_Submit
-rw-r--r--drivers/gpu/nvgpu/Makefile.nvgpu1
-rw-r--r--drivers/gpu/nvgpu/gk20a/platform_vgpu_tegra.c16
-rw-r--r--drivers/gpu/nvgpu/vgpu/clk_vgpu.c130
-rw-r--r--drivers/gpu/nvgpu/vgpu/clk_vgpu.h23
-rw-r--r--drivers/gpu/nvgpu/vgpu/vgpu.c49
-rw-r--r--include/linux/tegra_vgpu.h10
6 files changed, 216 insertions, 13 deletions
diff --git a/drivers/gpu/nvgpu/Makefile.nvgpu b/drivers/gpu/nvgpu/Makefile.nvgpu
index ac58d512..d16e2c3e 100644
--- a/drivers/gpu/nvgpu/Makefile.nvgpu
+++ b/drivers/gpu/nvgpu/Makefile.nvgpu
@@ -150,6 +150,7 @@ nvgpu-$(CONFIG_TEGRA_GR_VIRTUALIZATION) += \
150 vgpu/dbg_vgpu.o \ 150 vgpu/dbg_vgpu.o \
151 vgpu/fecs_trace_vgpu.o \ 151 vgpu/fecs_trace_vgpu.o \
152 vgpu/tsg_vgpu.o \ 152 vgpu/tsg_vgpu.o \
153 vgpu/clk_vgpu.o \
153 vgpu/css_vgpu.o \ 154 vgpu/css_vgpu.o \
154 vgpu/gk20a/vgpu_hal_gk20a.o \ 155 vgpu/gk20a/vgpu_hal_gk20a.o \
155 vgpu/gk20a/vgpu_gr_gk20a.o \ 156 vgpu/gk20a/vgpu_gr_gk20a.o \
diff --git a/drivers/gpu/nvgpu/gk20a/platform_vgpu_tegra.c b/drivers/gpu/nvgpu/gk20a/platform_vgpu_tegra.c
index e33fc29f..f2c877f9 100644
--- a/drivers/gpu/nvgpu/gk20a/platform_vgpu_tegra.c
+++ b/drivers/gpu/nvgpu/gk20a/platform_vgpu_tegra.c
@@ -16,6 +16,7 @@
16#include "gk20a.h" 16#include "gk20a.h"
17#include "hal_gk20a.h" 17#include "hal_gk20a.h"
18#include "platform_gk20a.h" 18#include "platform_gk20a.h"
19#include "vgpu/clk_vgpu.h"
19 20
20#include <nvgpu/nvhost.h> 21#include <nvgpu/nvhost.h>
21 22
@@ -23,7 +24,14 @@ static int gk20a_tegra_probe(struct device *dev)
23{ 24{
24#ifdef CONFIG_TEGRA_GK20A_NVHOST 25#ifdef CONFIG_TEGRA_GK20A_NVHOST
25 struct gk20a_platform *platform = dev_get_drvdata(dev); 26 struct gk20a_platform *platform = dev_get_drvdata(dev);
26 return nvgpu_get_nvhost_dev(platform->g); 27 int ret;
28
29 ret = nvgpu_get_nvhost_dev(platform->g);
30 if (ret)
31 return ret;
32
33 vgpu_init_clk_support(platform->g);
34 return 0;
27#else 35#else
28 return 0; 36 return 0;
29#endif 37#endif
@@ -47,5 +55,11 @@ struct gk20a_platform vgpu_tegra_platform = {
47 .probe = gk20a_tegra_probe, 55 .probe = gk20a_tegra_probe,
48 .default_big_page_size = SZ_128K, 56 .default_big_page_size = SZ_128K,
49 57
58 .clk_round_rate = vgpu_clk_round_rate,
59 .get_clk_freqs = vgpu_clk_get_freqs,
60
61 /* frequency scaling configuration */
62 .devfreq_governor = "userspace",
63
50 .virtual_dev = true, 64 .virtual_dev = true,
51}; 65};
diff --git a/drivers/gpu/nvgpu/vgpu/clk_vgpu.c b/drivers/gpu/nvgpu/vgpu/clk_vgpu.c
new file mode 100644
index 00000000..fe5533b6
--- /dev/null
+++ b/drivers/gpu/nvgpu/vgpu/clk_vgpu.c
@@ -0,0 +1,130 @@
1/*
2 * Virtualized GPU Clock Interface
3 *
4 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#include "vgpu/vgpu.h"
17#include "vgpu/clk_vgpu.h"
18
19static unsigned long
20vgpu_freq_table[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE];
21
22static unsigned long vgpu_clk_get_rate(struct gk20a *g, u32 api_domain)
23{
24 struct tegra_vgpu_cmd_msg msg = {};
25 struct tegra_vgpu_gpu_clk_rate_params *p = &msg.params.gpu_clk_rate;
26 int err;
27 unsigned long ret = 0;
28
29 gk20a_dbg_fn("");
30
31 switch (api_domain) {
32 case CTRL_CLK_DOMAIN_GPCCLK:
33 msg.cmd = TEGRA_VGPU_CMD_GET_GPU_CLK_RATE;
34 msg.handle = vgpu_get_handle(g);
35 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
36 err = err ? err : msg.ret;
37 if (err)
38 nvgpu_err(g, "%s failed - %d", __func__, err);
39 else
40 /* return frequency in Hz */
41 ret = p->rate * 1000;
42 break;
43 case CTRL_CLK_DOMAIN_PWRCLK:
44 nvgpu_err(g, "unsupported clock: %u", api_domain);
45 break;
46 default:
47 nvgpu_err(g, "unknown clock: %u", api_domain);
48 break;
49 }
50
51 return ret;
52}
53
54static int vgpu_clk_set_rate(struct gk20a *g,
55 u32 api_domain, unsigned long rate)
56{
57 struct tegra_vgpu_cmd_msg msg = {};
58 struct tegra_vgpu_gpu_clk_rate_params *p = &msg.params.gpu_clk_rate;
59 int err = -EINVAL;
60
61 gk20a_dbg_fn("");
62
63 switch (api_domain) {
64 case CTRL_CLK_DOMAIN_GPCCLK:
65 msg.cmd = TEGRA_VGPU_CMD_SET_GPU_CLK_RATE;
66 msg.handle = vgpu_get_handle(g);
67
68 /* server dvfs framework requires frequency in kHz */
69 p->rate = (u32)(rate / 1000);
70 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
71 err = err ? err : msg.ret;
72 if (err)
73 nvgpu_err(g, "%s failed - %d", __func__, err);
74 break;
75 case CTRL_CLK_DOMAIN_PWRCLK:
76 nvgpu_err(g, "unsupported clock: %u", api_domain);
77 break;
78 default:
79 nvgpu_err(g, "unknown clock: %u", api_domain);
80 break;
81 }
82
83 return err;
84}
85
86void vgpu_init_clk_support(struct gk20a *g)
87{
88 g->ops.clk.get_rate = vgpu_clk_get_rate;
89 g->ops.clk.set_rate = vgpu_clk_set_rate;
90}
91
92long vgpu_clk_round_rate(struct device *dev, unsigned long rate)
93{
94 /* server will handle frequency rounding */
95 return rate;
96}
97
98int vgpu_clk_get_freqs(struct device *dev,
99 unsigned long **freqs, int *num_freqs)
100{
101 struct gk20a_platform *platform = gk20a_get_platform(dev);
102 struct gk20a *g = platform->g;
103 struct tegra_vgpu_cmd_msg msg = {};
104 struct tegra_vgpu_get_gpu_freq_table_params *p =
105 &msg.params.get_gpu_freq_table;
106 unsigned int i;
107 int err;
108
109 gk20a_dbg_fn("");
110
111 msg.cmd = TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE;
112 msg.handle = vgpu_get_handle(g);
113
114 p->num_freqs = TEGRA_VGPU_GPU_FREQ_TABLE_SIZE;
115 err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg));
116 err = err ? err : msg.ret;
117 if (err) {
118 nvgpu_err(g, "%s failed - %d", __func__, err);
119 return err;
120 }
121
122 /* return frequency in Hz */
123 for (i = 0; i < p->num_freqs; i++)
124 vgpu_freq_table[i] = p->freqs[i] * 1000;
125
126 *freqs = vgpu_freq_table;
127 *num_freqs = p->num_freqs;
128
129 return 0;
130}
diff --git a/drivers/gpu/nvgpu/vgpu/clk_vgpu.h b/drivers/gpu/nvgpu/vgpu/clk_vgpu.h
new file mode 100644
index 00000000..a90b63d8
--- /dev/null
+++ b/drivers/gpu/nvgpu/vgpu/clk_vgpu.h
@@ -0,0 +1,23 @@
1/*
2 * Virtualized GPU Clock Interface
3 *
4 * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16#ifndef _CLK_VIRT_H_
17#define _CLK_VIRT_H_
18
19void vgpu_init_clk_support(struct gk20a *g);
20long vgpu_clk_round_rate(struct device *dev, unsigned long rate);
21int vgpu_clk_get_freqs(struct device *dev,
22 unsigned long **freqs, int *num_freqs);
23#endif
diff --git a/drivers/gpu/nvgpu/vgpu/vgpu.c b/drivers/gpu/nvgpu/vgpu/vgpu.c
index 2b1c93dd..e8a778f5 100644
--- a/drivers/gpu/nvgpu/vgpu/vgpu.c
+++ b/drivers/gpu/nvgpu/vgpu/vgpu.c
@@ -26,6 +26,7 @@
26 26
27#include "vgpu/vgpu.h" 27#include "vgpu/vgpu.h"
28#include "vgpu/fecs_trace_vgpu.h" 28#include "vgpu/fecs_trace_vgpu.h"
29#include "vgpu/clk_vgpu.h"
29#include "gk20a/hal_gk20a.h" 30#include "gk20a/hal_gk20a.h"
30#include "gk20a/ctxsw_trace_gk20a.h" 31#include "gk20a/ctxsw_trace_gk20a.h"
31#include "gk20a/tsg_gk20a.h" 32#include "gk20a/tsg_gk20a.h"
@@ -538,18 +539,22 @@ static int vgpu_qos_notify(struct notifier_block *nb,
538static int vgpu_pm_qos_init(struct device *dev) 539static int vgpu_pm_qos_init(struct device *dev)
539{ 540{
540 struct gk20a *g = get_gk20a(dev); 541 struct gk20a *g = get_gk20a(dev);
541 struct gk20a_scale_profile *profile; 542 struct gk20a_scale_profile *profile = g->scale_profile;
542 543
543 profile = nvgpu_kzalloc(g, sizeof(*profile)); 544 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ)) {
544 if (!profile) 545 if (!profile)
545 return -ENOMEM; 546 return -EINVAL;
547 } else {
548 profile = nvgpu_kzalloc(g, sizeof(*profile));
549 if (!profile)
550 return -ENOMEM;
551 g->scale_profile = profile;
552 }
546 553
547 profile->dev = dev; 554 profile->dev = dev;
548 profile->qos_notify_block.notifier_call = vgpu_qos_notify; 555 profile->qos_notify_block.notifier_call = vgpu_qos_notify;
549 g->scale_profile = profile;
550 pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS, 556 pm_qos_add_max_notifier(PM_QOS_GPU_FREQ_BOUNDS,
551 &profile->qos_notify_block); 557 &profile->qos_notify_block);
552
553 return 0; 558 return 0;
554} 559}
555 560
@@ -565,11 +570,31 @@ static void vgpu_pm_qos_remove(struct device *dev)
565 570
566static int vgpu_pm_init(struct device *dev) 571static int vgpu_pm_init(struct device *dev)
567{ 572{
573 struct gk20a *g = get_gk20a(dev);
574 unsigned long *freqs;
575 int num_freqs;
568 int err = 0; 576 int err = 0;
569 577
570 gk20a_dbg_fn(""); 578 gk20a_dbg_fn("");
571 579
572 __pm_runtime_disable(dev, false); 580 __pm_runtime_disable(dev, false);
581
582 if (IS_ENABLED(CONFIG_GK20A_DEVFREQ))
583 gk20a_scale_init(dev);
584
585 if (g->devfreq) {
586 /* set min/max frequency based on frequency table */
587 err = vgpu_clk_get_freqs(dev, &freqs, &num_freqs);
588 if (err)
589 return err;
590
591 if (num_freqs < 1)
592 return -EINVAL;
593
594 g->devfreq->min_freq = freqs[0];
595 g->devfreq->max_freq = freqs[num_freqs - 1];
596 }
597
573 err = vgpu_pm_qos_init(dev); 598 err = vgpu_pm_qos_init(dev);
574 if (err) 599 if (err)
575 return err; 600 return err;
@@ -675,12 +700,6 @@ int vgpu_probe(struct platform_device *pdev)
675 return err; 700 return err;
676 } 701 }
677 702
678 err = vgpu_pm_init(dev);
679 if (err) {
680 dev_err(dev, "pm init failed");
681 return err;
682 }
683
684 if (platform->late_probe) { 703 if (platform->late_probe) {
685 err = platform->late_probe(dev); 704 err = platform->late_probe(dev);
686 if (err) { 705 if (err) {
@@ -708,6 +727,12 @@ int vgpu_probe(struct platform_device *pdev)
708 return err; 727 return err;
709 } 728 }
710 729
730 err = vgpu_pm_init(dev);
731 if (err) {
732 dev_err(dev, "pm init failed");
733 return err;
734 }
735
711 err = nvgpu_thread_create(&priv->intr_handler, gk20a, 736 err = nvgpu_thread_create(&priv->intr_handler, gk20a,
712 vgpu_intr_thread, "gk20a"); 737 vgpu_intr_thread, "gk20a");
713 if (err) 738 if (err)
diff --git a/include/linux/tegra_vgpu.h b/include/linux/tegra_vgpu.h
index 67f51806..4d1e1ac9 100644
--- a/include/linux/tegra_vgpu.h
+++ b/include/linux/tegra_vgpu.h
@@ -100,6 +100,8 @@ enum {
100 TEGRA_VGPU_CMD_SUSPEND_CONTEXTS = 66, 100 TEGRA_VGPU_CMD_SUSPEND_CONTEXTS = 66,
101 TEGRA_VGPU_CMD_RESUME_CONTEXTS = 67, 101 TEGRA_VGPU_CMD_RESUME_CONTEXTS = 67,
102 TEGRA_VGPU_CMD_CLEAR_SM_ERROR_STATE = 68, 102 TEGRA_VGPU_CMD_CLEAR_SM_ERROR_STATE = 68,
103 TEGRA_VGPU_CMD_GET_GPU_CLK_RATE = 69,
104 TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE = 70,
103 TEGRA_VGPU_CMD_PROF_MGT = 72, 105 TEGRA_VGPU_CMD_PROF_MGT = 72,
104 TEGRA_VGPU_CMD_GET_TIMESTAMPS_ZIPPER = 74, 106 TEGRA_VGPU_CMD_GET_TIMESTAMPS_ZIPPER = 74,
105}; 107};
@@ -485,6 +487,13 @@ struct tegra_vgpu_prof_mgt_params {
485 u32 mode; 487 u32 mode;
486}; 488};
487 489
490#define TEGRA_VGPU_GPU_FREQ_TABLE_SIZE 25
491
492struct tegra_vgpu_get_gpu_freq_table_params {
493 u32 num_freqs;
494 u32 freqs[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE]; /* in kHz */
495};
496
488struct tegra_vgpu_cmd_msg { 497struct tegra_vgpu_cmd_msg {
489 u32 cmd; 498 u32 cmd;
490 int ret; 499 int ret;
@@ -536,6 +545,7 @@ struct tegra_vgpu_cmd_msg {
536 struct tegra_vgpu_clear_sm_error_state clear_sm_error_state; 545 struct tegra_vgpu_clear_sm_error_state clear_sm_error_state;
537 struct tegra_vgpu_prof_mgt_params prof_management; 546 struct tegra_vgpu_prof_mgt_params prof_management;
538 struct tegra_vgpu_get_timestamps_zipper_params get_timestamps_zipper; 547 struct tegra_vgpu_get_timestamps_zipper_params get_timestamps_zipper;
548 struct tegra_vgpu_get_gpu_freq_table_params get_gpu_freq_table;
539 char padding[192]; 549 char padding[192];
540 } params; 550 } params;
541}; 551};