summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/nvgpu/common/linux/nvlink.c
diff options
context:
space:
mode:
authorDavid Nieto <dmartineznie@nvidia.com>2017-12-07 19:48:09 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2018-01-25 20:39:53 -0500
commitfbdcc8a2d4c2b7f145b034ee7bde7105e66e0a4e (patch)
tree0bb7c6d0a1bbd723bf891f5c3287cb8abc315cd4 /drivers/gpu/nvgpu/common/linux/nvlink.c
parent37b8298a48ec65ca78048e68c8c3e1a060b8fb63 (diff)
gpu: nvgpu: Initial Nvlink driver skeleton
Adds the skeleton and integration of the GV100 endpoint driver to NVGPU (1) Adds a OS abstraction layer for the internal nvlink structure. (2) Adds linux specific integration with Nvlink core driver. (3) Adds function pointers for nvlink api, initialization and isr process. (4) Adds initial support for minion. (5) Adds new GPU enable properties to handle NVLINK presence (6) Adds new GPU enable properties for SG_PHY bypass (required for NVLINK over PCI) (7) Adds parsing of nvlink vbios structures. (8) Adds logging defines for NVGPU JIRA: EVLR-2328 Change-Id: I0720a165a15c7187892c8c1a0662ec598354ac06 Signed-off-by: David Nieto <dmartineznie@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/1644708 Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com>
Diffstat (limited to 'drivers/gpu/nvgpu/common/linux/nvlink.c')
-rw-r--r--drivers/gpu/nvgpu/common/linux/nvlink.c531
1 files changed, 531 insertions, 0 deletions
diff --git a/drivers/gpu/nvgpu/common/linux/nvlink.c b/drivers/gpu/nvgpu/common/linux/nvlink.c
new file mode 100644
index 00000000..eea6eda7
--- /dev/null
+++ b/drivers/gpu/nvgpu/common/linux/nvlink.c
@@ -0,0 +1,531 @@
1/*
2 * Copyright (c) 2018, NVIDIA CORPORATION. All rights reserved.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 */
16
17#include <gk20a/gk20a.h>
18#include <nvgpu/nvlink.h>
19#include <nvgpu/enabled.h>
20#include "module.h"
21
22#ifdef CONFIG_TEGRA_NVLINK
23#include <linux/platform/tegra/tegra-nvlink.h>
24#endif
25
26#ifdef CONFIG_TEGRA_NVLINK
27
28/*
29 * WAR: use this function to find detault link, as only one is supported
30 * on the library for now
31 * Returns NVLINK_MAX_LINKS_SW on failure
32 */
33static u32 __nvgpu_nvlink_get_link(struct nvlink_device *ndev)
34{
35 u32 link_id;
36 struct gk20a *g = (struct gk20a *) ndev->priv;
37
38 if (!g)
39 return NVLINK_MAX_LINKS_SW;
40
41 /* Lets find the detected link */
42 if (g->nvlink.initialized_links)
43 link_id = fls(g->nvlink.initialized_links);
44 else
45 return NVLINK_MAX_LINKS_SW;
46
47 if (g->nvlink.links[link_id].remote_info.is_connected)
48 return link_id;
49
50 return NVLINK_MAX_LINKS_SW;
51}
52static int nvgpu_nvlink_early_init(struct nvlink_device *ndev)
53{
54 struct gk20a *g = (struct gk20a *) ndev->priv;
55 int err;
56
57 /* For now master topology is the only one supported */
58 if (!ndev->is_master) {
59 nvgpu_log(g, gpu_dbg_info | gpu_dbg_nvlink,
60 "dGPU is not master of Nvlink link");
61 return -EINVAL;
62 }
63
64 err = g->ops.nvlink.early_init(g);
65 return err;
66}
67
68static int nvgpu_nvlink_link_early_init(struct nvlink_device *ndev)
69{
70 struct gk20a *g = (struct gk20a *) ndev->priv;
71 int err;
72 u32 link_id;
73
74 /*
75 * First check the topology and setup connectivity
76 * HACK: we are only enabling one link for now!!!
77 */
78 link_id = fls(g->nvlink.discovered_links);
79 g->nvlink.links[link_id].remote_info.is_connected = true;
80
81 err = g->ops.nvlink.link_early_init(g, BIT(link_id));
82
83 if (err == 0) {
84 g->nvlink.links[link_id].priv = (void *) &(ndev->link);
85 ndev->link.priv = (void *) g;
86 }
87 return err;
88}
89
90static int nvgpu_nvlink_interface_init(struct nvlink_device *ndev)
91{
92 int err;
93 struct gk20a *g = (struct gk20a *) ndev->priv;
94
95 err = g->ops.nvlink.interface_init(g);
96 return err;
97}
98
99static int nvgpu_nvlink_shutdown(struct nvlink_device *ndev)
100{
101 int err;
102 struct gk20a *g = (struct gk20a *) ndev->priv;
103
104 err = g->ops.nvlink.shutdown(g);
105 return 0;
106}
107
108static int nvgpu_nvlink_reg_init(struct nvlink_device *ndev)
109{
110 struct gk20a *g = (struct gk20a *) ndev->priv;
111 int err;
112
113 err = g->ops.nvlink.reg_init(g);
114
115 return err;
116}
117
118static u32 nvgpu_nvlink_get_link_mode(struct nvlink_device *ndev)
119{
120 struct gk20a *g = (struct gk20a *) ndev->priv;
121 u32 link_id;
122 u32 mode;
123
124 link_id = __nvgpu_nvlink_get_link(ndev);
125 if (link_id == NVLINK_MAX_LINKS_SW)
126 return -EINVAL;
127
128 mode = g->ops.nvlink.link_get_mode(g, link_id);
129
130 switch (mode) {
131 case nvgpu_nvlink_link_off:
132 return NVLINK_LINK_OFF;
133 case nvgpu_nvlink_link_hs:
134 return NVLINK_LINK_HS;
135 case nvgpu_nvlink_link_safe:
136 return NVLINK_LINK_SAFE;
137 case nvgpu_nvlink_link_fault:
138 return NVLINK_LINK_FAULT;
139 case nvgpu_nvlink_link_recovery:
140 return NVLINK_LINK_RECOVERY;
141 case nvgpu_nvlink_link_detect:
142 return NVLINK_LINK_DETECT;
143 case nvgpu_nvlink_link_reset:
144 return NVLINK_LINK_RESET;
145 case nvgpu_nvlink_link_enable_pm:
146 return NVLINK_LINK_ENABLE_PM;
147 case nvgpu_nvlink_link_disable_pm:
148 return NVLINK_LINK_DISABLE_PM;
149 case nvgpu_nvlink_link_disable_err_detect:
150 return NVLINK_LINK_DISABLE_ERR_DETECT;
151 case nvgpu_nvlink_link_lane_disable:
152 return NVLINK_LINK_LANE_DISABLE;
153 case nvgpu_nvlink_link_lane_shutdown:
154 return NVLINK_LINK_LANE_SHUTDOWN;
155 default:
156 nvgpu_log(g, gpu_dbg_info | gpu_dbg_nvlink,
157 "unsupported mode %u", mode);
158 }
159
160 return NVLINK_LINK_OFF;
161}
162
163static u32 nvgpu_nvlink_get_link_state(struct nvlink_device *ndev)
164{
165 struct gk20a *g = (struct gk20a *) ndev->priv;
166 u32 link_id;
167
168 link_id = __nvgpu_nvlink_get_link(ndev);
169 if (link_id == NVLINK_MAX_LINKS_SW)
170 return -EINVAL;
171
172 return g->ops.nvlink.link_get_state(g, link_id);
173}
174
175static int nvgpu_nvlink_set_link_mode(struct nvlink_device *ndev, u32 mode)
176{
177
178 struct gk20a *g = (struct gk20a *) ndev->priv;
179 u32 link_id;
180 u32 mode_sw;
181
182 link_id = __nvgpu_nvlink_get_link(ndev);
183 if (link_id == NVLINK_MAX_LINKS_SW)
184 return -EINVAL;
185
186 switch (mode) {
187 case NVLINK_LINK_OFF:
188 mode_sw = nvgpu_nvlink_link_off;
189 break;
190 case NVLINK_LINK_HS:
191 mode_sw = nvgpu_nvlink_link_hs;
192 break;
193 case NVLINK_LINK_SAFE:
194 mode_sw = nvgpu_nvlink_link_safe;
195 break;
196 case NVLINK_LINK_FAULT:
197 mode_sw = nvgpu_nvlink_link_fault;
198 break;
199 case NVLINK_LINK_RECOVERY:
200 mode_sw = nvgpu_nvlink_link_recovery;
201 break;
202 case NVLINK_LINK_DETECT:
203 mode_sw = nvgpu_nvlink_link_detect;
204 break;
205 case NVLINK_LINK_RESET:
206 mode_sw = nvgpu_nvlink_link_reset;
207 break;
208 case NVLINK_LINK_ENABLE_PM:
209 mode_sw = nvgpu_nvlink_link_enable_pm;
210 break;
211 case NVLINK_LINK_DISABLE_PM:
212 mode_sw = nvgpu_nvlink_link_disable_pm;
213 break;
214 case NVLINK_LINK_LANE_DISABLE:
215 mode_sw = nvgpu_nvlink_link_lane_disable;
216 break;
217 case NVLINK_LINK_LANE_SHUTDOWN:
218 mode_sw = nvgpu_nvlink_link_lane_shutdown;
219 break;
220 default:
221 mode_sw = nvgpu_nvlink_link_off;
222 }
223
224 return g->ops.nvlink.link_set_mode(g, link_id, mode_sw);
225}
226
227static void nvgpu_nvlink_get_tx_sublink_state(struct nvlink_device *ndev,
228 u32 *state)
229{
230 struct gk20a *g = (struct gk20a *) ndev->priv;
231 u32 link_id;
232
233 link_id = __nvgpu_nvlink_get_link(ndev);
234 if (link_id == NVLINK_MAX_LINKS_SW)
235 return;
236 if (state)
237 *state = g->ops.nvlink.get_tx_sublink_state(g, link_id);
238}
239
240static void nvgpu_nvlink_get_rx_sublink_state(struct nvlink_device *ndev,
241 u32 *state)
242{
243 struct gk20a *g = (struct gk20a *) ndev->priv;
244 u32 link_id;
245
246 link_id = __nvgpu_nvlink_get_link(ndev);
247 if (link_id == NVLINK_MAX_LINKS_SW)
248 return;
249 if (state)
250 *state = g->ops.nvlink.get_rx_sublink_state(g, link_id);
251}
252
253static u32 nvgpu_nvlink_get_sublink_mode(struct nvlink_device *ndev,
254 bool is_rx_sublink)
255{
256 struct gk20a *g = (struct gk20a *) ndev->priv;
257 u32 link_id;
258 u32 mode;
259
260 link_id = __nvgpu_nvlink_get_link(ndev);
261 if (link_id == NVLINK_MAX_LINKS_SW)
262 return -EINVAL;
263
264 mode = g->ops.nvlink.get_sublink_mode(g, link_id, is_rx_sublink);
265 switch (mode) {
266 case nvgpu_nvlink_sublink_tx_hs:
267 return NVLINK_TX_HS;
268 case nvgpu_nvlink_sublink_tx_off:
269 return NVLINK_TX_OFF;
270 case nvgpu_nvlink_sublink_tx_single_lane:
271 return NVLINK_TX_SINGLE_LANE;
272 case nvgpu_nvlink_sublink_tx_safe:
273 return NVLINK_TX_SAFE;
274 case nvgpu_nvlink_sublink_tx_enable_pm:
275 return NVLINK_TX_ENABLE_PM;
276 case nvgpu_nvlink_sublink_tx_disable_pm:
277 return NVLINK_TX_DISABLE_PM;
278 case nvgpu_nvlink_sublink_tx_common:
279 return NVLINK_TX_COMMON;
280 case nvgpu_nvlink_sublink_tx_common_disable:
281 return NVLINK_TX_COMMON_DISABLE;
282 case nvgpu_nvlink_sublink_tx_data_ready:
283 return NVLINK_TX_DATA_READY;
284 case nvgpu_nvlink_sublink_tx_prbs_en:
285 return NVLINK_TX_PRBS_EN;
286 case nvgpu_nvlink_sublink_rx_hs:
287 return NVLINK_RX_HS;
288 case nvgpu_nvlink_sublink_rx_enable_pm:
289 return NVLINK_RX_ENABLE_PM;
290 case nvgpu_nvlink_sublink_rx_disable_pm:
291 return NVLINK_RX_DISABLE_PM;
292 case nvgpu_nvlink_sublink_rx_single_lane:
293 return NVLINK_RX_SINGLE_LANE;
294 case nvgpu_nvlink_sublink_rx_safe:
295 return NVLINK_RX_SAFE;
296 case nvgpu_nvlink_sublink_rx_off:
297 return NVLINK_RX_OFF;
298 case nvgpu_nvlink_sublink_rx_rxcal:
299 return NVLINK_RX_RXCAL;
300 default:
301 nvgpu_log(g, gpu_dbg_nvlink, "Unsupported mode: %u", mode);
302 break;
303 }
304
305 if (is_rx_sublink)
306 return NVLINK_RX_OFF;
307 return NVLINK_TX_OFF;
308}
309
310static int nvgpu_nvlink_set_sublink_mode(struct nvlink_device *ndev,
311 bool is_rx_sublink, u32 mode)
312{
313 struct gk20a *g = (struct gk20a *) ndev->priv;
314 u32 link_id;
315 u32 mode_sw;
316
317 link_id = __nvgpu_nvlink_get_link(ndev);
318 if (link_id == NVLINK_MAX_LINKS_SW)
319 return -EINVAL;
320
321 if (!is_rx_sublink) {
322 switch (mode) {
323 case NVLINK_TX_HS:
324 mode_sw = nvgpu_nvlink_sublink_tx_hs;
325 break;
326 case NVLINK_TX_ENABLE_PM:
327 mode_sw = nvgpu_nvlink_sublink_tx_enable_pm;
328 break;
329 case NVLINK_TX_DISABLE_PM:
330 mode_sw = nvgpu_nvlink_sublink_tx_disable_pm;
331 break;
332 case NVLINK_TX_SINGLE_LANE:
333 mode_sw = nvgpu_nvlink_sublink_tx_single_lane;
334 break;
335 case NVLINK_TX_SAFE:
336 mode_sw = nvgpu_nvlink_sublink_tx_safe;
337 break;
338 case NVLINK_TX_OFF:
339 mode_sw = nvgpu_nvlink_sublink_tx_off;
340 break;
341 case NVLINK_TX_COMMON:
342 mode_sw = nvgpu_nvlink_sublink_tx_common;
343 break;
344 case NVLINK_TX_COMMON_DISABLE:
345 mode_sw = nvgpu_nvlink_sublink_tx_common_disable;
346 break;
347 case NVLINK_TX_DATA_READY:
348 mode_sw = nvgpu_nvlink_sublink_tx_data_ready;
349 break;
350 case NVLINK_TX_PRBS_EN:
351 mode_sw = nvgpu_nvlink_sublink_tx_prbs_en;
352 break;
353 default:
354 return -EINVAL;
355 }
356 } else {
357 switch (mode) {
358 case NVLINK_RX_HS:
359 mode_sw = nvgpu_nvlink_sublink_rx_hs;
360 break;
361 case NVLINK_RX_ENABLE_PM:
362 mode_sw = nvgpu_nvlink_sublink_rx_enable_pm;
363 break;
364 case NVLINK_RX_DISABLE_PM:
365 mode_sw = nvgpu_nvlink_sublink_rx_disable_pm;
366 break;
367 case NVLINK_RX_SINGLE_LANE:
368 mode_sw = nvgpu_nvlink_sublink_rx_single_lane;
369 break;
370 case NVLINK_RX_SAFE:
371 mode_sw = nvgpu_nvlink_sublink_rx_safe;
372 break;
373 case NVLINK_RX_OFF:
374 mode_sw = nvgpu_nvlink_sublink_rx_off;
375 break;
376 case NVLINK_RX_RXCAL:
377 mode_sw = nvgpu_nvlink_sublink_rx_rxcal;
378 break;
379 default:
380 return -EINVAL;
381 }
382 }
383
384 return g->ops.nvlink.set_sublink_mode(g, link_id, is_rx_sublink,
385 mode_sw);
386}
387#endif
388
389u32 nvgpu_nvlink_enumerate(struct gk20a *g)
390{
391 u32 err = -ENODEV;
392#ifdef CONFIG_TEGRA_NVLINK
393 struct nvlink_device *ndev;
394
395 ndev = (struct nvlink_device *) g->nvlink.priv;
396
397 if (ndev)
398 err = nvlink_enumerate(ndev);
399#endif
400 return err;
401}
402
403u32 nvgpu_nvlink_train(struct gk20a *g, u32 link_id, bool from_off)
404{
405 u32 err = -ENODEV;
406#ifdef CONFIG_TEGRA_NVLINK
407 struct nvlink_device *ndev;
408
409 ndev = (struct nvlink_device *) g->nvlink.priv;
410
411 if (!ndev)
412 return -ENODEV;
413
414 /* Check if the link is connected */
415 if (!g->nvlink.links[link_id].remote_info.is_connected)
416 return -ENODEV;
417
418 if (from_off)
419 return nvlink_transition_intranode_conn_off_to_safe(ndev);
420 return nvlink_train_intranode_conn_safe_to_hs(ndev);
421
422#endif
423 return err;
424}
425
426u32 nvgpu_nvlink_probe(struct gk20a *g)
427{
428#ifdef CONFIG_TEGRA_NVLINK
429 u32 err = 0;
430 struct device_node *np = nvgpu_get_node(g);
431 struct device_node *nvlink_np = NULL, *endp_np = NULL;
432 struct nvlink_device *ndev;
433 u32 phys_link_id;
434
435 /* Parse DT */
436 if (np) {
437 nvlink_np = of_get_child_by_name(np, "nvidia,nvlink");
438 if (nvlink_np)
439 endp_np = of_get_child_by_name(np, "endpoint");
440 }
441
442 if (!endp_np) {
443 nvgpu_log(g, gpu_dbg_info | gpu_dbg_nvlink,
444 "No Nvlink DT detected");
445 return -ENODEV;
446 }
447
448 /* Allocating structures */
449 ndev = nvgpu_kzalloc(g, sizeof(struct nvlink_device));
450 if (!ndev) {
451 nvgpu_err(g, "OOM while allocating nvlink device struct");
452 return -ENOMEM;
453 }
454
455 ndev->priv = (void *) g;
456 g->nvlink.priv = (void *) ndev;
457
458 /* Parse DT structure to detect endpoint topology */
459 of_property_read_u32(endp_np, "local_dev_id", &ndev->device_id);
460 of_property_read_u32(endp_np, "local_link_id", &ndev->link.link_id);
461 ndev->is_master = of_property_read_bool(endp_np, "is_master");
462 of_property_read_u32(endp_np, "remote_dev_id",
463 &ndev->link.remote_dev_info.device_id);
464 of_property_read_u32(endp_np, "remote_link_id",
465 &ndev->link.remote_dev_info.link_id);
466 of_property_read_u32(endp_np, "physical_link",
467 &phys_link_id);
468
469 g->nvlink.topology_connected_links = BIT(phys_link_id);
470
471 mutex_init(&ndev->init_state_mutex);
472
473 /* Check that we are in dGPU mode */
474 if (ndev->device_id != NVLINK_ENDPT_GV100) {
475 nvgpu_err(g, "Local nvlink device is not dGPU");
476 err = -EINVAL;
477 goto free_nvlink;
478 }
479
480 err = nvlink_set_init_state(ndev, NVLINK_DEV_OFF);
481 if (err) {
482 nvgpu_err(g, "Error initalizing device state to OFF");
483 goto free_nvlink;
484 }
485
486 /* Fill in device struct */
487 ndev->dev_ops.dev_early_init = nvgpu_nvlink_early_init;
488 ndev->dev_ops.dev_interface_init = nvgpu_nvlink_interface_init;
489 ndev->dev_ops.dev_reg_init = nvgpu_nvlink_reg_init;
490 ndev->dev_ops.dev_shutdown = nvgpu_nvlink_shutdown;
491
492 /* Fill in the link struct */
493 ndev->link.device_id = ndev->device_id;
494 ndev->link.mode = NVLINK_LINK_OFF;
495 ndev->link.link_ops.get_link_mode = nvgpu_nvlink_get_link_mode;
496 ndev->link.link_ops.set_link_mode = nvgpu_nvlink_set_link_mode;
497 ndev->link.link_ops.get_sublink_mode = nvgpu_nvlink_get_sublink_mode;
498 ndev->link.link_ops.set_sublink_mode = nvgpu_nvlink_set_sublink_mode;
499 ndev->link.link_ops.get_link_state = nvgpu_nvlink_get_link_state;
500 ndev->link.link_ops.get_tx_sublink_state =
501 nvgpu_nvlink_get_tx_sublink_state;
502 ndev->link.link_ops.get_rx_sublink_state =
503 nvgpu_nvlink_get_rx_sublink_state;
504 ndev->link.link_ops.link_early_init =
505 nvgpu_nvlink_link_early_init;
506
507 /* Register device with core driver*/
508 err = nvlink_register_device(ndev);
509 if (err) {
510 nvgpu_err(g, "failed on nvlink device registration");
511 goto free_nvlink;
512 }
513
514 /* Register link with core driver */
515 err = nvlink_register_link(&ndev->link);
516 if (err) {
517 nvgpu_err(g, "failed on nvlink link registration");
518 goto free_nvlink;
519 }
520
521 /* Enable NVLINK support */
522 __nvgpu_set_enabled(g, NVGPU_SUPPORT_NVLINK, true);
523free_nvlink:
524 nvgpu_kfree(g, ndev);
525 return err;
526
527#else
528 return -ENODEV;
529#endif
530}
531