1*91676d66SBernhard Stoeckner /*
2*91676d66SBernhard Stoeckner  * SPDX-FileCopyrightText: Copyright (c) 2022-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*91676d66SBernhard Stoeckner  * SPDX-License-Identifier: MIT
4*91676d66SBernhard Stoeckner  *
5*91676d66SBernhard Stoeckner  * Permission is hereby granted, free of charge, to any person obtaining a
6*91676d66SBernhard Stoeckner  * copy of this software and associated documentation files (the "Software"),
7*91676d66SBernhard Stoeckner  * to deal in the Software without restriction, including without limitation
8*91676d66SBernhard Stoeckner  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*91676d66SBernhard Stoeckner  * and/or sell copies of the Software, and to permit persons to whom the
10*91676d66SBernhard Stoeckner  * Software is furnished to do so, subject to the following conditions:
11*91676d66SBernhard Stoeckner  *
12*91676d66SBernhard Stoeckner  * The above copyright notice and this permission notice shall be included in
13*91676d66SBernhard Stoeckner  * all copies or substantial portions of the Software.
14*91676d66SBernhard Stoeckner  *
15*91676d66SBernhard Stoeckner  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*91676d66SBernhard Stoeckner  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*91676d66SBernhard Stoeckner  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*91676d66SBernhard Stoeckner  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*91676d66SBernhard Stoeckner  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*91676d66SBernhard Stoeckner  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*91676d66SBernhard Stoeckner  * DEALINGS IN THE SOFTWARE.
22*91676d66SBernhard Stoeckner  */
23*91676d66SBernhard Stoeckner 
24*91676d66SBernhard Stoeckner #include "common_nvswitch.h"
25*91676d66SBernhard Stoeckner #include "cci/cci_nvswitch.h"
26*91676d66SBernhard Stoeckner #include "cci/cci_priv_nvswitch.h"
27*91676d66SBernhard Stoeckner 
28*91676d66SBernhard Stoeckner /*!
29*91676d66SBernhard Stoeckner  * @brief Checks for CDB command completion.
30*91676d66SBernhard Stoeckner  *
31*91676d66SBernhard Stoeckner  * Page 00h byte 37 contains status bits. BIT 7 is the busy bit.
32*91676d66SBernhard Stoeckner  * (see CMIS rev4.0, Table 9-3, CDB Command 0000h: QUERY-Status)
33*91676d66SBernhard Stoeckner  */
34*91676d66SBernhard Stoeckner static NvlStatus
_cci_check_for_cdb_complete(nvswitch_device * device,NvU32 client,NvU32 osfp)35*91676d66SBernhard Stoeckner _cci_check_for_cdb_complete
36*91676d66SBernhard Stoeckner (
37*91676d66SBernhard Stoeckner     nvswitch_device *device,
38*91676d66SBernhard Stoeckner     NvU32 client,
39*91676d66SBernhard Stoeckner     NvU32 osfp
40*91676d66SBernhard Stoeckner )
41*91676d66SBernhard Stoeckner {
42*91676d66SBernhard Stoeckner     NvU8 status;
43*91676d66SBernhard Stoeckner 
44*91676d66SBernhard Stoeckner     cciRead(device, client, osfp, CMIS_CDB_BLOCK_STATUS_BYTE(0), 1, &status);
45*91676d66SBernhard Stoeckner 
46*91676d66SBernhard Stoeckner     // Return when the STS_BUSY bit goes to 0
47*91676d66SBernhard Stoeckner     if (FLD_TEST_REF(CMIS_CDB_BLOCK_STATUS_BYTE_BUSY, _FALSE, status))
48*91676d66SBernhard Stoeckner     {
49*91676d66SBernhard Stoeckner         return NVL_SUCCESS;
50*91676d66SBernhard Stoeckner     }
51*91676d66SBernhard Stoeckner 
52*91676d66SBernhard Stoeckner     return NVL_ERR_STATE_IN_USE;
53*91676d66SBernhard Stoeckner }
54*91676d66SBernhard Stoeckner 
55*91676d66SBernhard Stoeckner /*!
56*91676d66SBernhard Stoeckner  * @brief Check if module can recieve CDB command
57*91676d66SBernhard Stoeckner  */
58*91676d66SBernhard Stoeckner static NvlStatus
_cci_check_cdb_ready(nvswitch_device * device,NvU8 moduleId)59*91676d66SBernhard Stoeckner _cci_check_cdb_ready
60*91676d66SBernhard Stoeckner (
61*91676d66SBernhard Stoeckner     nvswitch_device *device,
62*91676d66SBernhard Stoeckner     NvU8 moduleId
63*91676d66SBernhard Stoeckner )
64*91676d66SBernhard Stoeckner {
65*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
66*91676d66SBernhard Stoeckner     NvlStatus retval;
67*91676d66SBernhard Stoeckner 
68*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
69*91676d66SBernhard Stoeckner 
70*91676d66SBernhard Stoeckner     if (pCdbState->cdbPhase != CCI_CDB_PHASE_CHECK_READY)
71*91676d66SBernhard Stoeckner     {
72*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
73*91676d66SBernhard Stoeckner     }
74*91676d66SBernhard Stoeckner 
75*91676d66SBernhard Stoeckner     if (!cciModulePresent(device, moduleId))
76*91676d66SBernhard Stoeckner     {
77*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, INFO,
78*91676d66SBernhard Stoeckner                 "%s: osfp %d is missing\n",
79*91676d66SBernhard Stoeckner                 __FUNCTION__, moduleId);
80*91676d66SBernhard Stoeckner         return -NVL_NOT_FOUND;
81*91676d66SBernhard Stoeckner     }
82*91676d66SBernhard Stoeckner 
83*91676d66SBernhard Stoeckner     retval = _cci_check_for_cdb_complete(device, pCdbState->client, moduleId);
84*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
85*91676d66SBernhard Stoeckner     {
86*91676d66SBernhard Stoeckner         return retval;
87*91676d66SBernhard Stoeckner     }
88*91676d66SBernhard Stoeckner 
89*91676d66SBernhard Stoeckner     pCdbState->cdbPhase = CCI_CDB_PHASE_SEND_COMMAND;
90*91676d66SBernhard Stoeckner 
91*91676d66SBernhard Stoeckner     return NVL_SUCCESS;
92*91676d66SBernhard Stoeckner }
93*91676d66SBernhard Stoeckner 
94*91676d66SBernhard Stoeckner /*!
95*91676d66SBernhard Stoeckner  * @brief Send CDB command
96*91676d66SBernhard Stoeckner  */
97*91676d66SBernhard Stoeckner static NvlStatus
_cci_send_cdb_command(nvswitch_device * device,NvU8 moduleId)98*91676d66SBernhard Stoeckner _cci_send_cdb_command
99*91676d66SBernhard Stoeckner (
100*91676d66SBernhard Stoeckner     nvswitch_device *device,
101*91676d66SBernhard Stoeckner     NvU8 moduleId
102*91676d66SBernhard Stoeckner )
103*91676d66SBernhard Stoeckner {
104*91676d66SBernhard Stoeckner     NvlStatus retval;
105*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
106*91676d66SBernhard Stoeckner     NvU8 payload[CMIS_CDB_LPL_MAX_SIZE];
107*91676d66SBernhard Stoeckner     NvU32 payLength;
108*91676d66SBernhard Stoeckner     NvU32 command;
109*91676d66SBernhard Stoeckner     NvBool padding;
110*91676d66SBernhard Stoeckner     NvU8 laneMask;
111*91676d66SBernhard Stoeckner 
112*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
113*91676d66SBernhard Stoeckner 
114*91676d66SBernhard Stoeckner     if (pCdbState->cdbPhase != CCI_CDB_PHASE_SEND_COMMAND)
115*91676d66SBernhard Stoeckner     {
116*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
117*91676d66SBernhard Stoeckner     }
118*91676d66SBernhard Stoeckner 
119*91676d66SBernhard Stoeckner     if (!cciModulePresent(device, moduleId))
120*91676d66SBernhard Stoeckner     {
121*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, INFO,
122*91676d66SBernhard Stoeckner                 "%s: osfp %d is missing\n",
123*91676d66SBernhard Stoeckner                 __FUNCTION__, moduleId);
124*91676d66SBernhard Stoeckner         return -NVL_NOT_FOUND;
125*91676d66SBernhard Stoeckner     }
126*91676d66SBernhard Stoeckner 
127*91676d66SBernhard Stoeckner     // Roll up lanes that will be operated on
128*91676d66SBernhard Stoeckner     laneMask = pCdbState->laneMasksPending[0] |
129*91676d66SBernhard Stoeckner                pCdbState->laneMasksPending[1] |
130*91676d66SBernhard Stoeckner                pCdbState->laneMasksPending[2] |
131*91676d66SBernhard Stoeckner                pCdbState->laneMasksPending[3];
132*91676d66SBernhard Stoeckner 
133*91676d66SBernhard Stoeckner     // Clear lanes whose commands will be triggered
134*91676d66SBernhard Stoeckner     pCdbState->laneMasksPending[0] &= ~laneMask;
135*91676d66SBernhard Stoeckner     pCdbState->laneMasksPending[1] &= ~laneMask;
136*91676d66SBernhard Stoeckner     pCdbState->laneMasksPending[2] &= ~laneMask;
137*91676d66SBernhard Stoeckner     pCdbState->laneMasksPending[3] &= ~laneMask;
138*91676d66SBernhard Stoeckner 
139*91676d66SBernhard Stoeckner     payload[0] = 0;
140*91676d66SBernhard Stoeckner     payload[1] = (pCdbState->freeze_maintenance << 4) +
141*91676d66SBernhard Stoeckner                  (pCdbState->restart_training << 1) +
142*91676d66SBernhard Stoeckner                  pCdbState->nvlink_mode;
143*91676d66SBernhard Stoeckner     payload[2] = 0;
144*91676d66SBernhard Stoeckner 
145*91676d66SBernhard Stoeckner     // Tx
146*91676d66SBernhard Stoeckner     payload[3] = laneMask;
147*91676d66SBernhard Stoeckner     payload[4] = 0;
148*91676d66SBernhard Stoeckner 
149*91676d66SBernhard Stoeckner     // Rx
150*91676d66SBernhard Stoeckner     payload[5] = laneMask;
151*91676d66SBernhard Stoeckner 
152*91676d66SBernhard Stoeckner     payLength = 6;
153*91676d66SBernhard Stoeckner     command = NVSWITCH_CCI_CDB_CMD_ID;
154*91676d66SBernhard Stoeckner     padding = NV_FALSE;
155*91676d66SBernhard Stoeckner 
156*91676d66SBernhard Stoeckner     retval = cciSendCDBCommand(device, pCdbState->client, moduleId, command, payLength, payload, padding);
157*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
158*91676d66SBernhard Stoeckner     {
159*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, INFO,
160*91676d66SBernhard Stoeckner             "%s: Failed to send CDB Command: 0x%x\n",
161*91676d66SBernhard Stoeckner             __FUNCTION__, command);
162*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
163*91676d66SBernhard Stoeckner     }
164*91676d66SBernhard Stoeckner 
165*91676d66SBernhard Stoeckner     pCdbState->cdbPhase = CCI_CDB_PHASE_GET_RESPONSE;
166*91676d66SBernhard Stoeckner 
167*91676d66SBernhard Stoeckner     return NVL_SUCCESS;
168*91676d66SBernhard Stoeckner }
169*91676d66SBernhard Stoeckner 
170*91676d66SBernhard Stoeckner /*!
171*91676d66SBernhard Stoeckner  * @brief Get get CDB response.
172*91676d66SBernhard Stoeckner  */
173*91676d66SBernhard Stoeckner static NvlStatus
_cci_get_cdb_response(nvswitch_device * device,NvU8 moduleId)174*91676d66SBernhard Stoeckner _cci_get_cdb_response
175*91676d66SBernhard Stoeckner (
176*91676d66SBernhard Stoeckner     nvswitch_device *device,
177*91676d66SBernhard Stoeckner     NvU8 moduleId
178*91676d66SBernhard Stoeckner )
179*91676d66SBernhard Stoeckner {
180*91676d66SBernhard Stoeckner     NvlStatus retval;
181*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
182*91676d66SBernhard Stoeckner     NvU8 cdbStatus = 0;
183*91676d66SBernhard Stoeckner     NvU8 response[CMIS_CDB_LPL_MAX_SIZE];
184*91676d66SBernhard Stoeckner     NvU32 resLength;
185*91676d66SBernhard Stoeckner 
186*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
187*91676d66SBernhard Stoeckner 
188*91676d66SBernhard Stoeckner     if (pCdbState->cdbPhase != CCI_CDB_PHASE_GET_RESPONSE)
189*91676d66SBernhard Stoeckner     {
190*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
191*91676d66SBernhard Stoeckner     }
192*91676d66SBernhard Stoeckner 
193*91676d66SBernhard Stoeckner     if (!cciModulePresent(device, moduleId))
194*91676d66SBernhard Stoeckner     {
195*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, INFO,
196*91676d66SBernhard Stoeckner                 "%s: osfp %d is missing\n",
197*91676d66SBernhard Stoeckner                 __FUNCTION__, moduleId);
198*91676d66SBernhard Stoeckner         return -NVL_NOT_FOUND;
199*91676d66SBernhard Stoeckner     }
200*91676d66SBernhard Stoeckner 
201*91676d66SBernhard Stoeckner     retval = _cci_check_for_cdb_complete(device, pCdbState->client, moduleId);
202*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
203*91676d66SBernhard Stoeckner     {
204*91676d66SBernhard Stoeckner         return retval;
205*91676d66SBernhard Stoeckner     }
206*91676d66SBernhard Stoeckner 
207*91676d66SBernhard Stoeckner     retval = cciGetCDBStatus(device, pCdbState->client, moduleId, &cdbStatus);
208*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
209*91676d66SBernhard Stoeckner     {
210*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, ERROR,
211*91676d66SBernhard Stoeckner             "%s: CDB command failed! result = 0x%x\n",
212*91676d66SBernhard Stoeckner             __FUNCTION__, cdbStatus);
213*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
214*91676d66SBernhard Stoeckner     }
215*91676d66SBernhard Stoeckner 
216*91676d66SBernhard Stoeckner     retval = cciGetCDBResponse(device, pCdbState->client, moduleId, response, &resLength);
217*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
218*91676d66SBernhard Stoeckner     {
219*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, ERROR,
220*91676d66SBernhard Stoeckner             "%s: Failed to get CDB command response\n",
221*91676d66SBernhard Stoeckner             __FUNCTION__);
222*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
223*91676d66SBernhard Stoeckner     }
224*91676d66SBernhard Stoeckner 
225*91676d66SBernhard Stoeckner     pCdbState->cdbPhase = CCI_CDB_PHASE_CHECK_DONE;
226*91676d66SBernhard Stoeckner 
227*91676d66SBernhard Stoeckner     return NVL_SUCCESS;
228*91676d66SBernhard Stoeckner }
229*91676d66SBernhard Stoeckner 
230*91676d66SBernhard Stoeckner /*!
231*91676d66SBernhard Stoeckner  * @brief
232*91676d66SBernhard Stoeckner  */
233*91676d66SBernhard Stoeckner static NvlStatus
_cci_check_cdb_done(nvswitch_device * device,NvU8 moduleId)234*91676d66SBernhard Stoeckner _cci_check_cdb_done
235*91676d66SBernhard Stoeckner (
236*91676d66SBernhard Stoeckner     nvswitch_device *device,
237*91676d66SBernhard Stoeckner     NvU8 moduleId
238*91676d66SBernhard Stoeckner )
239*91676d66SBernhard Stoeckner {
240*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
241*91676d66SBernhard Stoeckner 
242*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
243*91676d66SBernhard Stoeckner 
244*91676d66SBernhard Stoeckner     if (pCdbState->cdbPhase != CCI_CDB_PHASE_CHECK_DONE)
245*91676d66SBernhard Stoeckner     {
246*91676d66SBernhard Stoeckner         return -NVL_ERR_GENERIC;
247*91676d66SBernhard Stoeckner     }
248*91676d66SBernhard Stoeckner 
249*91676d66SBernhard Stoeckner     // Finish pending links
250*91676d66SBernhard Stoeckner     if (pCdbState->laneMasksPending[0] ||
251*91676d66SBernhard Stoeckner         pCdbState->laneMasksPending[1] ||
252*91676d66SBernhard Stoeckner         pCdbState->laneMasksPending[2] ||
253*91676d66SBernhard Stoeckner         pCdbState->laneMasksPending[3])
254*91676d66SBernhard Stoeckner     {
255*91676d66SBernhard Stoeckner         pCdbState->cdbPhase = CCI_CDB_PHASE_CHECK_READY;
256*91676d66SBernhard Stoeckner     }
257*91676d66SBernhard Stoeckner     else
258*91676d66SBernhard Stoeckner     {
259*91676d66SBernhard Stoeckner         pCdbState->cdbPhase = CCI_CDB_PHASE_IDLE;
260*91676d66SBernhard Stoeckner     }
261*91676d66SBernhard Stoeckner 
262*91676d66SBernhard Stoeckner     return NVL_SUCCESS;
263*91676d66SBernhard Stoeckner }
264*91676d66SBernhard Stoeckner 
265*91676d66SBernhard Stoeckner /*
266*91676d66SBernhard Stoeckner  * @brief Performs CDB stages on a module without blocking
267*91676d66SBernhard Stoeckner  *
268*91676d66SBernhard Stoeckner  */
269*91676d66SBernhard Stoeckner static void
_cci_cdb_perform_phases(nvswitch_device * device,NvU8 moduleId)270*91676d66SBernhard Stoeckner _cci_cdb_perform_phases
271*91676d66SBernhard Stoeckner (
272*91676d66SBernhard Stoeckner     nvswitch_device *device,
273*91676d66SBernhard Stoeckner     NvU8  moduleId
274*91676d66SBernhard Stoeckner )
275*91676d66SBernhard Stoeckner {
276*91676d66SBernhard Stoeckner     NVSWITCH_TIMEOUT timeout;
277*91676d66SBernhard Stoeckner     NvlStatus retval = NVL_SUCCESS;
278*91676d66SBernhard Stoeckner     NvBool bContinue = NV_TRUE;
279*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
280*91676d66SBernhard Stoeckner 
281*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
282*91676d66SBernhard Stoeckner 
283*91676d66SBernhard Stoeckner     nvswitch_timeout_create(NVSWITCH_INTERVAL_1SEC_IN_NS, &timeout);
284*91676d66SBernhard Stoeckner 
285*91676d66SBernhard Stoeckner     do
286*91676d66SBernhard Stoeckner     {
287*91676d66SBernhard Stoeckner         switch (pCdbState->cdbPhase)
288*91676d66SBernhard Stoeckner         {
289*91676d66SBernhard Stoeckner             case CCI_CDB_PHASE_CHECK_READY:
290*91676d66SBernhard Stoeckner             {
291*91676d66SBernhard Stoeckner                 retval = _cci_check_cdb_ready(device, moduleId);
292*91676d66SBernhard Stoeckner                 break;
293*91676d66SBernhard Stoeckner             }
294*91676d66SBernhard Stoeckner             case CCI_CDB_PHASE_SEND_COMMAND:
295*91676d66SBernhard Stoeckner             {
296*91676d66SBernhard Stoeckner                 retval = _cci_send_cdb_command(device, moduleId);
297*91676d66SBernhard Stoeckner                 break;
298*91676d66SBernhard Stoeckner             }
299*91676d66SBernhard Stoeckner             case CCI_CDB_PHASE_GET_RESPONSE:
300*91676d66SBernhard Stoeckner             {
301*91676d66SBernhard Stoeckner                 retval = _cci_get_cdb_response(device, moduleId);
302*91676d66SBernhard Stoeckner                 break;
303*91676d66SBernhard Stoeckner             }
304*91676d66SBernhard Stoeckner             case CCI_CDB_PHASE_CHECK_DONE:
305*91676d66SBernhard Stoeckner             {
306*91676d66SBernhard Stoeckner                 retval = _cci_check_cdb_done(device, moduleId);
307*91676d66SBernhard Stoeckner                 break;
308*91676d66SBernhard Stoeckner             }
309*91676d66SBernhard Stoeckner             default:
310*91676d66SBernhard Stoeckner             {
311*91676d66SBernhard Stoeckner                 retval = NVL_SUCCESS;
312*91676d66SBernhard Stoeckner                 bContinue = NV_FALSE;
313*91676d66SBernhard Stoeckner                 NVSWITCH_ASSERT(pCdbState->cdbPhase == CCI_CDB_PHASE_IDLE);
314*91676d66SBernhard Stoeckner                 break;
315*91676d66SBernhard Stoeckner             }
316*91676d66SBernhard Stoeckner         }
317*91676d66SBernhard Stoeckner 
318*91676d66SBernhard Stoeckner         // Module is busy
319*91676d66SBernhard Stoeckner         if (retval == NVL_ERR_STATE_IN_USE)
320*91676d66SBernhard Stoeckner         {
321*91676d66SBernhard Stoeckner             // Nothing more to do for now
322*91676d66SBernhard Stoeckner             bContinue = NV_FALSE;
323*91676d66SBernhard Stoeckner         }
324*91676d66SBernhard Stoeckner 
325*91676d66SBernhard Stoeckner         if (retval < 0)
326*91676d66SBernhard Stoeckner         {
327*91676d66SBernhard Stoeckner             NVSWITCH_PRINT(device, ERROR,
328*91676d66SBernhard Stoeckner                     "%s: CDB error module %d, phase %d!\n",
329*91676d66SBernhard Stoeckner                     __FUNCTION__, moduleId, pCdbState->cdbPhase);
330*91676d66SBernhard Stoeckner             bContinue = NV_FALSE;
331*91676d66SBernhard Stoeckner             pCdbState->cdbPhase = CCI_CDB_PHASE_CHECK_DONE;
332*91676d66SBernhard Stoeckner         }
333*91676d66SBernhard Stoeckner 
334*91676d66SBernhard Stoeckner         // Just in case
335*91676d66SBernhard Stoeckner         if (nvswitch_timeout_check(&timeout))
336*91676d66SBernhard Stoeckner         {
337*91676d66SBernhard Stoeckner             NVSWITCH_PRINT(device, ERROR,
338*91676d66SBernhard Stoeckner                 "%s: Timeout!\n",
339*91676d66SBernhard Stoeckner                     __FUNCTION__);
340*91676d66SBernhard Stoeckner             break;
341*91676d66SBernhard Stoeckner         }
342*91676d66SBernhard Stoeckner     } while(bContinue);
343*91676d66SBernhard Stoeckner }
344*91676d66SBernhard Stoeckner 
345*91676d66SBernhard Stoeckner void
cciProcessCDBCallback(nvswitch_device * device)346*91676d66SBernhard Stoeckner cciProcessCDBCallback
347*91676d66SBernhard Stoeckner (
348*91676d66SBernhard Stoeckner     nvswitch_device         *device
349*91676d66SBernhard Stoeckner )
350*91676d66SBernhard Stoeckner {
351*91676d66SBernhard Stoeckner     NVSWITCH_TIMEOUT timeout;
352*91676d66SBernhard Stoeckner     NvU32 moduleMaskPriority;
353*91676d66SBernhard Stoeckner     NvU32 moduleMask;
354*91676d66SBernhard Stoeckner     NvU8  moduleId;
355*91676d66SBernhard Stoeckner 
356*91676d66SBernhard Stoeckner     moduleMaskPriority = 0;
357*91676d66SBernhard Stoeckner 
358*91676d66SBernhard Stoeckner     nvswitch_timeout_create(20 * NVSWITCH_INTERVAL_1MSEC_IN_NS, &timeout);
359*91676d66SBernhard Stoeckner 
360*91676d66SBernhard Stoeckner     // Attempt to complete CDB commands for present modules
361*91676d66SBernhard Stoeckner     if (cciGetXcvrMask(device, &moduleMask, NULL) == NVL_SUCCESS)
362*91676d66SBernhard Stoeckner     {
363*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK(32, moduleId, moduleMask)
364*91676d66SBernhard Stoeckner         {
365*91676d66SBernhard Stoeckner             //
366*91676d66SBernhard Stoeckner             // Prioritize sending CDB commands.
367*91676d66SBernhard Stoeckner             // This also prioritizes getting responses for CDBs in the event that
368*91676d66SBernhard Stoeckner             // fewer than all lanes of a module were operated on.
369*91676d66SBernhard Stoeckner             //
370*91676d66SBernhard Stoeckner             if (device->pCci->cdbState[moduleId].laneMasksPending[0] ||
371*91676d66SBernhard Stoeckner                 device->pCci->cdbState[moduleId].laneMasksPending[1] ||
372*91676d66SBernhard Stoeckner                 device->pCci->cdbState[moduleId].laneMasksPending[2] ||
373*91676d66SBernhard Stoeckner                 device->pCci->cdbState[moduleId].laneMasksPending[3])
374*91676d66SBernhard Stoeckner             {
375*91676d66SBernhard Stoeckner                 moduleMaskPriority |= NVBIT32(moduleId);
376*91676d66SBernhard Stoeckner             }
377*91676d66SBernhard Stoeckner         }
378*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK_END;
379*91676d66SBernhard Stoeckner 
380*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK(32, moduleId, moduleMaskPriority)
381*91676d66SBernhard Stoeckner         {
382*91676d66SBernhard Stoeckner             _cci_cdb_perform_phases(device, moduleId);
383*91676d66SBernhard Stoeckner         }
384*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK_END;
385*91676d66SBernhard Stoeckner 
386*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK(32, moduleId, moduleMask)
387*91676d66SBernhard Stoeckner         {
388*91676d66SBernhard Stoeckner             _cci_cdb_perform_phases(device, moduleId);
389*91676d66SBernhard Stoeckner 
390*91676d66SBernhard Stoeckner             // Short circuit getting non time sensistive responses
391*91676d66SBernhard Stoeckner             if (nvswitch_timeout_check(&timeout))
392*91676d66SBernhard Stoeckner             {
393*91676d66SBernhard Stoeckner                 break;
394*91676d66SBernhard Stoeckner             }
395*91676d66SBernhard Stoeckner         }
396*91676d66SBernhard Stoeckner         FOR_EACH_INDEX_IN_MASK_END;
397*91676d66SBernhard Stoeckner     }
398*91676d66SBernhard Stoeckner }
399*91676d66SBernhard Stoeckner 
400*91676d66SBernhard Stoeckner NvlStatus
cciConfigureNvlinkModeAsync(nvswitch_device * device,NvU32 client,NvU8 linkId,NvBool freeze_maintenance,NvBool restart_training,NvBool nvlink_mode)401*91676d66SBernhard Stoeckner cciConfigureNvlinkModeAsync
402*91676d66SBernhard Stoeckner (
403*91676d66SBernhard Stoeckner     nvswitch_device *device,
404*91676d66SBernhard Stoeckner     NvU32            client,
405*91676d66SBernhard Stoeckner     NvU8             linkId,
406*91676d66SBernhard Stoeckner     NvBool           freeze_maintenance,
407*91676d66SBernhard Stoeckner     NvBool           restart_training,
408*91676d66SBernhard Stoeckner     NvBool           nvlink_mode
409*91676d66SBernhard Stoeckner )
410*91676d66SBernhard Stoeckner {
411*91676d66SBernhard Stoeckner     NvlStatus retval;
412*91676d66SBernhard Stoeckner     CCI_CDB_STATE *pCdbState;
413*91676d66SBernhard Stoeckner     NvU32 moduleId;
414*91676d66SBernhard Stoeckner     NvU8 laneMask;
415*91676d66SBernhard Stoeckner     NvU8 laneMasksIndex;
416*91676d66SBernhard Stoeckner 
417*91676d66SBernhard Stoeckner     if ((device->pCci == NULL) || (!device->pCci->bInitialized))
418*91676d66SBernhard Stoeckner     {
419*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, ERROR,
420*91676d66SBernhard Stoeckner             "%s: CCI not supported\n",
421*91676d66SBernhard Stoeckner             __FUNCTION__);
422*91676d66SBernhard Stoeckner         return -NVL_ERR_NOT_SUPPORTED;
423*91676d66SBernhard Stoeckner     }
424*91676d66SBernhard Stoeckner 
425*91676d66SBernhard Stoeckner     retval = cciGetModuleId(device, linkId, &moduleId);
426*91676d66SBernhard Stoeckner     if (retval != NVL_SUCCESS)
427*91676d66SBernhard Stoeckner     {
428*91676d66SBernhard Stoeckner         return retval;
429*91676d66SBernhard Stoeckner     }
430*91676d66SBernhard Stoeckner 
431*91676d66SBernhard Stoeckner     if (!cciModulePresent(device, moduleId))
432*91676d66SBernhard Stoeckner     {
433*91676d66SBernhard Stoeckner         return -NVL_NOT_FOUND;
434*91676d66SBernhard Stoeckner     }
435*91676d66SBernhard Stoeckner 
436*91676d66SBernhard Stoeckner     if (cciGetLaneMask(device, linkId, &laneMask) != NVL_SUCCESS)
437*91676d66SBernhard Stoeckner     {
438*91676d66SBernhard Stoeckner         NVSWITCH_PRINT(device, ERROR,
439*91676d66SBernhard Stoeckner             "%s: Failed to get osfp lanemask associated with link %d\n",
440*91676d66SBernhard Stoeckner             __FUNCTION__, linkId);
441*91676d66SBernhard Stoeckner         return -NVL_ERR_NOT_SUPPORTED;
442*91676d66SBernhard Stoeckner     }
443*91676d66SBernhard Stoeckner 
444*91676d66SBernhard Stoeckner     pCdbState = &device->pCci->cdbState[moduleId];
445*91676d66SBernhard Stoeckner 
446*91676d66SBernhard Stoeckner     // Add to first available slot
447*91676d66SBernhard Stoeckner     for (laneMasksIndex = 0; laneMasksIndex < NVSWITCH_CCI_NUM_LINKS_PER_OSFP_LS10; laneMasksIndex++)
448*91676d66SBernhard Stoeckner     {
449*91676d66SBernhard Stoeckner         if (pCdbState->laneMasksPending[laneMasksIndex] == 0)
450*91676d66SBernhard Stoeckner         {
451*91676d66SBernhard Stoeckner             pCdbState->laneMasksPending[laneMasksIndex] = laneMask;
452*91676d66SBernhard Stoeckner             break;
453*91676d66SBernhard Stoeckner         }
454*91676d66SBernhard Stoeckner     }
455*91676d66SBernhard Stoeckner 
456*91676d66SBernhard Stoeckner     if (pCdbState->cdbPhase != CCI_CDB_PHASE_IDLE)
457*91676d66SBernhard Stoeckner     {
458*91676d66SBernhard Stoeckner         // Don't support queuing multiple CDB command types
459*91676d66SBernhard Stoeckner         NVSWITCH_ASSERT(pCdbState->client == client);
460*91676d66SBernhard Stoeckner         NVSWITCH_ASSERT(pCdbState->freeze_maintenance == freeze_maintenance);
461*91676d66SBernhard Stoeckner         NVSWITCH_ASSERT(pCdbState->restart_training == restart_training);
462*91676d66SBernhard Stoeckner         NVSWITCH_ASSERT(pCdbState->nvlink_mode == nvlink_mode);
463*91676d66SBernhard Stoeckner 
464*91676d66SBernhard Stoeckner         return NVL_SUCCESS;
465*91676d66SBernhard Stoeckner     }
466*91676d66SBernhard Stoeckner 
467*91676d66SBernhard Stoeckner     // Setup cdbstate for callback
468*91676d66SBernhard Stoeckner     pCdbState->client = client;
469*91676d66SBernhard Stoeckner     pCdbState->freeze_maintenance = freeze_maintenance;
470*91676d66SBernhard Stoeckner     pCdbState->restart_training = restart_training;
471*91676d66SBernhard Stoeckner     pCdbState->nvlink_mode = nvlink_mode;
472*91676d66SBernhard Stoeckner     pCdbState->cdbPhase = CCI_CDB_PHASE_CHECK_READY;
473*91676d66SBernhard Stoeckner 
474*91676d66SBernhard Stoeckner     return NVL_SUCCESS;
475*91676d66SBernhard Stoeckner }
476