summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/gp106/xve_gp106.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/nvgpu/gp106/xve_gp106.c')
-rw-r--r--drivers/gpu/nvgpu/gp106/xve_gp106.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/gp106/xve_gp106.c b/drivers/gpu/nvgpu/gp106/xve_gp106.c
new file mode 100644
index 00000000..5acf35b2
--- /dev/null
+++ b/drivers/gpu/nvgpu/gp106/xve_gp106.c
@@ -0,0 +1,503 @@
1/*
2 * Copyright (c) 2016-2017, NVIDIA CORPORATION. All rights reserved.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 * DEALINGS IN THE SOFTWARE.
21 */
22
23#include "gk20a/gk20a.h"
24#include "gp106/bios_gp106.h"
25#include "gp106/xve_gp106.h"
26#include "common/linux/os_linux.h"
27
28#include <nvgpu/bug.h>
29#include <nvgpu/xve.h>
30
31#include <nvgpu/hw/gp106/hw_xp_gp106.h>
32#include <nvgpu/hw/gp106/hw_xve_gp106.h>
33
34#define NV_PCFG 0x88000
35
36void xve_xve_writel_gp106(struct gk20a *g, u32 reg, u32 val)
37{
38 gk20a_writel(g, NV_PCFG + reg, val);
39}
40
41u32 xve_xve_readl_gp106(struct gk20a *g, u32 reg)
42{
43 return gk20a_readl(g, NV_PCFG + reg);
44}
45
46/**
47 * Resets the GPU (except the XVE/XP).
48 */
49void xve_reset_gpu_gp106(struct gk20a *g)
50{
51 u32 reset;
52
53 /*
54 * This resets the GPU except for the XVE/XP (since then we would lose
55 * the dGPU from the bus). t18x has a HW limitation where once that
56 * happens the GPU is gone until the entire system is reset.
57 *
58 * We have to use the auto-deassert register since we won't be able to
59 * access the GPU after the GPU goes into reset. This appears like the
60 * GPU has dropped from the bus and causes nvgpu to reset the entire
61 * system. Whoops!
62 */
63 reset = xve_reset_reset_m() |
64 xve_reset_gpu_on_sw_reset_m() |
65 xve_reset_counter_en_m() |
66 xve_reset_counter_val_f(0x7ff) |
67 xve_reset_clock_on_sw_reset_m() |
68 xve_reset_clock_counter_en_m() |
69 xve_reset_clock_counter_val_f(0x7ff);
70
71 g->ops.xve.xve_writel(g, xve_reset_r(), reset | xve_reset_reset_m());
72
73 /*
74 * Don't access GPU until _after_ it's back out of reset!
75 */
76 nvgpu_msleep(100);
77 g->ops.xve.xve_writel(g, xve_reset_r(), 0);
78}
79
80/**
81 * Places one of:
82 *
83 * %GPU_XVE_SPEED_2P5
84 * %GPU_XVE_SPEED_5P0
85 * %GPU_XVE_SPEED_8P0
86 *
87 * in the u32 pointed to by @xve_link_speed. If for some reason an unknown PCIe
88 * bus speed is detected then *@xve_link_speed is not touched and -ENODEV is
89 * returned.
90 */
91int xve_get_speed_gp106(struct gk20a *g, u32 *xve_link_speed)
92{
93 u32 status;
94 u32 link_speed, real_link_speed = 0;
95
96 status = g->ops.xve.xve_readl(g, xve_link_control_status_r());
97
98 link_speed = xve_link_control_status_link_speed_v(status);
99
100 /*
101 * Can't use a switch statement becuase switch statements dont work with
102 * function calls.
103 */
104 if (link_speed == xve_link_control_status_link_speed_link_speed_2p5_v())
105 real_link_speed = GPU_XVE_SPEED_2P5;
106 if (link_speed == xve_link_control_status_link_speed_link_speed_5p0_v())
107 real_link_speed = GPU_XVE_SPEED_5P0;
108 if (link_speed == xve_link_control_status_link_speed_link_speed_8p0_v())
109 real_link_speed = GPU_XVE_SPEED_8P0;
110
111 if (!real_link_speed) {
112 pr_warn("%s: Unknown PCIe bus speed!\n", __func__);
113 return -ENODEV;
114 }
115
116 *xve_link_speed = real_link_speed;
117 return 0;
118}
119
120/**
121 * Set the mask for L0s in the XVE.
122 *
123 * When @status is non-zero the mask for L0s is set which _disables_ L0s. When
124 * @status is zero L0s is no longer masked and may be enabled.
125 */
126static void set_xve_l0s_mask(struct gk20a *g, bool status)
127{
128 u32 xve_priv;
129 u32 status_bit = status ? 1 : 0;
130
131 xve_priv = g->ops.xve.xve_readl(g, xve_priv_xv_r());
132
133 xve_priv = set_field(xve_priv,
134 xve_priv_xv_cya_l0s_enable_m(),
135 xve_priv_xv_cya_l0s_enable_f(status_bit));
136
137 g->ops.xve.xve_writel(g, xve_priv_xv_r(), xve_priv);
138}
139
140/**
141 * Set the mask for L1 in the XVE.
142 *
143 * When @status is non-zero the mask for L1 is set which _disables_ L0s. When
144 * @status is zero L1 is no longer masked and may be enabled.
145 */
146static void set_xve_l1_mask(struct gk20a *g, int status)
147{
148 u32 xve_priv;
149 u32 status_bit = status ? 1 : 0;
150
151 xve_priv = g->ops.xve.xve_readl(g, xve_priv_xv_r());
152
153 xve_priv = set_field(xve_priv,
154 xve_priv_xv_cya_l1_enable_m(),
155 xve_priv_xv_cya_l1_enable_f(status_bit));
156
157 g->ops.xve.xve_writel(g, xve_priv_xv_r(), xve_priv);
158}
159
160/**
161 * Disable ASPM permanently.
162 */
163void xve_disable_aspm_gp106(struct gk20a *g)
164{
165 u32 xve_priv;
166
167 xve_priv = g->ops.xve.xve_readl(g, xve_priv_xv_r());
168
169 set_xve_l0s_mask(g, true);
170 set_xve_l1_mask(g, true);
171}
172
173/**
174 * When doing the speed change disable power saving features.
175 */
176static void disable_aspm_gp106(struct gk20a *g)
177{
178 u32 xve_priv;
179
180 xve_priv = g->ops.xve.xve_readl(g, xve_priv_xv_r());
181
182 /*
183 * Store prior ASPM state so we can restore it later on.
184 */
185 g->xve_l0s = xve_priv_xv_cya_l0s_enable_v(xve_priv);
186 g->xve_l1 = xve_priv_xv_cya_l1_enable_v(xve_priv);
187
188 set_xve_l0s_mask(g, true);
189 set_xve_l1_mask(g, true);
190}
191
192/**
193 * Restore the state saved by disable_aspm_gp106().
194 */
195static void enable_aspm_gp106(struct gk20a *g)
196{
197 set_xve_l0s_mask(g, g->xve_l0s);
198 set_xve_l1_mask(g, g->xve_l1);
199}
200
201/*
202 * Error checking is done in xve_set_speed_gp106.
203 */
204static int __do_xve_set_speed_gp106(struct gk20a *g, u32 next_link_speed)
205{
206 u32 current_link_speed, new_link_speed;
207 u32 dl_mgr, saved_dl_mgr;
208 u32 pl_link_config;
209 u32 link_control_status, link_speed_setting, link_width;
210 struct nvgpu_timeout timeout;
211 int attempts = 10, err_status = 0;
212
213 g->ops.xve.get_speed(g, &current_link_speed);
214 xv_sc_dbg(PRE_CHANGE, "Executing PCIe link change.");
215 xv_sc_dbg(PRE_CHANGE, " Current speed: %s",
216 xve_speed_to_str(current_link_speed));
217 xv_sc_dbg(PRE_CHANGE, " Next speed: %s",
218 xve_speed_to_str(next_link_speed));
219 xv_sc_dbg(PRE_CHANGE, " PL_LINK_CONFIG: 0x%08x",
220 gk20a_readl(g, xp_pl_link_config_r(0)));
221
222 xv_sc_dbg(DISABLE_ASPM, "Disabling ASPM...");
223 disable_aspm_gp106(g);
224 xv_sc_dbg(DISABLE_ASPM, " Done!");
225
226 xv_sc_dbg(DL_SAFE_MODE, "Putting DL in safe mode...");
227 saved_dl_mgr = gk20a_readl(g, xp_dl_mgr_r(0));
228
229 /*
230 * Put the DL in safe mode.
231 */
232 dl_mgr = saved_dl_mgr;
233 dl_mgr |= xp_dl_mgr_safe_timing_f(1);
234 gk20a_writel(g, xp_dl_mgr_r(0), dl_mgr);
235 xv_sc_dbg(DL_SAFE_MODE, " Done!");
236
237 nvgpu_timeout_init(g, &timeout, GPU_XVE_TIMEOUT_MS,
238 NVGPU_TIMER_CPU_TIMER);
239
240 xv_sc_dbg(CHECK_LINK, "Checking for link idle...");
241 do {
242 pl_link_config = gk20a_readl(g, xp_pl_link_config_r(0));
243 if ((xp_pl_link_config_ltssm_status_f(pl_link_config) ==
244 xp_pl_link_config_ltssm_status_idle_v()) &&
245 (xp_pl_link_config_ltssm_directive_f(pl_link_config) ==
246 xp_pl_link_config_ltssm_directive_normal_operations_v()))
247 break;
248 } while (!nvgpu_timeout_expired(&timeout));
249
250 if (nvgpu_timeout_peek_expired(&timeout)) {
251 err_status = -ETIMEDOUT;
252 goto done;
253 }
254
255 xv_sc_dbg(CHECK_LINK, " Done");
256
257 xv_sc_dbg(LINK_SETTINGS, "Preparing next link settings");
258 pl_link_config &= ~xp_pl_link_config_max_link_rate_m();
259 switch (next_link_speed) {
260 case GPU_XVE_SPEED_2P5:
261 link_speed_setting =
262 xve_link_control_status_link_speed_link_speed_2p5_v();
263 pl_link_config |= xp_pl_link_config_max_link_rate_f(
264 xp_pl_link_config_max_link_rate_2500_mtps_v());
265 break;
266 case GPU_XVE_SPEED_5P0:
267 link_speed_setting =
268 xve_link_control_status_link_speed_link_speed_5p0_v();
269 pl_link_config |= xp_pl_link_config_max_link_rate_f(
270 xp_pl_link_config_max_link_rate_5000_mtps_v());
271 break;
272 case GPU_XVE_SPEED_8P0:
273 link_speed_setting =
274 xve_link_control_status_link_speed_link_speed_8p0_v();
275 pl_link_config |= xp_pl_link_config_max_link_rate_f(
276 xp_pl_link_config_max_link_rate_8000_mtps_v());
277 break;
278 default:
279 BUG(); /* Should never be hit. */
280 }
281
282 link_control_status =
283 g->ops.xve.xve_readl(g, xve_link_control_status_r());
284 link_width = xve_link_control_status_link_width_v(link_control_status);
285
286 pl_link_config &= ~xp_pl_link_config_target_tx_width_m();
287
288 /* Can't use a switch due to oddities in register definitions. */
289 if (link_width == xve_link_control_status_link_width_x1_v())
290 pl_link_config |= xp_pl_link_config_target_tx_width_f(
291 xp_pl_link_config_target_tx_width_x1_v());
292 else if (link_width == xve_link_control_status_link_width_x2_v())
293 pl_link_config |= xp_pl_link_config_target_tx_width_f(
294 xp_pl_link_config_target_tx_width_x2_v());
295 else if (link_width == xve_link_control_status_link_width_x4_v())
296 pl_link_config |= xp_pl_link_config_target_tx_width_f(
297 xp_pl_link_config_target_tx_width_x4_v());
298 else if (link_width == xve_link_control_status_link_width_x8_v())
299 pl_link_config |= xp_pl_link_config_target_tx_width_f(
300 xp_pl_link_config_target_tx_width_x8_v());
301 else if (link_width == xve_link_control_status_link_width_x16_v())
302 pl_link_config |= xp_pl_link_config_target_tx_width_f(
303 xp_pl_link_config_target_tx_width_x16_v());
304 else
305 BUG();
306
307 xv_sc_dbg(LINK_SETTINGS, " pl_link_config = 0x%08x", pl_link_config);
308 xv_sc_dbg(LINK_SETTINGS, " Done");
309
310 xv_sc_dbg(EXEC_CHANGE, "Running link speed change...");
311
312 nvgpu_timeout_init(g, &timeout, GPU_XVE_TIMEOUT_MS,
313 NVGPU_TIMER_CPU_TIMER);
314 do {
315 gk20a_writel(g, xp_pl_link_config_r(0), pl_link_config);
316 if (pl_link_config ==
317 gk20a_readl(g, xp_pl_link_config_r(0)))
318 break;
319 } while (!nvgpu_timeout_expired(&timeout));
320
321 if (nvgpu_timeout_peek_expired(&timeout)) {
322 err_status = -ETIMEDOUT;
323 goto done;
324 }
325
326 xv_sc_dbg(EXEC_CHANGE, " Wrote PL_LINK_CONFIG.");
327
328 pl_link_config = gk20a_readl(g, xp_pl_link_config_r(0));
329
330 do {
331 pl_link_config = set_field(pl_link_config,
332 xp_pl_link_config_ltssm_directive_m(),
333 xp_pl_link_config_ltssm_directive_f(
334 xp_pl_link_config_ltssm_directive_change_speed_v()));
335
336 xv_sc_dbg(EXEC_CHANGE, " Executing change (0x%08x)!",
337 pl_link_config);
338 gk20a_writel(g, xp_pl_link_config_r(0), pl_link_config);
339
340 /*
341 * Read NV_XP_PL_LINK_CONFIG until the link has swapped to
342 * the target speed.
343 */
344 nvgpu_timeout_init(g, &timeout, GPU_XVE_TIMEOUT_MS,
345 NVGPU_TIMER_CPU_TIMER);
346 do {
347 pl_link_config = gk20a_readl(g, xp_pl_link_config_r(0));
348 if (pl_link_config != 0xfffffff &&
349 (xp_pl_link_config_ltssm_status_f(pl_link_config) ==
350 xp_pl_link_config_ltssm_status_idle_v()) &&
351 (xp_pl_link_config_ltssm_directive_f(pl_link_config) ==
352 xp_pl_link_config_ltssm_directive_normal_operations_v()))
353 break;
354 } while (!nvgpu_timeout_expired(&timeout));
355
356 if (nvgpu_timeout_peek_expired(&timeout)) {
357 err_status = -ETIMEDOUT;
358 xv_sc_dbg(EXEC_CHANGE, " timeout; pl_link_config = 0x%x",
359 pl_link_config);
360 }
361
362 xv_sc_dbg(EXEC_CHANGE, " Change done... Checking status");
363
364 if (pl_link_config == 0xffffffff) {
365 WARN(1, "GPU fell of PCI bus!?");
366
367 /*
368 * The rest of the driver is probably about to
369 * explode...
370 */
371 BUG();
372 }
373
374 link_control_status =
375 g->ops.xve.xve_readl(g, xve_link_control_status_r());
376 xv_sc_dbg(EXEC_CHANGE, " target %d vs current %d",
377 link_speed_setting,
378 xve_link_control_status_link_speed_v(link_control_status));
379
380 if (err_status == -ETIMEDOUT) {
381 xv_sc_dbg(EXEC_CHANGE, " Oops timed out?");
382 break;
383 }
384 } while (attempts-- > 0 &&
385 link_speed_setting !=
386 xve_link_control_status_link_speed_v(link_control_status));
387
388 xv_sc_dbg(EXEC_VERIF, "Verifying speed change...");
389
390 /*
391 * Check that the new link speed is actually active. If we failed to
392 * change to the new link speed then return to the link speed setting
393 * pre-speed change.
394 */
395 new_link_speed = xve_link_control_status_link_speed_v(
396 link_control_status);
397 if (link_speed_setting != new_link_speed) {
398 u32 link_config = gk20a_readl(g, xp_pl_link_config_r(0));
399
400 xv_sc_dbg(EXEC_VERIF, " Current and target speeds mismatch!");
401 xv_sc_dbg(EXEC_VERIF, " LINK_CONTROL_STATUS: 0x%08x",
402 g->ops.xve.xve_readl(g, xve_link_control_status_r()));
403 xv_sc_dbg(EXEC_VERIF, " Link speed is %s - should be %s",
404 xve_speed_to_str(new_link_speed),
405 xve_speed_to_str(link_speed_setting));
406
407 link_config &= ~xp_pl_link_config_max_link_rate_m();
408 if (new_link_speed ==
409 xve_link_control_status_link_speed_link_speed_2p5_v())
410 link_config |= xp_pl_link_config_max_link_rate_f(
411 xp_pl_link_config_max_link_rate_2500_mtps_v());
412 else if (new_link_speed ==
413 xve_link_control_status_link_speed_link_speed_5p0_v())
414 link_config |= xp_pl_link_config_max_link_rate_f(
415 xp_pl_link_config_max_link_rate_5000_mtps_v());
416 else if (new_link_speed ==
417 xve_link_control_status_link_speed_link_speed_8p0_v())
418 link_config |= xp_pl_link_config_max_link_rate_f(
419 xp_pl_link_config_max_link_rate_8000_mtps_v());
420 else
421 link_config |= xp_pl_link_config_max_link_rate_f(
422 xp_pl_link_config_max_link_rate_2500_mtps_v());
423
424 gk20a_writel(g, xp_pl_link_config_r(0), link_config);
425 err_status = -ENODEV;
426 } else {
427 xv_sc_dbg(EXEC_VERIF, " Current and target speeds match!");
428 err_status = 0;
429 }
430
431done:
432 /* Restore safe timings. */
433 xv_sc_dbg(CLEANUP, "Restoring saved DL settings...");
434 gk20a_writel(g, xp_dl_mgr_r(0), saved_dl_mgr);
435 xv_sc_dbg(CLEANUP, " Done");
436
437 xv_sc_dbg(CLEANUP, "Re-enabling ASPM settings...");
438 enable_aspm_gp106(g);
439 xv_sc_dbg(CLEANUP, " Done");
440
441 return err_status;
442}
443
444/**
445 * Sets the PCIe link speed to @xve_link_speed which must be one of:
446 *
447 * %GPU_XVE_SPEED_2P5
448 * %GPU_XVE_SPEED_5P0
449 * %GPU_XVE_SPEED_8P0
450 *
451 * If an error is encountered an appropriate error will be returned.
452 */
453int xve_set_speed_gp106(struct gk20a *g, u32 next_link_speed)
454{
455 u32 current_link_speed;
456 int err;
457
458 if ((next_link_speed & GPU_XVE_SPEED_MASK) == 0)
459 return -EINVAL;
460
461 err = g->ops.xve.get_speed(g, &current_link_speed);
462 if (err)
463 return err;
464
465 /* No-op. */
466 if (current_link_speed == next_link_speed)
467 return 0;
468
469 return __do_xve_set_speed_gp106(g, next_link_speed);
470}
471
472/**
473 * Places a bitmask of available speeds for gp106 in @speed_mask.
474 */
475void xve_available_speeds_gp106(struct gk20a *g, u32 *speed_mask)
476{
477 *speed_mask = GPU_XVE_SPEED_2P5 | GPU_XVE_SPEED_5P0;
478}
479
480#if defined(CONFIG_PCI_MSI)
481void xve_rearm_msi_gp106(struct gk20a *g)
482{
483 /* We just need to write a dummy val in the CYA_2 offset */
484 g->ops.xve.xve_writel(g, xve_cya_2_r(), 0);
485}
486#endif
487
488void xve_enable_shadow_rom_gp106(struct gk20a *g)
489{
490 g->ops.xve.xve_writel(g, xve_rom_ctrl_r(),
491 xve_rom_ctrl_rom_shadow_enabled_f());
492}
493
494void xve_disable_shadow_rom_gp106(struct gk20a *g)
495{
496 g->ops.xve.xve_writel(g, xve_rom_ctrl_r(),
497 xve_rom_ctrl_rom_shadow_disabled_f());
498}
499
500u32 xve_get_link_control_status(struct gk20a *g)
501{
502 return g->ops.xve.xve_readl(g, xve_link_control_status_r());
503}