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                                   &regVal);
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                                   &regVal);
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, &regVal);
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, &regVal);
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