diff options
author | Aparna Das <aparnad@nvidia.com> | 2018-09-11 20:11:44 -0400 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2018-09-27 18:04:47 -0400 |
commit | 78e3d22da3c2513d425c8c2560468ce854a982dd (patch) | |
tree | 87ce6d1c47357c868cb58608e893afb4c14cfa69 /drivers/gpu/nvgpu/vgpu/clk_vgpu.c | |
parent | 8789cafcfb0d1e16ad0b2c61b047d275f2d684b4 (diff) |
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 <aparnad@nvidia.com>
Reviewed-on: https://git-master.nvidia.com/r/1812379
Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com>
Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/vgpu/clk_vgpu.c')
-rw-r--r-- | drivers/gpu/nvgpu/vgpu/clk_vgpu.c | 174 |
1 files changed, 159 insertions, 15 deletions
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 @@ | |||
21 | */ | 21 | */ |
22 | 22 | ||
23 | #include <nvgpu/vgpu/vgpu.h> | 23 | #include <nvgpu/vgpu/vgpu.h> |
24 | #include <nvgpu/vgpu/vgpu_ivc.h> | ||
24 | 25 | ||
25 | #include "gk20a/gk20a.h" | 26 | #include "gk20a/gk20a.h" |
26 | #include "clk_vgpu.h" | 27 | #include "clk_vgpu.h" |
27 | #include "ctrl/ctrlclk.h" | 28 | #include "ctrl/ctrlclk.h" |
28 | 29 | ||
29 | static unsigned long | ||
30 | vgpu_freq_table[TEGRA_VGPU_GPU_FREQ_TABLE_SIZE]; | ||
31 | |||
32 | static unsigned long vgpu_clk_get_rate(struct gk20a *g, u32 api_domain) | 30 | static unsigned long vgpu_clk_get_rate(struct gk20a *g, u32 api_domain) |
33 | { | 31 | { |
34 | struct tegra_vgpu_cmd_msg msg = {}; | 32 | struct tegra_vgpu_cmd_msg msg = {}; |
@@ -95,9 +93,117 @@ static int vgpu_clk_set_rate(struct gk20a *g, | |||
95 | 93 | ||
96 | static unsigned long vgpu_clk_get_maxrate(struct gk20a *g, u32 api_domain) | 94 | static unsigned long vgpu_clk_get_maxrate(struct gk20a *g, u32 api_domain) |
97 | { | 95 | { |
98 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | 96 | unsigned long *freqs; |
97 | int num_freqs = 0; | ||
98 | int err; | ||
99 | unsigned long ret = 0; | ||
100 | |||
101 | nvgpu_log_fn(g, " "); | ||
102 | |||
103 | switch (api_domain) { | ||
104 | case CTRL_CLK_DOMAIN_GPCCLK: | ||
105 | err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); | ||
106 | if (err == 0) { | ||
107 | /* return freq in Hz */ | ||
108 | ret = freqs[num_freqs - 1]; | ||
109 | } | ||
110 | break; | ||
111 | default: | ||
112 | nvgpu_err(g, "unknown clock: %u", api_domain); | ||
113 | break; | ||
114 | } | ||
115 | |||
116 | return ret; | ||
117 | } | ||
118 | |||
119 | static int vgpu_clk_get_round_rate(struct gk20a *g, u32 api_domain, | ||
120 | unsigned long rate_target, unsigned long *rounded_rate) | ||
121 | { | ||
122 | int err = -EINVAL; | ||
123 | |||
124 | nvgpu_log_fn(g, " "); | ||
99 | 125 | ||
100 | return priv->constants.max_freq; | 126 | switch (api_domain) { |
127 | case CTRL_CLK_DOMAIN_GPCCLK: | ||
128 | *rounded_rate = rate_target; | ||
129 | err = 0; | ||
130 | break; | ||
131 | default: | ||
132 | nvgpu_err(g, "unknown clock: %u", api_domain); | ||
133 | break; | ||
134 | } | ||
135 | |||
136 | return err; | ||
137 | } | ||
138 | |||
139 | static int vgpu_clk_get_range(struct gk20a *g, u32 api_domain, | ||
140 | u16 *min_mhz, u16 *max_mhz) | ||
141 | { | ||
142 | unsigned long *freqs; | ||
143 | int num_freqs = 0; | ||
144 | int err = -EINVAL; | ||
145 | |||
146 | nvgpu_log_fn(g, " "); | ||
147 | |||
148 | switch (api_domain) { | ||
149 | case CTRL_CLK_DOMAIN_GPCCLK: | ||
150 | err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); | ||
151 | if (err == 0) { | ||
152 | /* return freq in MHz */ | ||
153 | *min_mhz = (u16)(freqs[0] / 1000000); | ||
154 | *max_mhz = (u16)(freqs[num_freqs - 1] / 1000000); | ||
155 | } | ||
156 | break; | ||
157 | default: | ||
158 | nvgpu_err(g, "unknown clock: %u", api_domain); | ||
159 | break; | ||
160 | } | ||
161 | |||
162 | return err; | ||
163 | } | ||
164 | |||
165 | static int vgpu_clk_get_f_points(struct gk20a *g, | ||
166 | u32 api_domain, u32 *num_points, u16 *freqs_mhz) | ||
167 | { | ||
168 | unsigned long *freqs; | ||
169 | int num_freqs = 0; | ||
170 | u32 i; | ||
171 | int err = -EINVAL; | ||
172 | |||
173 | nvgpu_log_fn(g, " "); | ||
174 | |||
175 | switch (api_domain) { | ||
176 | case CTRL_CLK_DOMAIN_GPCCLK: | ||
177 | err = vgpu_clk_get_freqs(g, &freqs, &num_freqs); | ||
178 | if (err) { | ||
179 | return err; | ||
180 | } | ||
181 | |||
182 | if (num_points == NULL) { | ||
183 | return -EINVAL; | ||
184 | } | ||
185 | |||
186 | if (*num_points != 0U) { | ||
187 | if (freqs == NULL || (*num_points > (u32)num_freqs)) { | ||
188 | return -EINVAL; | ||
189 | } | ||
190 | } | ||
191 | |||
192 | if (*num_points == 0) { | ||
193 | *num_points = num_freqs; | ||
194 | } else { | ||
195 | for (i = 0; i < *num_points; i++) { | ||
196 | /* return freq in MHz */ | ||
197 | freqs_mhz[i] = (u16)(freqs[i] / 1000000); | ||
198 | } | ||
199 | } | ||
200 | break; | ||
201 | default: | ||
202 | nvgpu_err(g, "unknown clock: %u", api_domain); | ||
203 | break; | ||
204 | } | ||
205 | |||
206 | return err; | ||
101 | } | 207 | } |
102 | 208 | ||
103 | void vgpu_init_clk_support(struct gk20a *g) | 209 | void vgpu_init_clk_support(struct gk20a *g) |
@@ -105,37 +211,75 @@ void vgpu_init_clk_support(struct gk20a *g) | |||
105 | g->ops.clk.get_rate = vgpu_clk_get_rate; | 211 | g->ops.clk.get_rate = vgpu_clk_get_rate; |
106 | g->ops.clk.set_rate = vgpu_clk_set_rate; | 212 | g->ops.clk.set_rate = vgpu_clk_set_rate; |
107 | g->ops.clk.get_maxrate = vgpu_clk_get_maxrate; | 213 | g->ops.clk.get_maxrate = vgpu_clk_get_maxrate; |
214 | g->ops.clk.clk_get_round_rate = vgpu_clk_get_round_rate; | ||
215 | g->ops.clk.get_clk_range = vgpu_clk_get_range; | ||
216 | g->ops.clk.clk_domain_get_f_points = vgpu_clk_get_f_points; | ||
108 | } | 217 | } |
109 | 218 | ||
110 | int vgpu_clk_get_freqs(struct gk20a *g, unsigned long **freqs, int *num_freqs) | 219 | int vgpu_clk_get_freqs(struct gk20a *g, unsigned long **freqs_out, |
220 | int *num_freqs) | ||
111 | { | 221 | { |
112 | struct tegra_vgpu_cmd_msg msg = {}; | 222 | struct tegra_vgpu_cmd_msg msg = {}; |
113 | struct tegra_vgpu_get_gpu_freq_table_params *p = | 223 | struct tegra_vgpu_get_gpu_freq_table_params *p = |
114 | &msg.params.get_gpu_freq_table; | 224 | &msg.params.get_gpu_freq_table; |
225 | struct vgpu_priv_data *priv = vgpu_get_priv_data(g); | ||
226 | u32 *freqs; | ||
227 | int err = 0; | ||
228 | void *handle = NULL; | ||
229 | size_t oob_size; | ||
115 | unsigned int i; | 230 | unsigned int i; |
116 | int err; | ||
117 | 231 | ||
118 | nvgpu_log_fn(g, " "); | 232 | nvgpu_log_fn(g, " "); |
119 | 233 | ||
234 | nvgpu_mutex_acquire(&priv->vgpu_clk_get_freq_lock); | ||
235 | |||
236 | if (priv->freqs != NULL) { | ||
237 | goto done; | ||
238 | } | ||
239 | |||
120 | msg.cmd = TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE; | 240 | msg.cmd = TEGRA_VGPU_CMD_GET_GPU_FREQ_TABLE; |
121 | msg.handle = vgpu_get_handle(g); | 241 | msg.handle = vgpu_get_handle(g); |
122 | 242 | ||
123 | p->num_freqs = TEGRA_VGPU_GPU_FREQ_TABLE_SIZE; | ||
124 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); | 243 | err = vgpu_comm_sendrecv(&msg, sizeof(msg), sizeof(msg)); |
125 | err = err ? err : msg.ret; | 244 | err = err ? err : msg.ret; |
126 | if (err) { | 245 | if (err) { |
127 | nvgpu_err(g, "%s failed - %d", __func__, err); | 246 | nvgpu_err(g, "%s failed - %d", __func__, err); |
128 | return err; | 247 | goto done; |
129 | } | 248 | } |
130 | 249 | ||
131 | /* return frequency in Hz */ | 250 | handle = vgpu_ivc_oob_get_ptr(vgpu_ivc_get_server_vmid(), |
132 | for (i = 0; i < p->num_freqs; i++) | 251 | TEGRA_VGPU_QUEUE_CMD, (void **)&freqs, &oob_size); |
133 | vgpu_freq_table[i] = p->freqs[i] * 1000; | 252 | if (!handle) { |
253 | nvgpu_err(g, "failed to get ivm handle"); | ||
254 | err = -EINVAL; | ||
255 | goto done; | ||
256 | } | ||
134 | 257 | ||
135 | *freqs = vgpu_freq_table; | 258 | priv->freqs = nvgpu_kzalloc(g, sizeof(*priv->freqs) * (p->num_freqs)); |
136 | *num_freqs = p->num_freqs; | 259 | if (!priv->freqs) { |
260 | nvgpu_err(g, "failed to allocate memory"); | ||
261 | vgpu_ivc_oob_put_ptr(handle); | ||
262 | err = -ENOMEM; | ||
263 | goto done; | ||
264 | } | ||
265 | priv->num_freqs = p->num_freqs; | ||
137 | 266 | ||
138 | return 0; | 267 | for (i = 0; i < priv->num_freqs; i++) { |
268 | /* store frequency in Hz */ | ||
269 | priv->freqs[i] = (unsigned long)(freqs[i] * 1000); | ||
270 | } | ||
271 | |||
272 | vgpu_ivc_oob_put_ptr(handle); | ||
273 | |||
274 | done: | ||
275 | if (err == 0) { | ||
276 | *num_freqs = priv->num_freqs; | ||
277 | *freqs_out = priv->freqs; | ||
278 | } | ||
279 | |||
280 | nvgpu_mutex_release(&priv->vgpu_clk_get_freq_lock); | ||
281 | |||
282 | return err; | ||
139 | } | 283 | } |
140 | 284 | ||
141 | int vgpu_clk_cap_rate(struct gk20a *g, unsigned long rate) | 285 | int vgpu_clk_cap_rate(struct gk20a *g, unsigned long rate) |