1 /*
2 * SPDX-FileCopyrightText: Copyright (c) 2020-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3 * SPDX-License-Identifier: MIT
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21 * DEALINGS IN THE SOFTWARE.
22 */
23
24 #include "common_nvswitch.h"
25 #include "cci/cci_priv_nvswitch.h"
26
27 /* -------------------- Object construction/initialization ------------------- */
28
29 NvBool
nvswitch_is_cci_supported(nvswitch_device * device)30 nvswitch_is_cci_supported
31 (
32 nvswitch_device *device
33 )
34 {
35 return device->hal.nvswitch_is_cci_supported(device);
36 }
37
38 NvlStatus
nvswitch_cci_discovery(nvswitch_device * device)39 nvswitch_cci_discovery
40 (
41 nvswitch_device *device
42 )
43 {
44 return device->hal.nvswitch_cci_discovery(device);
45 }
46
47 void
nvswitch_cci_setup_gpio_pins(nvswitch_device * device)48 nvswitch_cci_setup_gpio_pins
49 (
50 nvswitch_device *device
51 )
52 {
53 device->hal.nvswitch_cci_setup_gpio_pins(device);
54 }
55
56 NvlStatus
nvswitch_cci_ports_cpld_read(nvswitch_device * device,NvU8 reg,NvU8 * pData)57 nvswitch_cci_ports_cpld_read
58 (
59 nvswitch_device *device,
60 NvU8 reg,
61 NvU8 *pData
62 )
63 {
64 return device->hal.nvswitch_cci_ports_cpld_read(device, reg, pData);
65 }
66
67 NvlStatus
nvswitch_cci_ports_cpld_write(nvswitch_device * device,NvU8 reg,NvU8 data)68 nvswitch_cci_ports_cpld_write
69 (
70 nvswitch_device *device,
71 NvU8 reg,
72 NvU8 data
73 )
74 {
75 return device->hal.nvswitch_cci_ports_cpld_write(device, reg, data);
76 }
77
78 NvlStatus
nvswitch_cci_reset(nvswitch_device * device)79 nvswitch_cci_reset
80 (
81 nvswitch_device *device
82 )
83 {
84 return device->hal.nvswitch_cci_reset(device);
85 }
86
87 NvlStatus
nvswitch_cci_reset_links(nvswitch_device * device,NvU64 linkMask)88 nvswitch_cci_reset_links
89 (
90 nvswitch_device *device,
91 NvU64 linkMask
92 )
93 {
94 return device->hal.nvswitch_cci_reset_links(device, linkMask);
95 }
96
97 void
nvswitch_cci_get_xcvrs_present(nvswitch_device * device,NvU32 * pMaskPresent)98 nvswitch_cci_get_xcvrs_present
99 (
100 nvswitch_device *device,
101 NvU32 *pMaskPresent
102 )
103 {
104 device->hal.nvswitch_cci_get_xcvrs_present(device, pMaskPresent);
105 }
106
107 void
nvswitch_cci_get_xcvrs_present_change(nvswitch_device * device,NvU32 * pMaskPresentChange)108 nvswitch_cci_get_xcvrs_present_change
109 (
110 nvswitch_device *device,
111 NvU32 *pMaskPresentChange
112 )
113 {
114 device->hal.nvswitch_cci_get_xcvrs_present_change(device, pMaskPresentChange);
115 }
116
117 void
nvswitch_cci_update_link_state_led(nvswitch_device * device)118 nvswitch_cci_update_link_state_led
119 (
120 nvswitch_device *device
121 )
122 {
123 device->hal.nvswitch_cci_update_link_state_led(device);
124 }
125
126 NvlStatus
nvswitch_cci_set_xcvr_led_state(nvswitch_device * device,NvU32 client,NvU32 osfp,NvBool bSetLocate)127 nvswitch_cci_set_xcvr_led_state
128 (
129 nvswitch_device *device,
130 NvU32 client,
131 NvU32 osfp,
132 NvBool bSetLocate
133 )
134 {
135 return device->hal.nvswitch_cci_set_xcvr_led_state(device, client, osfp, bSetLocate);
136 }
137
138 NvlStatus
nvswitch_cci_get_xcvr_led_state(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 * pLedState)139 nvswitch_cci_get_xcvr_led_state
140 (
141 nvswitch_device *device,
142 NvU32 client,
143 NvU32 osfp,
144 NvU8 *pLedState
145 )
146 {
147 return device->hal.nvswitch_cci_get_xcvr_led_state(device, client, osfp, pLedState);
148 }
149
150 NvlStatus
nvswitch_cci_setup_onboard(nvswitch_device * device)151 nvswitch_cci_setup_onboard
152 (
153 nvswitch_device *device
154 )
155 {
156 return device->hal.nvswitch_cci_setup_onboard(device);
157 }
158
159 NvlStatus
nvswitch_cci_setup_module_path(nvswitch_device * device,NvU32 client,NvU32 osfp)160 nvswitch_cci_setup_module_path
161 (
162 nvswitch_device *device,
163 NvU32 client,
164 NvU32 osfp
165 )
166 {
167 return device->hal.nvswitch_cci_setup_module_path(device, client, osfp);
168 }
169
170 NvlStatus
nvswitch_cci_module_access_cmd(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU32 addr,NvU32 length,NvU8 * pValArray,NvBool bRead,NvBool bBlk)171 nvswitch_cci_module_access_cmd
172 (
173 nvswitch_device *device,
174 NvU32 client,
175 NvU32 osfp,
176 NvU32 addr,
177 NvU32 length,
178 NvU8 *pValArray,
179 NvBool bRead,
180 NvBool bBlk
181 )
182 {
183 return device->hal.nvswitch_cci_module_access_cmd(device, client, osfp, addr, length,
184 pValArray, bRead, bBlk);
185 }
186
187 NvlStatus
nvswitch_cci_apply_control_set_values(nvswitch_device * device,NvU32 client,NvU32 moduleMask)188 nvswitch_cci_apply_control_set_values
189 (
190 nvswitch_device *device,
191 NvU32 client,
192 NvU32 moduleMask
193 )
194 {
195 return device->hal.nvswitch_cci_apply_control_set_values(device, client, moduleMask);
196 }
197
198 NvlStatus
nvswitch_cci_cmis_cage_bezel_marking(nvswitch_device * device,NvU8 cageIndex,char * pBezelMarking)199 nvswitch_cci_cmis_cage_bezel_marking
200 (
201 nvswitch_device *device,
202 NvU8 cageIndex,
203 char *pBezelMarking
204 )
205 {
206 return device->hal.nvswitch_cci_cmis_cage_bezel_marking(device, cageIndex, pBezelMarking);
207 }
208
209 NvlStatus
nvswitch_cci_get_grading_values(nvswitch_device * device,NvU32 client,NvU32 linkId,NvU8 * laneMask,NVSWITCH_CCI_GRADING_VALUES * pGrading)210 nvswitch_cci_get_grading_values
211 (
212 nvswitch_device *device,
213 NvU32 client,
214 NvU32 linkId,
215 NvU8 *laneMask,
216 NVSWITCH_CCI_GRADING_VALUES *pGrading
217 )
218 {
219 return device->hal.nvswitch_cci_get_grading_values(device, client, linkId, laneMask, pGrading);
220 }
221
222 NvlStatus
nvswitch_cci_get_xcvr_mask(nvswitch_device * device,NvU32 * pMaskAll,NvU32 * pMaskPresent)223 nvswitch_cci_get_xcvr_mask
224 (
225 nvswitch_device *device,
226 NvU32 *pMaskAll,
227 NvU32 *pMaskPresent
228 )
229 {
230 return device->hal.nvswitch_cci_get_xcvr_mask(device, pMaskAll, pMaskPresent);
231 }
232
233 void
nvswitch_cci_set_xcvr_present(nvswitch_device * device,NvU32 maskPresent)234 nvswitch_cci_set_xcvr_present
235 (
236 nvswitch_device *device,
237 NvU32 maskPresent
238 )
239 {
240 device->hal.nvswitch_cci_set_xcvr_present(device, maskPresent);
241 }
242
243 void
nvswitch_cci_destroy(nvswitch_device * device)244 nvswitch_cci_destroy
245 (
246 nvswitch_device *device
247 )
248 {
249 device->hal.nvswitch_cci_destroy(device);
250 }
251
252 NvBool
cciSupported(nvswitch_device * device)253 cciSupported
254 (
255 nvswitch_device *device
256 )
257 {
258 PCCI pCci = device->pCci;
259 NvlStatus retval;
260
261 if (pCci == NULL)
262 {
263 return NV_FALSE;
264 }
265
266 if (pCci->bDiscovered)
267 {
268 return pCci->bSupported;
269 }
270
271 // Discover if CCI supported board
272 retval = nvswitch_cci_discovery(device);
273 if (retval == NVL_SUCCESS)
274 {
275 pCci->bSupported = NV_TRUE;
276 }
277 else
278 {
279 pCci->bSupported = NV_FALSE;
280 }
281
282 pCci->bDiscovered = NV_TRUE;
283
284 return pCci->bSupported;
285 }
286
287 CCI *
cciAllocNew(void)288 cciAllocNew(void)
289 {
290 CCI *pCci = nvswitch_os_malloc(sizeof(*pCci));
291 if (pCci != NULL)
292 {
293 nvswitch_os_memset(pCci, 0, sizeof(*pCci));
294 }
295
296 return pCci;
297 }
298
299 static void
_nvswitch_cci_poll_callback(nvswitch_device * device)300 _nvswitch_cci_poll_callback
301 (
302 nvswitch_device *device
303 )
304 {
305 PCCI pCci = device->pCci;
306 NvU32 i;
307
308 // call all functions at specified frequencies
309 for (i = 0; i < NVSWITCH_CCI_CALLBACK_NUM_MAX; i++)
310 {
311 if ((pCci->callbackList[i].functionPtr != NULL) &&
312 ((pCci->callbackCounter % pCci->callbackList[i].interval) == 0))
313 {
314 pCci->callbackList[i].functionPtr(device);
315 }
316 }
317 pCci->callbackCounter++;
318 }
319
320 NvlStatus
cciInit(nvswitch_device * device,CCI * pCci,NvU32 pci_device_id)321 cciInit
322 (
323 nvswitch_device *device,
324 CCI *pCci,
325 NvU32 pci_device_id
326 )
327 {
328 nvswitch_task_create(device, _nvswitch_cci_poll_callback,
329 NVSWITCH_INTERVAL_1SEC_IN_NS / NVSWITCH_CCI_POLLING_RATE_HZ,
330 0);
331 return NVL_SUCCESS;
332 }
333
334 // reverse of cciInit()
335 void
cciDestroy(nvswitch_device * device,CCI * pCci)336 cciDestroy
337 (
338 nvswitch_device *device,
339 CCI *pCci
340 )
341 {
342 nvswitch_cci_destroy(device);
343 }
344
345 static NvBool
_nvswitch_cci_module_present(nvswitch_device * device,NvU32 osfp)346 _nvswitch_cci_module_present
347 (
348 nvswitch_device *device,
349 NvU32 osfp
350 )
351 {
352 return !!(device->pCci->osfpMaskPresent & NVBIT(osfp));
353 }
354
355 static NvlStatus
_nvswitch_cci_get_module_id(nvswitch_device * device,NvU32 linkId,NvU32 * osfp)356 _nvswitch_cci_get_module_id
357 (
358 nvswitch_device *device,
359 NvU32 linkId,
360 NvU32 *osfp
361 )
362 {
363 PCCI pCci = device->pCci;
364 NvU32 i;
365
366 for (i = 0; i < pCci->osfp_map_size; i++)
367 {
368 if (pCci->osfp_map[i].linkId == linkId)
369 {
370 *osfp = pCci->osfp_map[i].moduleId;
371
372 if (!(device->pCci->cagesMask & NVBIT(*osfp)))
373 {
374 NVSWITCH_PRINT(device, ERROR,
375 "%s: osfp %d associated with link %d is not supported\n",
376 __FUNCTION__, linkId, *osfp);
377 return -NVL_NOT_FOUND;
378 }
379
380 return NVL_SUCCESS;
381 }
382 }
383
384 return -NVL_NOT_FOUND;
385 }
386
387 NvlStatus
cciWrite(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU32 addr,NvU32 length,NvU8 * pVal)388 cciWrite
389 (
390 nvswitch_device *device,
391 NvU32 client,
392 NvU32 osfp,
393 NvU32 addr,
394 NvU32 length,
395 NvU8 *pVal
396 )
397 {
398 NvlStatus status = NVL_SUCCESS;
399 NvBool bRead = NV_FALSE;
400 NvBool bBlk = NV_FALSE;
401
402 if (!pVal)
403 {
404 NVSWITCH_PRINT(device, ERROR,
405 "%s: Bad Args!\n",
406 __FUNCTION__);
407 return -NVL_BAD_ARGS;
408 }
409
410 if (!device->pCci->bInitialized)
411 {
412 NVSWITCH_PRINT(device, ERROR,
413 "%s: CCI is not supported\n",
414 __FUNCTION__);
415 return -NVL_ERR_NOT_SUPPORTED;
416 }
417
418 if (!cciModulePresent(device, osfp))
419 {
420 return -NVL_NOT_FOUND;
421 }
422
423 status = nvswitch_cci_setup_module_path(device, client, osfp);
424 if (status != NVL_SUCCESS)
425 {
426 return status;
427 }
428
429 status = nvswitch_cci_module_access_cmd(device, client, osfp, addr,
430 length, pVal, bRead, bBlk);
431 if (status != NVL_SUCCESS)
432 {
433 return status;
434 }
435
436 return NVL_SUCCESS;
437 }
438
439 NvlStatus
cciRead(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU32 addr,NvU32 length,NvU8 * pVal)440 cciRead
441 (
442 nvswitch_device *device,
443 NvU32 client,
444 NvU32 osfp,
445 NvU32 addr,
446 NvU32 length,
447 NvU8 *pVal
448 )
449 {
450 NvlStatus status = NVL_SUCCESS;
451 NvBool bRead = NV_TRUE;
452 NvBool bBlk = NV_FALSE;
453
454 if (!pVal)
455 {
456 NVSWITCH_PRINT(device, ERROR,
457 "%s: Bad Args!\n",
458 __FUNCTION__);
459 return -NVL_BAD_ARGS;
460 }
461
462 if (!device->pCci->bInitialized)
463 {
464 NVSWITCH_PRINT(device, ERROR,
465 "%s: CCI is not supported\n",
466 __FUNCTION__);
467 return -NVL_ERR_NOT_SUPPORTED;
468 }
469
470 if (!cciModulePresent(device, osfp))
471 {
472 return -NVL_NOT_FOUND;
473 }
474
475 status = nvswitch_cci_setup_module_path(device, client, osfp);
476 if (status != NVL_SUCCESS)
477 {
478 return status;
479 }
480
481 status = nvswitch_cci_module_access_cmd(device, client, osfp, addr,
482 length, pVal, bRead, bBlk);
483 if (status != NVL_SUCCESS)
484 {
485 return status;
486 }
487
488 return NVL_SUCCESS;
489 }
490
491 /*
492 * @brief Set bank an page in the CMIS memory table.
493 *
494 * CMIS4 states, "For a bank change, the host shall write the Bank Select
495 * and Page Select registers in the same TWI transaction".
496 *
497 * Write to Page 0h, byte 126 sets the bank and page.
498 */
499 NvlStatus
cciSetBankAndPage(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 bank,NvU8 page)500 cciSetBankAndPage
501 (
502 nvswitch_device *device,
503 NvU32 client,
504 NvU32 osfp,
505 NvU8 bank,
506 NvU8 page
507 )
508 {
509 NvU8 temp[2];
510
511 // Modules with flat memory will fail setting of page and bank
512 if (device->pCci->isFlatMemory[osfp])
513 {
514 if ((page > 0x0) || (bank > 0x0))
515 {
516 return -NVL_BAD_ARGS;
517 }
518 return NVL_SUCCESS;
519 }
520
521 temp[0] = bank;
522 temp[1] = page;
523
524 return cciWrite(device, client, osfp, 126, 2, temp);
525 }
526
527 /*
528 * @brief Gets the current bank and page in the CMIS memory table.
529 *
530 * Read from Page 0h, byte 126 to get the bank and page.
531 */
532 NvlStatus
cciGetBankAndPage(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 * pBank,NvU8 * pPage)533 cciGetBankAndPage
534 (
535 nvswitch_device *device,
536 NvU32 client,
537 NvU32 osfp,
538 NvU8 *pBank,
539 NvU8 *pPage
540 )
541 {
542 NvlStatus status;
543 NvU8 temp[2] = {0};
544
545 status = cciRead(device, client, osfp, 126, 2, temp);
546
547 if (pBank != NULL)
548 {
549 *pBank = temp[0];
550 }
551
552 if (pPage != NULL)
553 {
554 *pPage = temp[1];
555 }
556
557 return status;
558 }
559
560 #define NVSWITCH_CCI_MAX_CDB_LENGTH 128
561
562 /*
563 * @brief Send commands for Command Data Block(CDB) communication.
564 *
565 * CDB reads and writes are performed on memory map pages 9Fh-AFh.
566 *
567 * Page 9Fh is used to specify the CDB command and use
568 * local payload (LPL) of 120 bytes.
569 *
570 * Pages A0h-AFh contain up to 2048 bytes of extended payload (EPL).
571 *
572 * Payload may be a zero-length array if no payload to send.
573 *
574 * (ref CMIS rev4.0, sections 7.2, 8.13, 8.2.7, 8.4.11).
575 */
576 NvlStatus
cciSendCDBCommand(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU32 command,NvU32 length,NvU8 * payload,NvBool padding)577 cciSendCDBCommand
578 (
579 nvswitch_device *device,
580 NvU32 client,
581 NvU32 osfp,
582 NvU32 command,
583 NvU32 length,
584 NvU8 *payload,
585 NvBool padding
586 )
587 {
588 NvU8 cmd_msb = (command >> 8) & 0xff;
589 NvU8 cmd_lsb = command & 0xff;
590 NvU32 chkcode;
591 NvU32 i;
592 NvU8 temp[8];
593
594 if (length > NVSWITCH_CCI_MAX_CDB_LENGTH)
595 {
596 NVSWITCH_PRINT(device, ERROR,
597 "%s: Command length %d exceeded max length %d. "
598 "CDB yet to support extended payloads\n",
599 __FUNCTION__, length, NVSWITCH_CCI_MAX_CDB_LENGTH);
600 return -NVL_ERR_GENERIC;
601 }
602
603 //
604 // Compute checksum over payload, including header bytes(command, length,...)
605 //
606 // CdbChkCode is the ones complement of the summation of page 9Fh,
607 // bytes 128 to (135+LPL_Length) with bytes 133,134 and 135 equal to 0.
608 // (ref CMIS 4.0, sec 8.13)
609 //
610 chkcode = cmd_msb + cmd_lsb + length;
611
612 // now add payload bytes
613 if (length > 0)
614 {
615 for (i = 0; i < length; i++)
616 {
617 chkcode += payload[i];
618 }
619 }
620 chkcode = (~(chkcode & 0xff)) & 0xff;
621
622 // # nw: page 198 of cmis4 spec.
623 // # nw:
624
625 // Set page to 0x9F to setup CDB command
626 cciSetBankAndPage(device, client, osfp, 0, 0x9f);
627
628 //
629 // Send CDB message
630 //
631 // Fill page 9Fh bytes 128-135 in the order -
632 // [cmd_msb, cmd_lsb, epl_length msb, epl_length lsb, lpl_length,
633 // chkcode, resp_length = 0, resp_chkcode = 0]
634 //
635 // LPL starts from Bytes 136 upto 120 bytes.
636 // The command is triggered when byte 129 is written. So fill bytes 128, 129 at the end.
637 //
638
639 // #1. Write bytes 130-135. The "header portion", minus the first two bytes
640 // which is the command code.
641 temp[0] = 0; // epl_length msb
642 temp[1] = 0; // epl_length lsb
643 temp[2] = length; // lpl_length
644 temp[3] = chkcode; // cdb chkcode
645 temp[4] = 0; // response length
646 temp[5] = 0; // response chkcode
647 cciWrite(device, client, osfp, 130, 6, temp);
648
649 // #2. If payload's not empty, write the payload (bytes 136 to 255).
650 // If payload is empty, infer the command is payload-less and skip.
651 if ((length > 0) && padding)
652 {
653 for (i = length; i < CMIS_CDB_LPL_MAX_SIZE; i++)
654 {
655 payload[i] = 0;
656 }
657 cciWrite(device, client, osfp, 136, CMIS_CDB_LPL_MAX_SIZE, payload);
658 }
659 else if ((length > 0) && !padding)
660 {
661 cciWrite(device, client, osfp, 136, length, payload);
662 }
663
664 // # 3. Write the command code (bytes 128,129), which additionally
665 // kicks off processing of the command by the module.
666 temp[0] = cmd_msb;
667 temp[1] = cmd_lsb;
668 cciWrite(device, client, osfp, 128, 2, temp);
669
670 return NVL_SUCCESS;
671 }
672
673 /*!
674 * @brief Waits for CDB command completion and returns status.
675 *
676 * Page 00h byte 37 contains status bits.
677 * (see CMIS rev4.0, Table 9-3, CDB Command 0000h: QUERY-Status)
678 */
679 NvlStatus
cciGetCDBStatus(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 * pStatus)680 cciGetCDBStatus
681 (
682 nvswitch_device *device,
683 NvU32 client,
684 NvU32 osfp,
685 NvU8 *pStatus
686 )
687 {
688 NvBool status_busy;
689 NvBool status_fail;
690 NvU8 cdb_result;
691 NvU8 status;
692 NVSWITCH_TIMEOUT timeout;
693
694 status = 0;
695
696 nvswitch_timeout_create(10 * NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
697
698 do
699 {
700 cciRead(device, client, osfp, CMIS_CDB_BLOCK_STATUS_BYTE(0), 1, &status);
701 *pStatus = status;
702
703 // Quit when the STS_BUSY bit goes to 0
704 if (FLD_TEST_REF(CMIS_CDB_BLOCK_STATUS_BYTE_BUSY, _FALSE, status))
705 {
706 break;
707 }
708
709 if (nvswitch_timeout_check(&timeout))
710 {
711 NVSWITCH_PRINT(device, ERROR,
712 "%s: Timeout waiting for CDB command to complete! "
713 "STATUS = 0x%x\n",
714 __FUNCTION__, status);
715 break;
716 }
717
718 nvswitch_os_sleep(10);
719 } while (NV_TRUE);
720
721 status_busy = (status >> 7) & 0x1;
722 status_fail = (status >> 6) & 0x1;
723 cdb_result = status & 0x3f;
724
725 if (status_busy) // status is busy
726 {
727 if (cdb_result == 0x01)
728 {
729 NVSWITCH_PRINT(device, INFO,
730 "%s: CDB status = BUSY. Last Command Result: "
731 "'Command is captured but not processed'\n",
732 __FUNCTION__);
733 }
734 else if (cdb_result == 0x02)
735 {
736 NVSWITCH_PRINT(device, INFO,
737 "%s: CDB status = BUSY. Last Command Result: "
738 "'Command checking is in progress'\n",
739 __FUNCTION__);
740 }
741 else if (cdb_result == 0x03)
742 {
743 NVSWITCH_PRINT(device, ERROR,
744 "%s: CDB status = BUSY. Last Command Result: "
745 "'Command execution is in progress'\n",
746 __FUNCTION__);
747 }
748 else
749 {
750 NVSWITCH_PRINT(device, ERROR,
751 "%s: CDB status = BUSY. Last Command Result: "
752 "Unknown (0x%x)\n",
753 __FUNCTION__, cdb_result);
754 }
755
756 return -NVL_ERR_GENERIC;
757 }
758
759 if (status_fail) // status failed
760 {
761 if (cdb_result == 0x01)
762 {
763 NVSWITCH_PRINT(device, ERROR,
764 "%s: CDB status = FAIL. Last Command Result: "
765 "'CMD Code unknown'\n",
766 __FUNCTION__);
767 }
768 else if (cdb_result == 0x02)
769 {
770 NVSWITCH_PRINT(device, ERROR,
771 "%s: CDB status = FAIL. Last Command Result: "
772 "'Parameter range error or not supported'\n",
773 __FUNCTION__);
774 }
775 else if (cdb_result == 0x03)
776 {
777 NVSWITCH_PRINT(device, ERROR,
778 "%s: CDB status = FAIL. Last Command Result: "
779 "'Previous CMD was not ABORTED by CMD Abort'\n",
780 __FUNCTION__);
781 }
782 else if (cdb_result == 0x04)
783 {
784 NVSWITCH_PRINT(device, ERROR,
785 "%s: CDB status = FAIL. Last Command Result: "
786 "'Command checking time out'\n",
787 __FUNCTION__);
788 }
789 else if (cdb_result == 0x05)
790 {
791 NVSWITCH_PRINT(device, ERROR,
792 "%s: CDB status = FAIL. Last Command Result: "
793 "'CdbCheckCode Error'\n",
794 __FUNCTION__);
795 }
796 else if (cdb_result == 0x06)
797 {
798 NVSWITCH_PRINT(device, ERROR,
799 "%s: CDB status = FAIL. Last Command Result: "
800 "'Password Error'\n",
801 __FUNCTION__);
802 }
803 else
804 {
805 NVSWITCH_PRINT(device, ERROR,
806 "%s: CDB status = FAIL. Last Command Result: "
807 "Unknown (0x%x)\n",
808 __FUNCTION__, cdb_result);
809 }
810
811 return -NVL_ERR_GENERIC;
812 }
813
814 return NVL_SUCCESS;
815 }
816
817 /*!
818 * @brief Waits for CDB command completion.
819 *
820 * Page 00h byte 37 contains status bits. BIT 7 is the busy bit.
821 * (see CMIS rev4.0, Table 9-3, CDB Command 0000h: QUERY-Status)
822 */
823 NvlStatus
cciWaitForCDBComplete(nvswitch_device * device,NvU32 client,NvU32 osfp)824 cciWaitForCDBComplete
825 (
826 nvswitch_device *device,
827 NvU32 client,
828 NvU32 osfp
829 )
830 {
831 NVSWITCH_TIMEOUT timeout;
832 NvU8 status;
833
834 status = 0;
835
836 nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
837
838 do
839 {
840 cciRead(device, client, osfp, CMIS_CDB_BLOCK_STATUS_BYTE(0), 1, &status);
841
842 // Return when the STS_BUSY bit goes to 0
843 if (FLD_TEST_REF(CMIS_CDB_BLOCK_STATUS_BYTE_BUSY, _FALSE, status))
844 {
845 return NVL_SUCCESS;
846 }
847
848 if (nvswitch_timeout_check(&timeout))
849 {
850 NVSWITCH_PRINT(device, ERROR,
851 "%s: Timeout waiting for CDB command to complete! STATUS = 0x%x\n",
852 __FUNCTION__, status);
853 return -NVL_ERR_GENERIC;
854 }
855
856 nvswitch_os_sleep(10);
857 } while (NV_TRUE);
858 }
859
860 /*!
861 * @brief Get the CDB response data.
862 *
863 * This function must be sent after CDB status is success.
864 *
865 * Page 9Fh, bytes 134-255 contains response data
866 * Byte 134 : Response LPL Length of the data returned by CDB command code.
867 * Byte 135 : Response LPL ChkCode
868 * Bytes 136-255 : Local payload of the module response.
869 */
870 NvlStatus
cciGetCDBResponse(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 * response,NvU32 * resLength)871 cciGetCDBResponse
872 (
873 nvswitch_device *device,
874 NvU32 client,
875 NvU32 osfp,
876 NvU8 *response,
877 NvU32 *resLength
878 )
879 {
880 NvU8 header[8] = {0};
881 NvU32 rlpllen; // Response local payload length
882 NvU8 rlplchkcode; // Response local payload check code
883 NvU8 chksum = 0;
884 NvU32 i;
885 NvBool bSkipChecksum = NV_FALSE;
886
887 cciSetBankAndPage(device, client, osfp, 0, 0x9f);
888
889 // get header
890 cciRead(device, client, osfp, 128, 8, header);
891
892 // get reported response length
893 rlpllen = header[6];
894 rlplchkcode = header[7];
895
896 // TODO : Remove this once FW support improves
897 if (rlpllen == 0)
898 {
899 // bug with earlier Stallion FW, presume hit it an read maximum-sized lpl.
900 // Assume the maximum length of 120 and skip checksum because it will also
901 // be zero
902 rlpllen = CMIS_CDB_LPL_MAX_SIZE;
903 bSkipChecksum = NV_TRUE;
904 }
905
906 if (rlpllen > CMIS_CDB_LPL_MAX_SIZE)
907 {
908 NVSWITCH_PRINT(device, ERROR,
909 "%s: Error: Invalid CDB response length: %d\n",
910 __FUNCTION__, rlpllen);
911 return -NVL_ERR_GENERIC;
912 }
913
914 if (rlpllen != 0)
915 {
916 // get response
917 cciRead(device, client, osfp, 136, rlpllen, response);
918
919 if (!bSkipChecksum)
920 {
921 // compute checksum of response
922 for (i = 0; i < rlpllen; i++)
923 {
924 chksum += response[i];
925 }
926
927 // and compare against rlplchkcode (byte 7 of page 9Fh)
928 if ((~chksum & 0xff) != rlplchkcode)
929 {
930 NVSWITCH_PRINT(device, ERROR,
931 "%s: Error: RLPLChkCode incorrect for returned data\n",
932 __FUNCTION__);
933 return -NVL_ERR_GENERIC;
934 }
935 }
936 }
937
938 if (resLength != NULL)
939 {
940 *resLength = rlpllen;
941 }
942
943 return NVL_SUCCESS;
944 }
945
946 /*!
947 * @brief Get the CDB command and get response.
948 */
949 NvlStatus
cciSendCDBCommandAndGetResponse(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU32 command,NvU32 payLength,NvU8 * payload,NvU32 * resLength,NvU8 * response,NvBool padding)950 cciSendCDBCommandAndGetResponse
951 (
952 nvswitch_device *device,
953 NvU32 client,
954 NvU32 osfp,
955 NvU32 command,
956 NvU32 payLength,
957 NvU8 *payload,
958 NvU32 *resLength,
959 NvU8 *response,
960 NvBool padding
961 )
962 {
963 NvlStatus retval;
964 NvU8 status = 0;
965
966 if (!cciModulePresent(device, osfp))
967 {
968 NVSWITCH_PRINT(device, INFO,
969 "%s: osfp %d is missing\n",
970 __FUNCTION__, osfp);
971 return -NVL_NOT_FOUND;
972 }
973
974 // Wait for CDB status to be free
975 retval = cciWaitForCDBComplete(device, client, osfp);
976 if (retval != NVL_SUCCESS)
977 {
978 NVSWITCH_PRINT(device, INFO,
979 "%s: CDB is busy!!\n",
980 __FUNCTION__);
981 return -NVL_ERR_GENERIC;
982 }
983
984 retval = cciSendCDBCommand(device, client, osfp, command, payLength, payload, padding);
985 if (retval != NVL_SUCCESS)
986 {
987 NVSWITCH_PRINT(device, INFO,
988 "%s: Failed to send CDB Command: 0x%x\n",
989 __FUNCTION__, command);
990 return -NVL_ERR_GENERIC;
991 }
992
993 retval = cciGetCDBStatus(device, client, osfp, &status);
994 if (retval != NVL_SUCCESS)
995 {
996 NVSWITCH_PRINT(device, ERROR,
997 "%s: CDB command failed! result = 0x%x\n",
998 __FUNCTION__, status);
999 return -NVL_ERR_GENERIC;
1000 }
1001
1002 retval = cciGetCDBResponse(device, client, osfp, response, resLength);
1003 if (retval != NVL_SUCCESS)
1004 {
1005 NVSWITCH_PRINT(device, ERROR,
1006 "%s: Failed to get CDB command response\n",
1007 __FUNCTION__);
1008 return -NVL_ERR_GENERIC;
1009 }
1010
1011 return NVL_SUCCESS;
1012 }
1013
1014 NvlStatus
cciRegisterCallback(nvswitch_device * device,NvU32 callbackId,void (* functionPtr)(nvswitch_device *),NvU32 rateHz)1015 cciRegisterCallback
1016 (
1017 nvswitch_device *device,
1018 NvU32 callbackId,
1019 void (*functionPtr)(nvswitch_device*),
1020 NvU32 rateHz
1021 )
1022 {
1023 PCCI pCci = device->pCci;
1024
1025 if ((callbackId >= NVSWITCH_CCI_CALLBACK_NUM_MAX) ||
1026 (functionPtr == NULL))
1027 {
1028 return -NVL_BAD_ARGS;
1029 }
1030
1031 if ((rateHz == 0) || ((NVSWITCH_CCI_POLLING_RATE_HZ % rateHz) != 0))
1032 {
1033 NVSWITCH_PRINT(device, ERROR,
1034 "%s: Input rate must divide main polling rate: %d\n",
1035 __FUNCTION__, NVSWITCH_CCI_POLLING_RATE_HZ);
1036 return -NVL_BAD_ARGS;
1037 }
1038
1039 if (pCci->callbackList[callbackId].functionPtr != NULL)
1040 {
1041 NVSWITCH_PRINT(device, SETUP,
1042 "%s: CCI callback previously set.\n",
1043 __FUNCTION__);
1044 }
1045
1046 pCci->callbackList[callbackId].interval = NVSWITCH_CCI_POLLING_RATE_HZ/rateHz;
1047 pCci->callbackList[callbackId].functionPtr = functionPtr;
1048
1049 return NVL_SUCCESS;
1050 }
1051
1052 // CCI CONTROL CALLS
1053 NvlStatus
nvswitch_ctrl_get_cci_fw_revisions(nvswitch_device * device,NVSWITCH_CCI_GET_FW_REVISION_PARAMS * pParams)1054 nvswitch_ctrl_get_cci_fw_revisions
1055 (
1056 nvswitch_device *device,
1057 NVSWITCH_CCI_GET_FW_REVISION_PARAMS *pParams
1058 )
1059 {
1060 return cciGetFWRevisions(device, 0, pParams->linkId,
1061 pParams->revisions);
1062 }
1063
1064 NvlStatus
nvswitch_ctrl_get_grading_values(nvswitch_device * device,NVSWITCH_CCI_GET_GRADING_VALUES_PARAMS * pParams)1065 nvswitch_ctrl_get_grading_values
1066 (
1067 nvswitch_device *device,
1068 NVSWITCH_CCI_GET_GRADING_VALUES_PARAMS *pParams
1069 )
1070 {
1071 return cciGetGradingValues(device, 0, pParams->linkId,
1072 &pParams->laneMask, &pParams->grading);
1073 }
1074
1075 NvlStatus
nvswitch_ctrl_get_ports_cpld_info(nvswitch_device * device,NVSWITCH_CCI_GET_PORTS_CPLD_INFO_PARAMS * pParams)1076 nvswitch_ctrl_get_ports_cpld_info
1077 (
1078 nvswitch_device *device,
1079 NVSWITCH_CCI_GET_PORTS_CPLD_INFO_PARAMS *pParams
1080 )
1081 {
1082 NvlStatus retval = NVL_SUCCESS;
1083 NvU8 val;
1084
1085 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1086 {
1087 NVSWITCH_PRINT(device, ERROR,
1088 "%s: CCI not supported\n",
1089 __FUNCTION__);
1090 return -NVL_ERR_NOT_SUPPORTED;
1091 }
1092
1093 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_VERSION_MAJOR, &val);
1094 if (retval != NVL_SUCCESS)
1095 {
1096 return -NVL_IO_ERROR;
1097 }
1098 pParams->versionMajor = val;
1099
1100 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_VERSION_MINOR, &val);
1101 if (retval != NVL_SUCCESS)
1102 {
1103 return -NVL_IO_ERROR;
1104 }
1105 pParams->versionMinor = val;
1106
1107 return NVL_SUCCESS;
1108 }
1109
1110 NvlStatus
nvswitch_ctrl_set_locate_led(nvswitch_device * device,NVSWITCH_CCI_SET_LOCATE_LED_PARAMS * pParams)1111 nvswitch_ctrl_set_locate_led
1112 (
1113 nvswitch_device *device,
1114 NVSWITCH_CCI_SET_LOCATE_LED_PARAMS *pParams
1115 )
1116 {
1117 NvlStatus retval = NVL_SUCCESS;
1118 NvU32 cagesMask;
1119 NvU8 ledState;
1120
1121 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1122 {
1123 NVSWITCH_PRINT(device, ERROR,
1124 "%s: CCI not supported\n",
1125 __FUNCTION__);
1126 return -NVL_ERR_NOT_SUPPORTED;
1127 }
1128
1129 retval = cciGetXcvrMask(device, &cagesMask, NULL);
1130 if (retval != NVL_SUCCESS)
1131 {
1132 return retval;
1133 }
1134
1135 if (!(cagesMask & NVBIT(pParams->cageIndex)))
1136 {
1137 NVSWITCH_PRINT(device, ERROR,
1138 "%s: Module cage does not exist\n",
1139 __FUNCTION__);
1140 return -NVL_BAD_ARGS;
1141 }
1142
1143 if (pParams->portNum > 1)
1144 {
1145 NVSWITCH_PRINT(device, ERROR,
1146 "%s: Invalid port number\n",
1147 __FUNCTION__);
1148 return -NVL_BAD_ARGS;
1149 }
1150
1151 ledState = device->pCci->xcvrCurrentLedState[pParams->cageIndex];
1152
1153 if (pParams->portNum == 0)
1154 {
1155 ledState = FLD_SET_REF_NUM(CCI_LED_STATE_LED_A,
1156 pParams->bSetLocateOn ? CCI_LED_STATE_LOCATE :
1157 CCI_LED_STATE_OFF,
1158 ledState);
1159 }
1160 else
1161 {
1162 ledState = FLD_SET_REF_NUM(CCI_LED_STATE_LED_B,
1163 pParams->bSetLocateOn ? CCI_LED_STATE_LOCATE :
1164 CCI_LED_STATE_OFF,
1165 ledState);
1166 }
1167
1168 cciSetNextXcvrLedState(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
1169 pParams->cageIndex, ledState);
1170 cciSetXcvrLedState(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
1171 pParams->cageIndex, NV_FALSE);
1172
1173 return NVL_SUCCESS;
1174 }
1175
1176 NvlStatus
nvswitch_ctrl_cci_request_ali(nvswitch_device * device,NVSWITCH_REQUEST_ALI_PARAMS * pParams)1177 nvswitch_ctrl_cci_request_ali
1178 (
1179 nvswitch_device *device,
1180 NVSWITCH_REQUEST_ALI_PARAMS *pParams
1181 )
1182 {
1183 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1184 {
1185 NVSWITCH_PRINT(device, ERROR,
1186 "%s: CCI not supported\n",
1187 __FUNCTION__);
1188 return -NVL_ERR_NOT_SUPPORTED;
1189 }
1190
1191 return cciRequestALI(device, pParams->linkMaskTrain);
1192 }
1193
1194 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
1195
1196 /*
1197 * @Brief : Reset CCI on this device.
1198 *
1199 * This is temporary and eventually moved to bios.
1200 * Tracking this in bug 200668898.
1201 *
1202 */
1203 static NvlStatus
_nvswitch_reset_cci(nvswitch_device * device)1204 _nvswitch_reset_cci
1205 (
1206 nvswitch_device *device
1207 )
1208 {
1209 return nvswitch_cci_reset(device);
1210 }
1211
1212 /*
1213 * @Brief : Execute CCI pre-reset sequence for secure reset.
1214 */
1215 static NvlStatus
_nvswitch_cci_prepare_for_reset(nvswitch_device * device)1216 _nvswitch_cci_prepare_for_reset
1217 (
1218 nvswitch_device *device
1219 )
1220 {
1221 nvswitch_cci_setup_gpio_pins(device);
1222
1223 return NVL_SUCCESS;
1224 }
1225
1226 /*
1227 * Check for CMIS boards by pinging on OSFP devices
1228 */
1229 static NvlStatus
_nvswitch_identify_cci_devices(nvswitch_device * device)1230 _nvswitch_identify_cci_devices
1231 (
1232 nvswitch_device *device
1233 )
1234 {
1235 PCCI pCci = device->pCci;
1236 NvU32 maskPresent;
1237
1238 maskPresent = 0;
1239
1240 nvswitch_cci_get_xcvrs_present(device, &maskPresent);
1241 pCci->osfpMaskPresent = maskPresent;
1242 pCci->osfpMaskAll = pCci->cagesMask;
1243
1244 NVSWITCH_PRINT(device, SETUP,
1245 "%s: Identified modules mask: 0x%x\n",
1246 __FUNCTION__, pCci->osfpMaskPresent);
1247
1248 pCci->bInitialized = NV_TRUE;
1249
1250 return NVL_SUCCESS;
1251 }
1252
1253 NvBool
cciIsLinkManaged(nvswitch_device * device,NvU32 linkNumber)1254 cciIsLinkManaged
1255 (
1256 nvswitch_device *device,
1257 NvU32 linkNumber
1258 )
1259 {
1260 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1261 {
1262 return NV_FALSE;
1263 }
1264
1265 return !!(device->pCci->linkMask & NVBIT64(linkNumber));
1266 }
1267
1268 NvlStatus
cciGetLinkMode(nvswitch_device * device,NvU32 linkNumber,NvU64 * mode)1269 cciGetLinkMode
1270 (
1271 nvswitch_device *device,
1272 NvU32 linkNumber,
1273 NvU64 *mode
1274 )
1275 {
1276 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1277 {
1278 NVSWITCH_PRINT(device, ERROR,
1279 "%s: CCI not supported\n",
1280 __FUNCTION__);
1281 return -NVL_ERR_NOT_SUPPORTED;
1282 }
1283
1284 if (mode == NULL)
1285 {
1286 return -NVL_BAD_ARGS;
1287 }
1288
1289 if (!cciIsLinkManaged(device, linkNumber))
1290 {
1291 return -NVL_BAD_ARGS;
1292 }
1293
1294 if (cciLinkTrainIdle(device, linkNumber))
1295 {
1296 *mode = NVLINK_LINKSTATE_OFF;
1297 }
1298 else
1299 {
1300 *mode = NVLINK_LINKSTATE_TRAINING_CCI;
1301 }
1302
1303 return NVL_SUCCESS;
1304 }
1305
1306 /*
1307 * @Brief : Bootstrap CCI on the specified device
1308 *
1309 * @param[in] device Bootstrap CCI on this device
1310 */
1311 NvlStatus
cciLoad(nvswitch_device * device)1312 cciLoad
1313 (
1314 nvswitch_device *device
1315 )
1316 {
1317 NvlStatus status;
1318
1319 if (IS_FMODEL(device) || IS_RTLSIM(device))
1320 {
1321 NVSWITCH_PRINT(device, SETUP,
1322 "%s: Skipping CCI init on preSilicon.\n",
1323 __FUNCTION__);
1324 return -NVL_ERR_NOT_SUPPORTED;
1325 }
1326
1327 if (device->pCci == NULL)
1328 {
1329 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_CCI_INIT,
1330 "Failed to init CCI(0)\n");
1331 return -NVL_BAD_ARGS;
1332 }
1333
1334 // Prepare CCI for reset.
1335 status = _nvswitch_cci_prepare_for_reset(device);
1336 if (status != NVL_SUCCESS)
1337 {
1338 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_CCI_RESET,
1339 "Failed to reset CCI(0)\n");
1340 return status;
1341 }
1342
1343 // Reset CCI
1344 status = _nvswitch_reset_cci(device);
1345 if (status != NVL_SUCCESS)
1346 {
1347 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_CCI_RESET,
1348 "Failed to reset CCI(1)\n");
1349 return status;
1350 }
1351
1352 // Identify CCI devices
1353 status = _nvswitch_identify_cci_devices(device);
1354 if (status != NVL_SUCCESS)
1355 {
1356 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_CCI_INIT,
1357 "Failed to init CCI(1)\n");
1358 return status;
1359 }
1360
1361 // Complete CCI setup
1362 status = nvswitch_cci_setup_onboard(device);
1363 if (status != NVL_SUCCESS)
1364 {
1365 NVSWITCH_PRINT_SXID(device, NVSWITCH_ERR_HW_CCI_INIT,
1366 "Failed to init CCI(2)\n");
1367 return status;
1368 }
1369
1370 NVSWITCH_PRINT(device, SETUP,
1371 "%s: CCI load successful.\n",
1372 __FUNCTION__);
1373
1374 return status;
1375 }
1376
1377 /*
1378 * @brief Get FW revisions of the osfp device by link Id
1379 *
1380 * Module FW revision is obtained from CDB command 0x100.
1381 * (ref CMIS rev4.0, Table 9-16 CDB Command 0100h: Get firmware Info)
1382 */
1383 NvlStatus
cciGetFWRevisions(nvswitch_device * device,NvU32 client,NvU32 linkId,NVSWITCH_CCI_GET_FW_REVISIONS * pRevisions)1384 cciGetFWRevisions
1385 (
1386 nvswitch_device *device,
1387 NvU32 client,
1388 NvU32 linkId,
1389 NVSWITCH_CCI_GET_FW_REVISIONS *pRevisions
1390 )
1391 {
1392 NvU32 osfp;
1393
1394 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1395 {
1396 NVSWITCH_PRINT(device, ERROR,
1397 "%s: CCI not supported\n",
1398 __FUNCTION__);
1399 return -NVL_ERR_NOT_SUPPORTED;
1400 }
1401
1402 if (cciGetModuleId(device, linkId, &osfp) != NVL_SUCCESS)
1403 {
1404 NVSWITCH_PRINT(device, ERROR,
1405 "%s: Failed to get moduleid associated with link %d\n",
1406 __FUNCTION__, linkId);
1407 return -NVL_ERR_NOT_SUPPORTED;
1408 }
1409
1410 return cciGetXcvrFWRevisions(device, client, osfp, pRevisions);
1411 }
1412
1413 static NvlStatus
_cciGetXcvrFWRevisionsFlatMem(nvswitch_device * device,NvU32 client,NvU32 osfp,NVSWITCH_CCI_GET_FW_REVISIONS * pRevisions)1414 _cciGetXcvrFWRevisionsFlatMem
1415 (
1416 nvswitch_device *device,
1417 NvU32 client,
1418 NvU32 osfp,
1419 NVSWITCH_CCI_GET_FW_REVISIONS *pRevisions
1420 )
1421 {
1422 NvlStatus retVal;
1423 NvU8 versionByte;
1424
1425 retVal = cciCmisRead(device, osfp, 0, 0,
1426 CMIS_ACTIVE_FW_MAJOR_REVISION, 1, &versionByte);
1427 if (retVal != NVL_SUCCESS)
1428 {
1429 return retVal;
1430 }
1431
1432 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].major = versionByte;
1433
1434 retVal = cciCmisRead(device, osfp, 0, 0,
1435 CMIS_ACTIVE_FW_MINOR_REVISION, 1, &versionByte);
1436 if (retVal != NVL_SUCCESS)
1437 {
1438 return retVal;
1439 }
1440
1441 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].minor = versionByte;
1442
1443 if (pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].major ||
1444 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].minor)
1445 {
1446 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags =
1447 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _ACTIVE, _YES,
1448 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags);
1449 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags =
1450 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _PRESENT, _YES,
1451 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags);
1452 }
1453
1454 // Entries for images A and B will be left as 0
1455
1456 return NVL_SUCCESS;
1457 }
1458
1459 /*
1460 * @brief Get FW revisions of the osfp device by OSFP xceiver index
1461 *
1462 * Module FW revision is obtained from CDB command 0x100.
1463 * (ref CMIS rev4.0, Table 9-16 CDB Command 0100h: Get firmware Info)
1464 */
1465 NvlStatus
cciGetXcvrFWRevisions(nvswitch_device * device,NvU32 client,NvU32 osfp,NVSWITCH_CCI_GET_FW_REVISIONS * pRevisions)1466 cciGetXcvrFWRevisions
1467 (
1468 nvswitch_device *device,
1469 NvU32 client,
1470 NvU32 osfp,
1471 NVSWITCH_CCI_GET_FW_REVISIONS *pRevisions
1472 )
1473 {
1474 NvU8 response[CMIS_CDB_LPL_MAX_SIZE];
1475 NvU32 resLength;
1476 NvlStatus retVal;
1477 NvU8 status;
1478
1479 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1480 {
1481 NVSWITCH_PRINT(device, ERROR,
1482 "%s: CCI not supported\n",
1483 __FUNCTION__);
1484 return -NVL_ERR_NOT_SUPPORTED;
1485 }
1486
1487 if (osfp >= (sizeof(device->pCci->osfpMaskAll) * 8))
1488 {
1489 return -NVL_BAD_ARGS;
1490 }
1491
1492 if (!(device->pCci->osfpMaskPresent & NVBIT(osfp)))
1493 {
1494 NVSWITCH_PRINT(device, ERROR,
1495 "%s: osfp %d is missing\n",
1496 __FUNCTION__, osfp);
1497 return -NVL_ERR_NOT_SUPPORTED;
1498 }
1499
1500 nvswitch_os_memset(pRevisions, 0, sizeof(NVSWITCH_CCI_GET_FW_REVISIONS));
1501
1502 if (device->pCci->isFlatMemory[osfp])
1503 {
1504 retVal = _cciGetXcvrFWRevisionsFlatMem(device, client, osfp, pRevisions);
1505 if (retVal != NVL_SUCCESS)
1506 {
1507 NVSWITCH_PRINT(device, ERROR,
1508 "%s: Failed to get FW revisions\n",
1509 __FUNCTION__);
1510 return -NVL_ERR_GENERIC;
1511 }
1512
1513 return NVL_SUCCESS;
1514 }
1515
1516 retVal = cciSendCDBCommandAndGetResponse(device, client, osfp,
1517 0x100, 0, NULL, &resLength, response, NV_FALSE);
1518 if (retVal != NVL_SUCCESS)
1519 {
1520 NVSWITCH_PRINT(device, ERROR,
1521 "%s: Failed to get FW revisions\n",
1522 __FUNCTION__);
1523 return -NVL_ERR_GENERIC;
1524 }
1525
1526 // Byte 0(or 136) contains FW status
1527 status = response[0];
1528
1529 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags = 0;
1530 if (status == 0)
1531 {
1532 NVSWITCH_PRINT(device, INFO,
1533 "%s: Factory Boot Image is Running\n",
1534 __FUNCTION__);
1535
1536 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags =
1537 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _ACTIVE, _YES,
1538 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags);
1539 }
1540
1541 if (response[1] & NVBIT(2))
1542 {
1543 //
1544 // For Factory Image,
1545 // Byte 74(or 210) contains major revision
1546 // Byte 75(or 211) contains minor revision
1547 // Byte 76, 77(or 212, 213) contains build number
1548 //
1549 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags =
1550 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _PRESENT, _YES,
1551 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].flags);
1552 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].major = response[74];
1553 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].minor = response[75];
1554 pRevisions[NVSWITCH_CCI_FW_IMAGE_FACTORY].build = (response[76] << 4 | response[77]);
1555 }
1556
1557 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags = 0;
1558 if (status & NVBIT(0))
1559 {
1560 NVSWITCH_PRINT(device, INFO,
1561 "%s: Image A is Running\n",
1562 __FUNCTION__);
1563
1564 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags =
1565 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _ACTIVE, _YES,
1566 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags);
1567 }
1568 if (status & NVBIT(1))
1569 {
1570 NVSWITCH_PRINT(device, INFO,
1571 "%s: Image A is committed, module boots from Image A\n",
1572 __FUNCTION__);
1573 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags =
1574 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _COMMITED, _YES,
1575 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags);
1576 }
1577 if (status & NVBIT(2))
1578 {
1579 NVSWITCH_PRINT(device, INFO,
1580 "%s: Image A is erased/empty\n",
1581 __FUNCTION__);
1582 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags =
1583 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _EMPTY, _YES,
1584 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags);
1585 }
1586
1587 if (response[1] & NVBIT(0))
1588 {
1589 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags =
1590 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _PRESENT, _YES,
1591 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].flags);
1592 //
1593 // For Image A,
1594 // Byte 2(or 138) contains major revision
1595 // Byte 3(or 139) contains minor revision
1596 // Byte 4, 5(or 140, 141) contains build number
1597 //
1598 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].major = response[2];
1599 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].minor = response[3];
1600 pRevisions[NVSWITCH_CCI_FW_IMAGE_A].build = (response[4] << 4 | response[5]);
1601 }
1602
1603 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags = 0;
1604 if (status & NVBIT(4))
1605 {
1606 NVSWITCH_PRINT(device, INFO,
1607 "%s: Image B is Running\n",
1608 __FUNCTION__);
1609
1610 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags =
1611 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _ACTIVE, _YES,
1612 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags);
1613 }
1614 if (status & NVBIT(5))
1615 {
1616 NVSWITCH_PRINT(device, INFO,
1617 "%s: Image B is committed, module boots from Image B\n",
1618 __FUNCTION__);
1619 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags =
1620 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _COMMITED, _YES,
1621 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags);
1622 }
1623 if (status & NVBIT(6))
1624 {
1625 NVSWITCH_PRINT(device, INFO,
1626 "%s: Image B is erased/empty\n",
1627 __FUNCTION__);
1628 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags =
1629 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _EMPTY, _YES,
1630 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags);
1631 }
1632
1633 if (response[1] & NVBIT(1))
1634 {
1635 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags =
1636 FLD_SET_DRF(SWITCH, _CCI_FW_FLAGS, _PRESENT, _YES,
1637 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].flags);
1638 //
1639 // For Image B,
1640 // Byte 38(or 174) contains major revision
1641 // Byte 39(or 175) contains minor revision
1642 // Byte 40, 41(or 176, 177) contains build number
1643 //
1644 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].major = response[38];
1645 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].minor = response[39];
1646 pRevisions[NVSWITCH_CCI_FW_IMAGE_B].build = (response[40] << 8 | response[41]);
1647 }
1648
1649 return NVL_SUCCESS;
1650 }
1651
1652 /*
1653 * @brief Get xceiver LED state by OSFP xceiver index.
1654 *
1655 */
1656 NvlStatus
cciGetXcvrLedState(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 * pLedState)1657 cciGetXcvrLedState
1658 (
1659 nvswitch_device *device,
1660 NvU32 client,
1661 NvU32 osfp,
1662 NvU8 *pLedState
1663 )
1664 {
1665 NvlStatus status;
1666
1667 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1668 {
1669 NVSWITCH_PRINT(device, ERROR,
1670 "%s: CCI not supported\n",
1671 __FUNCTION__);
1672 return -NVL_ERR_NOT_SUPPORTED;
1673 }
1674
1675 status = nvswitch_cci_get_xcvr_led_state(device, client, osfp, pLedState);
1676 if (status != NVL_SUCCESS)
1677 {
1678 return status;
1679 }
1680
1681 return status;
1682 }
1683
1684 /*
1685 * @brief Set the next LED state for the given OSFP.
1686 * The HW will reflect this state on the next iteration of link
1687 * state update callback.
1688 */
1689 NvlStatus
cciSetNextXcvrLedState(nvswitch_device * device,NvU32 client,NvU32 osfp,NvU8 nextLedState)1690 cciSetNextXcvrLedState
1691 (
1692 nvswitch_device *device,
1693 NvU32 client,
1694 NvU32 osfp,
1695 NvU8 nextLedState
1696 )
1697 {
1698 NvlStatus status;
1699 NvU32 cagesMask;
1700
1701 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1702 {
1703 NVSWITCH_PRINT(device, ERROR,
1704 "%s: CCI not supported\n",
1705 __FUNCTION__);
1706 return -NVL_ERR_NOT_SUPPORTED;
1707 }
1708
1709 status = cciGetXcvrMask(device, &cagesMask, NULL);
1710 if (status != NVL_SUCCESS)
1711 {
1712 return status;
1713 }
1714
1715 if ((cagesMask & NVBIT32(osfp)) == 0)
1716 {
1717 NVSWITCH_PRINT(device, ERROR,
1718 "%s: Module cage not found\n",
1719 __FUNCTION__);
1720 return -NVL_BAD_ARGS;
1721 }
1722
1723 device->pCci->xcvrNextLedState[osfp] = nextLedState;
1724
1725 return status;
1726 }
1727
1728 /*
1729 * @brief Set HW xceiver LED state (Locate On/Off) by OSFP xceiver index.
1730 * If Locate is off then set LED state based on link state.
1731 *
1732 */
1733 NvlStatus
cciSetXcvrLedState(nvswitch_device * device,NvU32 client,NvU32 osfp,NvBool bSetLocate)1734 cciSetXcvrLedState
1735 (
1736 nvswitch_device *device,
1737 NvU32 client,
1738 NvU32 osfp,
1739 NvBool bSetLocate
1740 )
1741 {
1742 NvlStatus status;
1743 NvU32 cagesMask;
1744
1745 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1746 {
1747 NVSWITCH_PRINT(device, ERROR,
1748 "%s: CCI not supported\n",
1749 __FUNCTION__);
1750 return -NVL_ERR_NOT_SUPPORTED;
1751 }
1752
1753 status = cciGetXcvrMask(device, &cagesMask, NULL);
1754 if (status != NVL_SUCCESS)
1755 {
1756 return status;
1757 }
1758
1759 if ((cagesMask & NVBIT32(osfp)) == 0)
1760 {
1761 return -NVL_BAD_ARGS;
1762 }
1763
1764 status = nvswitch_cci_set_xcvr_led_state(device, client, osfp, bSetLocate);
1765 if (status != NVL_SUCCESS)
1766 {
1767 return status;
1768 }
1769
1770 return status;
1771 }
1772
1773 /*
1774 * @brief Determine which OSFP transceivers are connected
1775 *
1776 */
1777 void
cciDetectXcvrsPresent(nvswitch_device * device)1778 cciDetectXcvrsPresent
1779 (
1780 nvswitch_device *device
1781 )
1782 {
1783 NvU32 maskPresent;
1784
1785 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1786 {
1787 NVSWITCH_PRINT(device, ERROR,
1788 "%s: CCI not supported\n",
1789 __FUNCTION__);
1790 return;
1791 }
1792
1793 maskPresent = 0;
1794
1795 nvswitch_cci_get_xcvrs_present(device, &maskPresent);
1796 nvswitch_cci_set_xcvr_present(device, maskPresent);
1797 }
1798
1799 /*
1800 * @brief Get the bitset mask of connected OSFP transceivers
1801 *
1802 */
1803 NvlStatus
cciGetXcvrMask(nvswitch_device * device,NvU32 * pMaskAll,NvU32 * pMaskPresent)1804 cciGetXcvrMask
1805 (
1806 nvswitch_device *device,
1807 NvU32 *pMaskAll,
1808 NvU32 *pMaskPresent
1809 )
1810 {
1811 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1812 {
1813 NVSWITCH_PRINT(device, ERROR,
1814 "%s: CCI not supported\n",
1815 __FUNCTION__);
1816 return -NVL_ERR_NOT_SUPPORTED;
1817 }
1818
1819 return nvswitch_cci_get_xcvr_mask(device, pMaskAll, pMaskPresent);
1820 }
1821
1822 NvlStatus
cciConfigureNvlinkModeModule(nvswitch_device * device,NvU32 client,NvU8 moduleId,NvU64 linkMask,NvBool freeze_maintenance,NvBool restart_training,NvBool nvlink_mode)1823 cciConfigureNvlinkModeModule
1824 (
1825 nvswitch_device *device,
1826 NvU32 client,
1827 NvU8 moduleId,
1828 NvU64 linkMask,
1829 NvBool freeze_maintenance,
1830 NvBool restart_training,
1831 NvBool nvlink_mode
1832 )
1833 {
1834 NvlStatus status;
1835 NvU8 payload[CMIS_CDB_LPL_MAX_SIZE];
1836 NvU8 response[CMIS_CDB_LPL_MAX_SIZE];
1837 NvU32 resLength;
1838 NvU8 linkId;
1839 NvU8 laneMask;
1840 NvU8 laneMaskTemp;
1841
1842 laneMask = 0;
1843
1844 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1845 {
1846 NVSWITCH_PRINT(device, ERROR,
1847 "%s: CCI not supported\n",
1848 __FUNCTION__);
1849 return -NVL_ERR_NOT_SUPPORTED;
1850 }
1851
1852 FOR_EACH_INDEX_IN_MASK(64, linkId, linkMask)
1853 {
1854 status = cciGetLaneMask(device, linkId, &laneMaskTemp);
1855 if (status != NVL_SUCCESS)
1856 {
1857 return status;
1858 }
1859 laneMask |= laneMaskTemp;
1860 }
1861 FOR_EACH_INDEX_IN_MASK_END;
1862
1863 payload[0] = 0;
1864 payload[1] = (freeze_maintenance << 4) + (restart_training << 1) + nvlink_mode;
1865 payload[2] = 0;
1866
1867 // Tx
1868 payload[3] = laneMask;
1869 payload[4] = 0;
1870
1871 // Rx
1872 payload[5] = laneMask;
1873
1874 status = cciSendCDBCommandAndGetResponse(device, client, moduleId, NVSWITCH_CCI_CDB_CMD_ID, 6,
1875 payload, &resLength, response, NV_FALSE);
1876 if (status != NVL_SUCCESS)
1877 {
1878 NVSWITCH_PRINT(device, ERROR, "%s: Failed to configure nvlink mode\n",
1879 __FUNCTION__);
1880 return status;
1881 }
1882
1883 return NVL_SUCCESS;
1884 }
1885
1886 /*
1887 * @brief Configures individual RX and TX osfp lanes to NVLink mode
1888 *
1889 * Freeze Maintenance(FM) : When pre-training starts this should be set, and later
1890 * cleared once link becomes active.
1891 *
1892 * Restart Training(RT) : must be set only when linkup flow is reset and pre-training
1893 * should be performed.
1894 *
1895 * Nvlink Mode(NV) : Must be set to 0x1 for NVLink Mode.
1896 *
1897 * CDB address 0xCD19. Write sequence -
1898 * [0, (0,0,0,0,FM,0,0,RT,NV), TX CH Mask 15..8(00h), TX CH Mask 7..0(FFh), RX CH Mask 15..8 (00h), RX CH Mask 7..0(FFh)]
1899 *
1900 * (ref cdb_prospector.pdf)
1901 */
1902 NvlStatus
cciConfigureNvlinkMode(nvswitch_device * device,NvU32 client,NvU32 linkId,NvBool bTx,NvBool freeze_maintenance,NvBool restart_training,NvBool nvlink_mode)1903 cciConfigureNvlinkMode
1904 (
1905 nvswitch_device *device,
1906 NvU32 client,
1907 NvU32 linkId,
1908 NvBool bTx,
1909 NvBool freeze_maintenance,
1910 NvBool restart_training,
1911 NvBool nvlink_mode
1912 )
1913 {
1914 NvU8 payload[CMIS_CDB_LPL_MAX_SIZE];
1915 NvU8 response[CMIS_CDB_LPL_MAX_SIZE];
1916 NvU32 resLength;
1917 NvlStatus status;
1918 NvU32 osfp;
1919 NvU8 laneMask;
1920
1921 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1922 {
1923 NVSWITCH_PRINT(device, ERROR,
1924 "%s: CCI not supported\n",
1925 __FUNCTION__);
1926 return -NVL_ERR_NOT_SUPPORTED;
1927 }
1928
1929 if (cciGetModuleId(device, linkId, &osfp) != NVL_SUCCESS)
1930 {
1931 NVSWITCH_PRINT(device, ERROR,
1932 "%s: Failed to get moduleId associated with link %d\n",
1933 __FUNCTION__, linkId);
1934 return -NVL_ERR_NOT_SUPPORTED;
1935 }
1936
1937 if (!cciModulePresent(device, osfp))
1938 {
1939 return -NVL_NOT_FOUND;
1940 }
1941
1942 if (cciGetLaneMask(device, linkId, &laneMask) != NVL_SUCCESS)
1943 {
1944 NVSWITCH_PRINT(device, ERROR,
1945 "%s: Failed to get osfp lanemask associated with link %d\n",
1946 __FUNCTION__, linkId);
1947 return -NVL_ERR_NOT_SUPPORTED;
1948 }
1949
1950 payload[0] = 0;
1951 payload[1] = (freeze_maintenance<<4)+(restart_training<<1)+nvlink_mode;
1952 payload[2] = 0;
1953 payload[3] = bTx ? laneMask : 0;
1954 payload[4] = 0;
1955 payload[5] = bTx ? 0 : laneMask;
1956
1957 status = cciSendCDBCommandAndGetResponse(device, client, osfp,
1958 NVSWITCH_CCI_CDB_CMD_ID, 6, payload, &resLength, response, NV_FALSE);
1959 if (status != NVL_SUCCESS)
1960 {
1961 NVSWITCH_PRINT(device, ERROR,
1962 "%s: Failed to configure nvlink mode\n",
1963 __FUNCTION__);
1964 return status;
1965 }
1966
1967 return NVL_SUCCESS;
1968 }
1969
1970 /*
1971 * @brief Check for optical pre training completion
1972 *
1973 * CDB address CD20h - Retrieves individual RX and TX channels training status.
1974 * Read sequence -
1975 * [TX CH Mask 15..8(00h), TX CH Mask 7..0(FFh), RX CH Mask 15..8 (00h), RX CH Mask 7..0(FFh)]
1976 *
1977 * (ref cdb_prospector.pdf)
1978 */
1979 NvBool
cciCheckForPreTraining(nvswitch_device * device,NvU32 client,NvU32 linkId,NvBool bTx)1980 cciCheckForPreTraining
1981 (
1982 nvswitch_device *device,
1983 NvU32 client,
1984 NvU32 linkId,
1985 NvBool bTx
1986 )
1987 {
1988 NvlStatus status;
1989 NvU8 response[CMIS_CDB_LPL_MAX_SIZE];
1990 NvU32 resLength;
1991 NvU32 osfp;
1992 NvU8 train_mask;
1993 NvU8 lane_mask;
1994
1995 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
1996 {
1997 NVSWITCH_PRINT(device, ERROR,
1998 "%s: CCI not supported\n",
1999 __FUNCTION__);
2000 return NV_FALSE;
2001 }
2002
2003 if (cciGetModuleId(device, linkId, &osfp) != NVL_SUCCESS)
2004 {
2005 NVSWITCH_PRINT(device, ERROR,
2006 "%s: Failed to get moduleId associated with link %d\n",
2007 __FUNCTION__, linkId);
2008 return NV_FALSE;
2009 }
2010
2011 if (!cciModulePresent(device, osfp))
2012 {
2013 return NV_FALSE;
2014 }
2015
2016 if (cciGetLaneMask(device, linkId, &lane_mask) != NVL_SUCCESS)
2017 {
2018 NVSWITCH_PRINT(device, ERROR,
2019 "%s: Failed to get osfp lanemask associated with link %d\n",
2020 __FUNCTION__, linkId);
2021 return NV_FALSE;
2022 }
2023
2024 status = cciSendCDBCommandAndGetResponse(device, client, osfp,
2025 0xcd20, 0, NULL, &resLength, response, NV_FALSE);
2026 if (status != NVL_SUCCESS)
2027 {
2028 NVSWITCH_PRINT(device, ERROR,
2029 "%s: Failed to get nvlink status\n",
2030 __FUNCTION__);
2031 return NV_FALSE;
2032 }
2033
2034 train_mask = bTx ? response[1] : response[3];
2035 if ((lane_mask & train_mask) == lane_mask)
2036 {
2037 NVSWITCH_PRINT(device, INFO,
2038 "%s: pre-training completed on link %d!\n",
2039 __FUNCTION__, linkId);
2040 return NV_TRUE;
2041 }
2042
2043 return NV_FALSE;
2044 }
2045
2046 NvlStatus
cciApplyControlSetValues(nvswitch_device * device,NvU32 client,NvU32 moduleMask)2047 cciApplyControlSetValues
2048 (
2049 nvswitch_device *device,
2050 NvU32 client,
2051 NvU32 moduleMask
2052 )
2053 {
2054 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
2055 {
2056 NVSWITCH_PRINT(device, ERROR,
2057 "%s: CCI not supported\n",
2058 __FUNCTION__);
2059 return -NVL_ERR_NOT_SUPPORTED;
2060 }
2061
2062 return nvswitch_cci_apply_control_set_values(device, client, moduleMask);
2063 }
2064
2065 NvlStatus
cciGetGradingValues(nvswitch_device * device,NvU32 client,NvU32 linkId,NvU8 * laneMask,NVSWITCH_CCI_GRADING_VALUES * pGrading)2066 cciGetGradingValues
2067 (
2068 nvswitch_device *device,
2069 NvU32 client,
2070 NvU32 linkId,
2071 NvU8 *laneMask,
2072 NVSWITCH_CCI_GRADING_VALUES *pGrading
2073 )
2074 {
2075 return nvswitch_cci_get_grading_values(device, client, linkId, laneMask, pGrading);
2076 }
2077
2078 /*
2079 * @brief Gets the mapping between cageIndex and link Ids
2080 * Returns a bitmask containing all links mapped to the given
2081 * cage. Also returns a value that encodes other information
2082 * including the mapping between OSFP link lane and Nvlink link
2083 */
2084 NvlStatus
cciGetCageMapping(nvswitch_device * device,NvU8 cageIndex,NvU64 * pLinkMask,NvU64 * pEncodedValue)2085 cciGetCageMapping
2086 (
2087 nvswitch_device *device,
2088 NvU8 cageIndex,
2089 NvU64 *pLinkMask,
2090 NvU64 *pEncodedValue
2091 )
2092 {
2093 NVSWITCH_CCI_MODULE_LINK_LANE_MAP *p_nvswitch_cci_osfp_map;
2094 NvU64 linkMask;
2095 NvU64 encodedValue;
2096 NvU8 *pEncodedByte;
2097 NvU32 nvswitch_cci_osfp_map_size;
2098 NvU32 i;
2099 NvU8 linkId;
2100 NvU8 osfpLane;
2101
2102 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
2103 {
2104 NVSWITCH_PRINT(device, ERROR,
2105 "%s: CCI not initialized\n",
2106 __FUNCTION__);
2107 return -NVL_ERR_NOT_SUPPORTED;
2108 }
2109
2110 linkMask = 0;
2111 encodedValue = 0;
2112 pEncodedByte = (NvU8 *)&encodedValue;
2113 p_nvswitch_cci_osfp_map = device->pCci->osfp_map;
2114 nvswitch_cci_osfp_map_size = device->pCci->osfp_map_size;
2115
2116 for (i = 0; i < nvswitch_cci_osfp_map_size; i++)
2117 {
2118 if (p_nvswitch_cci_osfp_map[i].moduleId == cageIndex)
2119 {
2120 linkId = p_nvswitch_cci_osfp_map[i].linkId;
2121 NVSWITCH_ASSERT(linkId <= 63);
2122
2123 linkMask |= NVBIT64(linkId);
2124 FOR_EACH_INDEX_IN_MASK(8, osfpLane, p_nvswitch_cci_osfp_map[i].laneMask)
2125 {
2126 pEncodedByte[osfpLane] =
2127 REF_NUM(NVSWITCH_CCI_CMIS_NVLINK_MAPPING_ENCODED_VALUE_LINK_ID, linkId);
2128 }
2129 FOR_EACH_INDEX_IN_MASK_END;
2130 }
2131 }
2132
2133 if (pLinkMask != NULL)
2134 {
2135 *pLinkMask = linkMask;
2136 }
2137
2138 if (pEncodedValue != NULL)
2139 {
2140 *pEncodedValue = encodedValue;
2141 }
2142
2143 return NVL_SUCCESS;
2144 }
2145
2146 static NvlStatus
_cciCmisAccessSetup(nvswitch_device * device,NvU8 cageIndex,NvU8 bank,NvU8 page,NvU8 address,NvU8 count,NvU8 * pSavedBank,NvU8 * pSavedPage)2147 _cciCmisAccessSetup
2148 (
2149 nvswitch_device *device,
2150 NvU8 cageIndex,
2151 NvU8 bank,
2152 NvU8 page,
2153 NvU8 address,
2154 NvU8 count,
2155 NvU8 *pSavedBank,
2156 NvU8 *pSavedPage
2157 )
2158 {
2159 NvlStatus status;
2160 NvU32 cagesMask;
2161
2162 status = cciGetXcvrMask(device, &cagesMask, NULL);
2163 if (status != NVL_SUCCESS)
2164 {
2165 return status;
2166 }
2167
2168 if (!(cagesMask & NVBIT(cageIndex)))
2169 {
2170 NVSWITCH_PRINT(device, ERROR,
2171 "%s: Provided cage index does not exist.\n",
2172 __FUNCTION__);
2173 return -NVL_BAD_ARGS;
2174 }
2175
2176 if (count == 0 ||
2177 count > NVSWITCH_CCI_CMIS_MEMORY_ACCESS_BUF_SIZE)
2178 {
2179 NVSWITCH_PRINT(device, ERROR,
2180 "%s: Invalid byte count.\n",
2181 __FUNCTION__);
2182 return -NVL_BAD_ARGS;
2183 }
2184
2185 if (device->pCci->isFlatMemory[cageIndex])
2186 {
2187 if (page != 0 || bank !=0)
2188 {
2189 return -NVL_ERR_NOT_SUPPORTED;
2190 }
2191 else
2192 {
2193 return NVL_SUCCESS;
2194 }
2195 }
2196
2197 if (address >= 0x80)
2198 {
2199 // Save previous bank and page
2200 status = cciGetBankAndPage(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
2201 cageIndex, pSavedBank, pSavedPage);
2202 if (status != NVL_SUCCESS)
2203 {
2204 NVSWITCH_PRINT(device, ERROR,
2205 "%s: Failed to save bank and page.\n",
2206 __FUNCTION__);
2207 return status;
2208 }
2209
2210 // Don't change bank and page unnecessarily
2211 if (*pSavedBank != bank || *pSavedPage != page)
2212 {
2213 status = cciSetBankAndPage(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
2214 cageIndex, bank, page);
2215 if (status != NVL_SUCCESS)
2216 {
2217 NVSWITCH_PRINT(device, ERROR,
2218 "%s: Failed to set bank and page.\n",
2219 __FUNCTION__);
2220 return status;
2221 }
2222 }
2223 }
2224
2225 return NVL_SUCCESS;
2226 }
2227
2228 static NvlStatus
_cciCmisAccessRestore(nvswitch_device * device,NvU8 cageIndex,NvU8 bank,NvU8 page,NvU8 address,NvU8 savedBank,NvU8 savedPage)2229 _cciCmisAccessRestore
2230 (
2231 nvswitch_device *device,
2232 NvU8 cageIndex,
2233 NvU8 bank,
2234 NvU8 page,
2235 NvU8 address,
2236 NvU8 savedBank,
2237 NvU8 savedPage
2238 )
2239 {
2240 NvlStatus status;
2241
2242 if (device->pCci->isFlatMemory[cageIndex])
2243 {
2244 if (page != 0 || bank !=0)
2245 {
2246 return -NVL_ERR_NOT_SUPPORTED;
2247 }
2248 else
2249 {
2250 return NVL_SUCCESS;
2251 }
2252 }
2253
2254 // Restore previous bank and page
2255 if (address >= 0x80)
2256 {
2257 if (savedBank != bank || savedPage != page)
2258 {
2259 status = cciSetBankAndPage(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
2260 cageIndex, savedBank, savedPage);
2261 if (status != NVL_SUCCESS)
2262 {
2263 NVSWITCH_PRINT(device, ERROR,
2264 "%s: Failed to restore bank and page.\n",
2265 __FUNCTION__);
2266 return status;
2267 }
2268 }
2269 }
2270
2271 return NVL_SUCCESS;
2272 }
2273
2274 static NvBool
_cciCmisAccessAllowed(nvswitch_device * device,NvU8 cageIndex)2275 _cciCmisAccessAllowed
2276 (
2277 nvswitch_device *device,
2278 NvU8 cageIndex
2279 )
2280 {
2281 PCCI pCci = device->pCci;
2282 NvU32 pid;
2283 NvlStatus status;
2284
2285 status = nvswitch_os_get_pid(&pid);
2286 if (status != NVL_SUCCESS)
2287 {
2288 NVSWITCH_PRINT(device, WARN,
2289 "%s: CCI CMIS lock not supported\n",
2290 __FUNCTION__);
2291 return NV_TRUE;
2292 }
2293
2294 // Reject clients with different PIDs that attempt access
2295 if (pCci->cmisAccessLock[cageIndex].bLocked &&
2296 (pid != pCci->cmisAccessLock[cageIndex].pid))
2297 {
2298 return NV_FALSE;
2299 }
2300
2301 return NV_TRUE;
2302 }
2303
2304 /*!
2305 * @brief Try to obtain lock for CMIS accesses
2306 */
2307 NvBool
cciCmisAccessTryLock(nvswitch_device * device,NvU8 cageIndex)2308 cciCmisAccessTryLock
2309 (
2310 nvswitch_device *device,
2311 NvU8 cageIndex
2312 )
2313 {
2314 PCCI pCci = device->pCci;
2315 NvU64 timestampCurr;
2316 NvU64 timestampSaved;
2317 NvU32 pid;
2318 NvlStatus status;
2319
2320 status = nvswitch_os_get_pid(&pid);
2321 if (status != NVL_SUCCESS)
2322 {
2323 NVSWITCH_PRINT(device, WARN,
2324 "%s: CCI CMIS lock not supported\n",
2325 __FUNCTION__);
2326 return NV_TRUE;
2327 }
2328
2329 timestampCurr = nvswitch_os_get_platform_time();
2330 timestampSaved = pCci->cmisAccessLock[cageIndex].timestamp;
2331
2332 // Release lock if modules accesses have been idle
2333 if ((timestampCurr - timestampSaved) >= NVSWITCH_CCI_CMIS_LOCK_TIMEOUT)
2334 {
2335 cciCmisAccessReleaseLock(device, cageIndex);
2336 }
2337
2338 if (!_cciCmisAccessAllowed(device, cageIndex))
2339 {
2340 return NV_FALSE;
2341 }
2342
2343 // Lock CMIS access to module. External clients may attempt to lock multiple times
2344 pCci->cmisAccessLock[cageIndex].bLocked = NV_TRUE;
2345 pCci->cmisAccessLock[cageIndex].timestamp = timestampCurr;
2346 pCci->cmisAccessLock[cageIndex].pid = pid;
2347
2348 return NV_TRUE;
2349 }
2350
2351 /*!
2352 * @brief Release lock for CMIS accesses
2353 */
2354 void
cciCmisAccessReleaseLock(nvswitch_device * device,NvU8 cageIndex)2355 cciCmisAccessReleaseLock
2356 (
2357 nvswitch_device *device,
2358 NvU8 cageIndex
2359 )
2360 {
2361 PCCI pCci = device->pCci;
2362 NvU32 pid;
2363 NvlStatus status;
2364
2365 status = nvswitch_os_get_pid(&pid);
2366 if (status != NVL_SUCCESS)
2367 {
2368 NVSWITCH_PRINT(device, WARN,
2369 "%s: CCI CMIS lock not supported\n",
2370 __FUNCTION__);
2371 return;
2372 }
2373
2374 pCci->cmisAccessLock[cageIndex].bLocked = NV_FALSE;
2375 }
2376
2377 /*!
2378 * @brief Read from specified module cage.
2379 * Sets the bank and page if necessary.
2380 */
2381 NvlStatus
cciCmisRead(nvswitch_device * device,NvU8 cageIndex,NvU8 bank,NvU8 page,NvU8 address,NvU8 count,NvU8 * pData)2382 cciCmisRead
2383 (
2384 nvswitch_device *device,
2385 NvU8 cageIndex,
2386 NvU8 bank,
2387 NvU8 page,
2388 NvU8 address,
2389 NvU8 count,
2390 NvU8 *pData
2391 )
2392 {
2393 NvU8 savedBank;
2394 NvU8 savedPage;
2395 NvlStatus status;
2396
2397 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
2398 {
2399 NVSWITCH_PRINT(device, ERROR,
2400 "%s: CCI not supported\n",
2401 __FUNCTION__);
2402 return -NVL_ERR_NOT_SUPPORTED;
2403 }
2404
2405 // Prevent internal driver CMIS reads from occuring while access is locked
2406 if (!_cciCmisAccessAllowed(device, cageIndex))
2407 {
2408 return -NVL_ERR_STATE_IN_USE;
2409 }
2410
2411 // Perform checks and save bank/page if needed
2412 status = _cciCmisAccessSetup(device, cageIndex, bank, page,
2413 address, count, &savedBank, &savedPage);
2414 if (status != NVL_SUCCESS)
2415 {
2416 return status;
2417 }
2418
2419 status = cciRead(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
2420 cageIndex, address, count, pData);
2421 if (status != NVL_SUCCESS)
2422 {
2423 NVSWITCH_PRINT(device, ERROR,
2424 "%s: Failed to read from module cage %d\n",
2425 __FUNCTION__, cageIndex);
2426 return status;
2427 }
2428
2429 status = _cciCmisAccessRestore(device, cageIndex, bank, page,
2430 address, savedBank, savedPage);
2431 if (status != NVL_SUCCESS)
2432 {
2433 return status;
2434 }
2435
2436 return NVL_SUCCESS;
2437 }
2438
2439 /*!
2440 * @brief Write to specified module cage.
2441 * Sets the bank and page if necessary.
2442 */
2443 NvlStatus
cciCmisWrite(nvswitch_device * device,NvU8 cageIndex,NvU8 bank,NvU8 page,NvU8 address,NvU8 count,NvU8 * pData)2444 cciCmisWrite
2445 (
2446 nvswitch_device *device,
2447 NvU8 cageIndex,
2448 NvU8 bank,
2449 NvU8 page,
2450 NvU8 address,
2451 NvU8 count,
2452 NvU8 *pData
2453 )
2454 {
2455 NvU8 savedBank;
2456 NvU8 savedPage;
2457 NvlStatus status;
2458
2459 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
2460 {
2461 NVSWITCH_PRINT(device, ERROR,
2462 "%s: CCI not supported\n",
2463 __FUNCTION__);
2464 return -NVL_ERR_NOT_SUPPORTED;
2465 }
2466
2467 // Prevent internal driver CMIS reads from occuring while access is locked
2468 if (!_cciCmisAccessAllowed(device, cageIndex))
2469 {
2470 return -NVL_ERR_STATE_IN_USE;
2471 }
2472
2473 // Perform checks and save bank/page if needed
2474 status = _cciCmisAccessSetup(device, cageIndex, bank, page,
2475 address, count, &savedBank, &savedPage);
2476 if (status != NVL_SUCCESS)
2477 {
2478 return status;
2479 }
2480
2481 status = cciWrite(device, NVSWITCH_I2C_ACQUIRER_CCI_UX,
2482 cageIndex, address, count, pData);
2483 if (status != NVL_SUCCESS)
2484 {
2485 NVSWITCH_PRINT(device, ERROR,
2486 "%s: Failed to write to module cage %d\n",
2487 __FUNCTION__, cageIndex);
2488 return status;
2489 }
2490
2491 status = _cciCmisAccessRestore(device, cageIndex, bank, page,
2492 address, savedBank, savedPage);
2493 if (status != NVL_SUCCESS)
2494 {
2495 return status;
2496 }
2497
2498 return NVL_SUCCESS;
2499 }
2500
2501 NvlStatus
cciCmisCageBezelMarking(nvswitch_device * device,NvU8 cageIndex,char * pBezelMarking)2502 cciCmisCageBezelMarking
2503 (
2504 nvswitch_device *device,
2505 NvU8 cageIndex,
2506 char *pBezelMarking
2507 )
2508 {
2509 return nvswitch_cci_cmis_cage_bezel_marking(device, cageIndex, pBezelMarking);
2510 }
2511
2512 // Helper functions for CCI subcomponents
2513 NvlStatus
cciGetModuleId(nvswitch_device * device,NvU32 linkId,NvU32 * osfp)2514 cciGetModuleId
2515 (
2516 nvswitch_device *device,
2517 NvU32 linkId,
2518 NvU32 *osfp
2519 )
2520 {
2521 return _nvswitch_cci_get_module_id(device, linkId, osfp);
2522 }
2523
2524 NvBool
cciModulePresent(nvswitch_device * device,NvU32 osfp)2525 cciModulePresent
2526 (
2527 nvswitch_device *device,
2528 NvU32 osfp
2529 )
2530 {
2531 return _nvswitch_cci_module_present(device, osfp);
2532 }
2533
2534 void
cciGetModulePresenceChange(nvswitch_device * device,NvU32 * pModuleMask)2535 cciGetModulePresenceChange
2536 (
2537 nvswitch_device *device,
2538 NvU32 *pModuleMask
2539 )
2540 {
2541 nvswitch_cci_get_xcvrs_present_change(device, pModuleMask);
2542 }
2543
2544 NvlStatus
cciResetModule(nvswitch_device * device,NvU32 moduleId)2545 cciResetModule
2546 (
2547 nvswitch_device *device,
2548 NvU32 moduleId
2549 )
2550 {
2551 NvlStatus retval;
2552 NvU8 regByte;
2553
2554 // Assert OSFP reset
2555 regByte = NVBIT32(moduleId);
2556 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_RESET_REG1, regByte);
2557 if (retval != NVL_SUCCESS)
2558 {
2559 return retval;
2560 }
2561
2562 regByte = (NVBIT32(moduleId) >> 8);
2563 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_RESET_REG2, regByte);
2564 if (retval != NVL_SUCCESS)
2565 {
2566 return retval;
2567 }
2568
2569 nvswitch_os_sleep(1);
2570
2571 // De-assert OSFP reset
2572 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_RESET_REG1, 0);
2573 if (retval != NVL_SUCCESS)
2574 {
2575 return retval;
2576 }
2577
2578 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_RESET_REG2, 0);
2579 if (retval != NVL_SUCCESS)
2580 {
2581 return retval;
2582 }
2583
2584 // Assert lpmode
2585 retval = cciSetLPMode(device, moduleId, NV_TRUE);
2586 if (retval != NVL_SUCCESS)
2587 {
2588 return retval;
2589 }
2590
2591 return NVL_SUCCESS;
2592 }
2593
2594 /*
2595 * @brief Get FW info
2596 * Module FW info is obtained from CDB command 0x100.
2597 * (ref CMIS rev4.0, Table 9-16 CDB Command 0100h: Get firmware Info)
2598 *
2599 * @pre pInfo points to a buffer of size CMIS_CDB_LPL_MAX_SIZE bytes
2600 */
2601 NvlStatus
cciGetXcvrFWInfo(nvswitch_device * device,NvU32 moduleId,NvU8 * pInfo)2602 cciGetXcvrFWInfo
2603 (
2604 nvswitch_device *device,
2605 NvU32 moduleId,
2606 NvU8 *pInfo
2607 )
2608 {
2609 NvlStatus retVal;
2610
2611 if ((device->pCci == NULL) || (!device->pCci->bInitialized))
2612 {
2613 NVSWITCH_PRINT(device, ERROR,
2614 "%s: CCI not supported\n",
2615 __FUNCTION__);
2616 return -NVL_ERR_NOT_SUPPORTED;
2617 }
2618
2619 if (pInfo == NULL)
2620 {
2621 return -NVL_BAD_ARGS;
2622 }
2623
2624 if (!cciModulePresent(device, moduleId))
2625 {
2626 NVSWITCH_PRINT(device, ERROR,
2627 "%s: Module %d is missing\n",
2628 __FUNCTION__, moduleId);
2629 return -NVL_NOT_FOUND;
2630 }
2631
2632 retVal = cciSendCDBCommandAndGetResponse(device, 0, moduleId,
2633 0x100, 0, NULL, NULL, pInfo, NV_FALSE);
2634 if (retVal != NVL_SUCCESS)
2635 {
2636 NVSWITCH_PRINT(device, ERROR,
2637 "%s: Failed to get FW revisions\n",
2638 __FUNCTION__);
2639 return -NVL_ERR_GENERIC;
2640 }
2641
2642 return NVL_SUCCESS;
2643 }
2644
2645 NvlStatus
cciSetLPMode(nvswitch_device * device,NvU8 moduleId,NvBool bAssert)2646 cciSetLPMode
2647 (
2648 nvswitch_device *device,
2649 NvU8 moduleId,
2650 NvBool bAssert
2651 )
2652 {
2653 NvlStatus retval;
2654 NvU8 valReg1;
2655 NvU8 valReg2;
2656
2657 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_PORTS_LPMODE_REG1, &valReg1);
2658 if (retval != NVL_SUCCESS)
2659 {
2660 return retval;
2661 }
2662
2663 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_PORTS_LPMODE_REG2, &valReg2);
2664 if (retval != NVL_SUCCESS)
2665 {
2666 return retval;
2667 }
2668
2669 if (bAssert)
2670 {
2671 valReg1 = valReg1 | NVBIT32(moduleId);
2672 valReg2 = valReg2 | (NVBIT32(moduleId) >> 8);
2673 }
2674 else
2675 {
2676 valReg1 = valReg1 & ~NVBIT32(moduleId);
2677 valReg2 = valReg2 & ~(NVBIT32(moduleId) >> 8);
2678 }
2679
2680 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_LPMODE_REG1, valReg1);
2681 if (retval != NVL_SUCCESS)
2682 {
2683 return retval;
2684 }
2685
2686 retval = nvswitch_cci_ports_cpld_write(device, CPLD_MACHXO3_PORTS_LPMODE_REG2, valReg2);
2687 if (retval != NVL_SUCCESS)
2688 {
2689 return retval;
2690 }
2691
2692 return NVL_SUCCESS;
2693 }
2694
2695 NvBool
cciCheckLPMode(nvswitch_device * device,NvU8 moduleId)2696 cciCheckLPMode
2697 (
2698 nvswitch_device *device,
2699 NvU8 moduleId
2700 )
2701 {
2702 NvlStatus retval;
2703 NvU8 valReg1;
2704 NvU8 valReg2;
2705
2706 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_PORTS_LPMODE_REG1, &valReg1);
2707 if (retval != NVL_SUCCESS)
2708 {
2709 return NV_FALSE;
2710 }
2711
2712 retval = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_PORTS_LPMODE_REG2, &valReg2);
2713 if (retval != NVL_SUCCESS)
2714 {
2715 return NV_FALSE;
2716 }
2717
2718 if ((valReg1 & NVBIT32(moduleId)) ||
2719 (valReg2 & (NVBIT32(moduleId) >> 8)))
2720 {
2721 return NV_TRUE;
2722 }
2723
2724 return NV_FALSE;
2725 }
2726
2727 void
cciPingModules(nvswitch_device * device,NvU32 * pMaskPresent)2728 cciPingModules
2729 (
2730 nvswitch_device *device,
2731 NvU32 *pMaskPresent
2732 )
2733 {
2734 NVSWITCH_CTRL_I2C_INDEXED_PARAMS i2c_params = { 0 };
2735 NvU32 idx_i2cdevice;
2736 PCCI pCci;
2737 NvU32 presentMask;
2738 NvU32 client;
2739 NvlStatus retval;
2740
2741 pCci = device->pCci;
2742 presentMask = 0;
2743 client = NVSWITCH_I2C_ACQUIRER_CCI_INITIALIZE;
2744
2745 for (idx_i2cdevice = 0; idx_i2cdevice < pCci->osfp_num; idx_i2cdevice++)
2746 {
2747 retval = nvswitch_cci_setup_module_path(device, client, idx_i2cdevice);
2748 if (retval != NVL_SUCCESS)
2749 {
2750 continue;
2751 }
2752
2753 i2c_params.port = pCci->osfp_i2c_info[idx_i2cdevice].i2cPortLogical;
2754 i2c_params.address = (NvU16) pCci->osfp_i2c_info[idx_i2cdevice].i2cAddress;
2755 i2c_params.bIsRead = NV_FALSE;
2756 i2c_params.flags =
2757 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _START, _SEND) |
2758 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _RESTART, _NONE) |
2759 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _STOP, _SEND) |
2760 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _ADDRESS_MODE, _7BIT) |
2761 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _INDEX_LENGTH, _ZERO) |
2762 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _FLAVOR, _HW) |
2763 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _SPEED_MODE, _400KHZ) |
2764 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _BLOCK_PROTOCOL, _DISABLED) |
2765 DRF_DEF(SWITCH_CTRL, _I2C_FLAGS, _TRANSACTION_MODE, _PING);
2766 i2c_params.messageLength = 0;
2767 i2c_params.acquirer = client;
2768
2769 if (nvswitch_ctrl_i2c_indexed(device, &i2c_params) == NVL_SUCCESS)
2770 {
2771 // Only print if newly present OSFP
2772 if (!cciModulePresent(device, idx_i2cdevice))
2773 {
2774 NVSWITCH_PRINT(device, INFO,
2775 "%s: Identified osfp = %d, port = %d, addr = 0x%x\n",
2776 __FUNCTION__, idx_i2cdevice, i2c_params.port, i2c_params.address);
2777 }
2778
2779 presentMask |= NVBIT(idx_i2cdevice);
2780 }
2781 }
2782
2783 if (pMaskPresent != NULL)
2784 {
2785 *pMaskPresent = presentMask;
2786 }
2787 }
2788
2789 void
cciGetAllLinks(nvswitch_device * device,NvU64 * pLinkMaskAll)2790 cciGetAllLinks
2791 (
2792 nvswitch_device *device,
2793 NvU64 *pLinkMaskAll
2794 )
2795 {
2796 PCCI pCci = device->pCci;
2797 NvU64 linkMaskAll;
2798 NvU32 i;
2799
2800 linkMaskAll = 0;
2801 for (i = 0; i < pCci->osfp_map_size; i++)
2802 {
2803 linkMaskAll |= NVBIT64(pCci->osfp_map[i].linkId);
2804 }
2805
2806 if (pLinkMaskAll != NULL)
2807 {
2808 *pLinkMaskAll = linkMaskAll;
2809 }
2810 }
2811
2812 NvlStatus
cciGetModuleMask(nvswitch_device * device,NvU64 linkMask,NvU32 * pModuleMask)2813 cciGetModuleMask
2814 (
2815 nvswitch_device *device,
2816 NvU64 linkMask,
2817 NvU32 *pModuleMask
2818 )
2819 {
2820 NvU32 cciModuleMask;
2821 NvU32 moduleId;
2822 NvU8 linkId;
2823 NvlStatus retval;
2824
2825 cciModuleMask = 0;
2826
2827 FOR_EACH_INDEX_IN_MASK(64, linkId, linkMask)
2828 {
2829 retval = cciGetModuleId(device, linkId, &moduleId);
2830 if (retval != NVL_SUCCESS)
2831 {
2832 NVSWITCH_PRINT(device, ERROR,
2833 "%s: Failed to get moduleId associated with link %d\n",
2834 __FUNCTION__, linkId);
2835 return retval;
2836 }
2837
2838 cciModuleMask |= NVBIT32(moduleId);
2839 }
2840 FOR_EACH_INDEX_IN_MASK_END;
2841
2842 *pModuleMask = cciModuleMask;
2843
2844 return NVL_SUCCESS;
2845 }
2846
2847 NvBool
cciCheckXcvrForLinkTraffic(nvswitch_device * device,NvU32 osfp,NvU64 linkMask)2848 cciCheckXcvrForLinkTraffic
2849 (
2850 nvswitch_device *device,
2851 NvU32 osfp,
2852 NvU64 linkMask
2853 )
2854 {
2855 NVSWITCH_GET_THROUGHPUT_COUNTERS_PARAMS *pCounterParams = NULL;
2856 NvU64 *pCounterValues;
2857 NvU64 tpCounterPreviousSum;
2858 NvU64 tpCounterCurrentSum;
2859 NvBool bTraffic = NV_FALSE;
2860 NvU8 linkNum;
2861
2862 pCounterParams = nvswitch_os_malloc(sizeof(*pCounterParams));
2863 if (pCounterParams == NULL)
2864 goto out;
2865
2866 pCounterParams->counterMask = NVSWITCH_THROUGHPUT_COUNTERS_TYPE_DATA_TX |
2867 NVSWITCH_THROUGHPUT_COUNTERS_TYPE_DATA_RX;
2868 pCounterParams->linkMask = linkMask;
2869 if (nvswitch_ctrl_get_throughput_counters(device,
2870 pCounterParams) != NVL_SUCCESS)
2871 {
2872 goto out;
2873 }
2874
2875 // Sum TX/RX traffic for each link
2876 FOR_EACH_INDEX_IN_MASK(64, linkNum, linkMask)
2877 {
2878 pCounterValues = pCounterParams->counters[linkNum].values;
2879
2880 tpCounterPreviousSum = device->pCci->tpCounterPreviousSum[linkNum];
2881
2882 // Sum taken to save space as it is unlikely to overflow before system is reset
2883 tpCounterCurrentSum = pCounterValues[NVSWITCH_THROUGHPUT_COUNTERS_TYPE_DATA_TX] +
2884 pCounterValues[NVSWITCH_THROUGHPUT_COUNTERS_TYPE_DATA_RX];
2885
2886 device->pCci->tpCounterPreviousSum[linkNum] = tpCounterCurrentSum;
2887
2888 // Skip traffic check in first call on system start up
2889 if (device->pCci->callbackCounter == 0)
2890 {
2891 continue;
2892 }
2893
2894 if (tpCounterCurrentSum > tpCounterPreviousSum)
2895 {
2896 bTraffic = NV_TRUE;
2897 }
2898 }
2899 FOR_EACH_INDEX_IN_MASK_END;
2900
2901 out:
2902 nvswitch_os_free(pCounterParams);
2903 return bTraffic;
2904 }
2905
2906 NvlStatus
cciGetLaneMask(nvswitch_device * device,NvU32 linkId,NvU8 * laneMask)2907 cciGetLaneMask
2908 (
2909 nvswitch_device *device,
2910 NvU32 linkId,
2911 NvU8 *laneMask
2912 )
2913 {
2914 NVSWITCH_CCI_MODULE_LINK_LANE_MAP * module_map = device->pCci->osfp_map;
2915 NvU32 module_map_size = device->pCci->osfp_map_size;
2916 NvU32 i;
2917
2918 for (i = 0; i < module_map_size; i++)
2919 {
2920 if (module_map[i].linkId == linkId)
2921 {
2922 *laneMask = module_map[i].laneMask;
2923
2924 return NVL_SUCCESS;
2925 }
2926 }
2927
2928 return -NVL_NOT_FOUND;
2929 }
2930
2931 void
cciSetModulePower(nvswitch_device * device,NvU32 moduleId,NvBool bPowerOn)2932 cciSetModulePower
2933 (
2934 nvswitch_device *device,
2935 NvU32 moduleId,
2936 NvBool bPowerOn
2937 )
2938 {
2939 NvlStatus status;
2940 NvU8 regVal;
2941
2942 if (moduleId < 8)
2943 {
2944 status = nvswitch_cci_ports_cpld_read(device,
2945 CPLD_MACHXO3_LD_SW_EN_REG1,
2946 ®Val);
2947 if (status == NVL_SUCCESS)
2948 {
2949 regVal = bPowerOn ? regVal | NVBIT(moduleId) :
2950 regVal & ~NVBIT(moduleId);
2951 nvswitch_cci_ports_cpld_write(device,
2952 CPLD_MACHXO3_LD_SW_EN_REG1,
2953 regVal);
2954 }
2955 }
2956 else
2957 {
2958 status = nvswitch_cci_ports_cpld_read(device,
2959 CPLD_MACHXO3_LD_SW_EN_REG2,
2960 ®Val);
2961 if (status == NVL_SUCCESS)
2962 {
2963 regVal = bPowerOn ? regVal | NVBIT(moduleId - 8) :
2964 regVal & ~NVBIT(moduleId - 8);
2965 nvswitch_cci_ports_cpld_write(device,
2966 CPLD_MACHXO3_LD_SW_EN_REG2,
2967 regVal);
2968 }
2969 }
2970 }
2971
2972 static void
_cciClearModuleFault(nvswitch_device * device,NvU32 moduleId)2973 _cciClearModuleFault
2974 (
2975 nvswitch_device *device,
2976 NvU32 moduleId
2977 )
2978 {
2979 if (moduleId < 8)
2980 {
2981 nvswitch_cci_ports_cpld_write(device,
2982 CPLD_MACHXO3_LD_SW_FAULT_REG1,
2983 ~NVBIT(moduleId));
2984 }
2985 else
2986 {
2987 nvswitch_cci_ports_cpld_write(device,
2988 CPLD_MACHXO3_LD_SW_FAULT_REG2,
2989 ~NVBIT(moduleId - 8));
2990 }
2991 }
2992
2993 static NvBool
_cciCheckModuleFault(nvswitch_device * device,NvU32 moduleId)2994 _cciCheckModuleFault
2995 (
2996 nvswitch_device *device,
2997 NvU32 moduleId
2998 )
2999 {
3000 NvlStatus status;
3001 NvU8 regVal;
3002
3003 if (moduleId < 8)
3004 {
3005 status = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_LD_SW_FAULT_REG1, ®Val);
3006 if (status != NVL_SUCCESS)
3007 {
3008 return NV_TRUE;
3009 }
3010
3011 if (regVal & NVBIT(moduleId))
3012 {
3013 return NV_TRUE;
3014 }
3015 }
3016 else
3017 {
3018 status = nvswitch_cci_ports_cpld_read(device, CPLD_MACHXO3_LD_SW_FAULT_REG2, ®Val);
3019 if (status != NVL_SUCCESS)
3020 {
3021 return NV_TRUE;
3022 }
3023
3024 if (regVal & NVBIT(moduleId - 8))
3025 {
3026 return NV_TRUE;
3027 }
3028 }
3029
3030 return NV_FALSE;
3031 }
3032
3033 NvBool
cciModuleHWGood(nvswitch_device * device,NvU32 moduleId)3034 cciModuleHWGood
3035 (
3036 nvswitch_device *device,
3037 NvU32 moduleId
3038 )
3039 {
3040 if (_cciCheckModuleFault(device, moduleId))
3041 {
3042 // Attempt to recover module by power cycling
3043 cciSetModulePower(device, moduleId, NV_FALSE);
3044 nvswitch_os_sleep(1);
3045 cciSetModulePower(device, moduleId, NV_TRUE);
3046
3047 // Clear fault flag and check again
3048 _cciClearModuleFault(device, moduleId);
3049 nvswitch_os_sleep(1);
3050
3051 if (_cciCheckModuleFault(device, moduleId))
3052 {
3053 return NV_FALSE;
3054 }
3055 }
3056
3057 return NV_TRUE;
3058 }
3059
3060