1*90eb1077SAndy Ritger /*
2*90eb1077SAndy Ritger  * SPDX-FileCopyrightText: Copyright (c) 2021-2022 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3*90eb1077SAndy Ritger  * SPDX-License-Identifier: MIT
4*90eb1077SAndy Ritger  *
5*90eb1077SAndy Ritger  * Permission is hereby granted, free of charge, to any person obtaining a
6*90eb1077SAndy Ritger  * copy of this software and associated documentation files (the "Software"),
7*90eb1077SAndy Ritger  * to deal in the Software without restriction, including without limitation
8*90eb1077SAndy Ritger  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9*90eb1077SAndy Ritger  * and/or sell copies of the Software, and to permit persons to whom the
10*90eb1077SAndy Ritger  * Software is furnished to do so, subject to the following conditions:
11*90eb1077SAndy Ritger  *
12*90eb1077SAndy Ritger  * The above copyright notice and this permission notice shall be included in
13*90eb1077SAndy Ritger  * all copies or substantial portions of the Software.
14*90eb1077SAndy Ritger  *
15*90eb1077SAndy Ritger  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16*90eb1077SAndy Ritger  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17*90eb1077SAndy Ritger  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18*90eb1077SAndy Ritger  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19*90eb1077SAndy Ritger  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20*90eb1077SAndy Ritger  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21*90eb1077SAndy Ritger  * DEALINGS IN THE SOFTWARE.
22*90eb1077SAndy Ritger  */
23*90eb1077SAndy Ritger 
24*90eb1077SAndy Ritger  /*!
25*90eb1077SAndy Ritger   *
26*90eb1077SAndy Ritger   * @file   kern_fsp.c
27*90eb1077SAndy Ritger   * @brief  Provides all kernel side interfaces for tracking the FSP state,
28*90eb1077SAndy Ritger   *         submitting commands and parsing replies needed from the CPU.
29*90eb1077SAndy Ritger   */
30*90eb1077SAndy Ritger #include "gpu/gpu.h"
31*90eb1077SAndy Ritger #include "gpu/fsp/kern_fsp.h"
32*90eb1077SAndy Ritger #include "nvrm_registry.h"
33*90eb1077SAndy Ritger 
34*90eb1077SAndy Ritger #if RMCFG_MODULE_ENABLED (GSP)
35*90eb1077SAndy Ritger #include "gpu/gsp/gsp.h"
36*90eb1077SAndy Ritger #include "objflcnable.h"
37*90eb1077SAndy Ritger #endif
38*90eb1077SAndy Ritger 
39*90eb1077SAndy Ritger /*!
40*90eb1077SAndy Ritger * Local object related functions
41*90eb1077SAndy Ritger */
42*90eb1077SAndy Ritger static void kfspInitRegistryOverrides(OBJGPU *, KernelFsp *);
43*90eb1077SAndy Ritger 
44*90eb1077SAndy Ritger static NV_STATUS kfspReadMessage(OBJGPU *pGpu, KernelFsp *pKernelFsp, NvU8 *pPayloadBuffer, NvU32 payloadBufferSize);
45*90eb1077SAndy Ritger 
46*90eb1077SAndy Ritger NV_STATUS
47*90eb1077SAndy Ritger kfspConstructEngine_IMPL(OBJGPU *pGpu, KernelFsp *pKernelFsp, ENGDESCRIPTOR engDesc)
48*90eb1077SAndy Ritger {
49*90eb1077SAndy Ritger 
50*90eb1077SAndy Ritger     // Initialize based on registry keys
51*90eb1077SAndy Ritger     kfspInitRegistryOverrides(pGpu, pKernelFsp);
52*90eb1077SAndy Ritger     if (pKernelFsp->getProperty(pKernelFsp, PDB_PROP_KFSP_IS_MISSING))
53*90eb1077SAndy Ritger     {
54*90eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "KernelFsp is disabled\n");
55*90eb1077SAndy Ritger         return NV_ERR_OBJECT_NOT_FOUND;
56*90eb1077SAndy Ritger     }
57*90eb1077SAndy Ritger     return NV_OK;
58*90eb1077SAndy Ritger }
59*90eb1077SAndy Ritger 
60*90eb1077SAndy Ritger /*!
61*90eb1077SAndy Ritger  * Initialize all registry overrides for this object
62*90eb1077SAndy Ritger  *
63*90eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
64*90eb1077SAndy Ritger  * @param[in]  pKernelFsp KernelFsp object pointer
65*90eb1077SAndy Ritger  */
66*90eb1077SAndy Ritger static void
67*90eb1077SAndy Ritger kfspInitRegistryOverrides
68*90eb1077SAndy Ritger (
69*90eb1077SAndy Ritger     OBJGPU    *pGpu,
70*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
71*90eb1077SAndy Ritger )
72*90eb1077SAndy Ritger {
73*90eb1077SAndy Ritger     NvU32 data = 0;
74*90eb1077SAndy Ritger 
75*90eb1077SAndy Ritger     if (((osReadRegistryDword(pGpu, NV_REG_STR_RM_DISABLE_FSP, &data) == NV_OK) &&
76*90eb1077SAndy Ritger         (data == NV_REG_STR_RM_DISABLE_FSP_YES) && IS_EMULATION(pGpu)) ||
77*90eb1077SAndy Ritger         IS_FMODEL(pGpu))
78*90eb1077SAndy Ritger     {
79*90eb1077SAndy Ritger         //
80*90eb1077SAndy Ritger         // Force disable FSP engine, used only on emulation because some
81*90eb1077SAndy Ritger         // emulation netlists stub out FSP but leave the engine in PTOP
82*90eb1077SAndy Ritger         //
83*90eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "FSP disabled due to regkey override.\n");
84*90eb1077SAndy Ritger         pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_IS_MISSING, NV_TRUE);
85*90eb1077SAndy Ritger     }
86*90eb1077SAndy Ritger 
87*90eb1077SAndy Ritger     if (osReadRegistryDword(pGpu, NV_REG_STR_RM_DISABLE_COT_CMD, &data) == NV_OK)
88*90eb1077SAndy Ritger     {
89*90eb1077SAndy Ritger         // Assume non-zero value only has NV_REG_STR_RM_DISABLE_COT_CMD_YES
90*90eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_FRTS_SYSMEM))
91*90eb1077SAndy Ritger         {
92*90eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_SYSMEM, NV_TRUE);
93*90eb1077SAndy Ritger         }
94*90eb1077SAndy Ritger 
95*90eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_FRTS_VIDMEM))
96*90eb1077SAndy Ritger         {
97*90eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_VIDMEM, NV_TRUE);
98*90eb1077SAndy Ritger         }
99*90eb1077SAndy Ritger 
100*90eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_GSPFMC))
101*90eb1077SAndy Ritger         {
102*90eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_GSPFMC, NV_TRUE);
103*90eb1077SAndy Ritger         }
104*90eb1077SAndy Ritger     }
105*90eb1077SAndy Ritger 
106*90eb1077SAndy Ritger     // Inst-in-sys must only set up FRTS in SYSMEM. This includes FB broken.
107*90eb1077SAndy Ritger     if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_ALL_INST_IN_SYSMEM))
108*90eb1077SAndy Ritger     {
109*90eb1077SAndy Ritger         pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_VIDMEM, NV_TRUE);
110*90eb1077SAndy Ritger     }
111*90eb1077SAndy Ritger }
112*90eb1077SAndy Ritger 
113*90eb1077SAndy Ritger 
114*90eb1077SAndy Ritger /*!
115*90eb1077SAndy Ritger  * @brief FSP State Initialization.
116*90eb1077SAndy Ritger  *
117*90eb1077SAndy Ritger  * Initializes all software states including allocating the dbg memory surface
118*90eb1077SAndy Ritger  * and the initialization of FSP HAL layer.
119*90eb1077SAndy Ritger  *
120*90eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
121*90eb1077SAndy Ritger  * @param[in]  pKernelFsp FSP object pointer
122*90eb1077SAndy Ritger  *
123*90eb1077SAndy Ritger  * @return 'NV_OK' if state-initialization was successful.
124*90eb1077SAndy Ritger  * @return other   bubbles up errors from @ref kfspStateInitHal_HAL on failure
125*90eb1077SAndy Ritger  */
126*90eb1077SAndy Ritger NV_STATUS
127*90eb1077SAndy Ritger kfspStateInitUnlocked_IMPL
128*90eb1077SAndy Ritger (
129*90eb1077SAndy Ritger     OBJGPU    *pGpu,
130*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
131*90eb1077SAndy Ritger )
132*90eb1077SAndy Ritger {
133*90eb1077SAndy Ritger     return NV_OK;
134*90eb1077SAndy Ritger }
135*90eb1077SAndy Ritger 
136*90eb1077SAndy Ritger /*!
137*90eb1077SAndy Ritger  * @brief Destroy FSP state
138*90eb1077SAndy Ritger  *
139*90eb1077SAndy Ritger  * @param[in]  pGpu        GPU object pointer
140*90eb1077SAndy Ritger  * @param[in]  pKernelFsp  FSP object pointer
141*90eb1077SAndy Ritger  *
142*90eb1077SAndy Ritger  * @return 'NV_OK' if the FSP state was successfully destroyed
143*90eb1077SAndy Ritger  */
144*90eb1077SAndy Ritger void
145*90eb1077SAndy Ritger kfspStateDestroy_IMPL
146*90eb1077SAndy Ritger (
147*90eb1077SAndy Ritger     OBJGPU    *pGpu,
148*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
149*90eb1077SAndy Ritger )
150*90eb1077SAndy Ritger {
151*90eb1077SAndy Ritger     if (pKernelFsp->pCotPayload != NULL)
152*90eb1077SAndy Ritger     {
153*90eb1077SAndy Ritger         portMemFree(pKernelFsp->pCotPayload);
154*90eb1077SAndy Ritger         pKernelFsp->pCotPayload = NULL;
155*90eb1077SAndy Ritger     }
156*90eb1077SAndy Ritger 
157*90eb1077SAndy Ritger     if (pKernelFsp->pSysmemFrtsMemdesc != NULL)
158*90eb1077SAndy Ritger     {
159*90eb1077SAndy Ritger         memdescUnmap(pKernelFsp->pSysmemFrtsMemdesc, NV_TRUE, 0,
160*90eb1077SAndy Ritger             memdescGetKernelMapping(pKernelFsp->pSysmemFrtsMemdesc),
161*90eb1077SAndy Ritger             memdescGetKernelMappingPriv(pKernelFsp->pSysmemFrtsMemdesc));
162*90eb1077SAndy Ritger         memdescFree(pKernelFsp->pSysmemFrtsMemdesc);
163*90eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pSysmemFrtsMemdesc);
164*90eb1077SAndy Ritger         pKernelFsp->pSysmemFrtsMemdesc = NULL;
165*90eb1077SAndy Ritger     }
166*90eb1077SAndy Ritger 
167*90eb1077SAndy Ritger     if (pKernelFsp->pVidmemFrtsMemdesc != NULL)
168*90eb1077SAndy Ritger     {
169*90eb1077SAndy Ritger         memdescFree(pKernelFsp->pVidmemFrtsMemdesc);
170*90eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pVidmemFrtsMemdesc);
171*90eb1077SAndy Ritger         pKernelFsp->pVidmemFrtsMemdesc = NULL;
172*90eb1077SAndy Ritger     }
173*90eb1077SAndy Ritger 
174*90eb1077SAndy Ritger     if (pKernelFsp->pGspFmcMemdesc != NULL)
175*90eb1077SAndy Ritger     {
176*90eb1077SAndy Ritger         memdescFree(pKernelFsp->pGspFmcMemdesc);
177*90eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pGspFmcMemdesc);
178*90eb1077SAndy Ritger         pKernelFsp->pGspFmcMemdesc = NULL;
179*90eb1077SAndy Ritger     }
180*90eb1077SAndy Ritger 
181*90eb1077SAndy Ritger     if (pKernelFsp->pGspBootArgsMemdesc != NULL)
182*90eb1077SAndy Ritger     {
183*90eb1077SAndy Ritger         memdescFree(pKernelFsp->pGspBootArgsMemdesc);
184*90eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pGspBootArgsMemdesc);
185*90eb1077SAndy Ritger         pKernelFsp->pGspBootArgsMemdesc = NULL;
186*90eb1077SAndy Ritger     }
187*90eb1077SAndy Ritger 
188*90eb1077SAndy Ritger }
189*90eb1077SAndy Ritger 
190*90eb1077SAndy Ritger /*!
191*90eb1077SAndy Ritger  * @brief Override default behaviour of reset
192*90eb1077SAndy Ritger  *
193*90eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
194*90eb1077SAndy Ritger  * @param[in]  pKernelFsp FSP object pointer
195*90eb1077SAndy Ritger  *
196*90eb1077SAndy Ritger  * @return
197*90eb1077SAndy Ritger  */
198*90eb1077SAndy Ritger void
199*90eb1077SAndy Ritger kfspSecureReset_IMPL
200*90eb1077SAndy Ritger (
201*90eb1077SAndy Ritger     OBJGPU    *pGpu,
202*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
203*90eb1077SAndy Ritger )
204*90eb1077SAndy Ritger {
205*90eb1077SAndy Ritger     // Should not reset FSP
206*90eb1077SAndy Ritger     NV_PRINTF(LEVEL_ERROR, "FSP cannot be reset by CPU.\n");
207*90eb1077SAndy Ritger     NV_ASSERT(0);
208*90eb1077SAndy Ritger     return;
209*90eb1077SAndy Ritger }
210*90eb1077SAndy Ritger 
211*90eb1077SAndy Ritger 
212*90eb1077SAndy Ritger /*!
213*90eb1077SAndy Ritger  * @brief Check if FSP RM command queue is empty
214*90eb1077SAndy Ritger  *
215*90eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
216*90eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
217*90eb1077SAndy Ritger  *
218*90eb1077SAndy Ritger  * @return NV_TRUE if queue is empty, NV_FALSE otherwise
219*90eb1077SAndy Ritger  */
220*90eb1077SAndy Ritger NvBool
221*90eb1077SAndy Ritger kfspIsQueueEmpty_IMPL
222*90eb1077SAndy Ritger (
223*90eb1077SAndy Ritger     OBJGPU    *pGpu,
224*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
225*90eb1077SAndy Ritger )
226*90eb1077SAndy Ritger {
227*90eb1077SAndy Ritger     NvU32 cmdqHead, cmdqTail;
228*90eb1077SAndy Ritger 
229*90eb1077SAndy Ritger     kfspGetQueueHeadTail_HAL(pGpu, pKernelFsp, &cmdqHead, &cmdqTail);
230*90eb1077SAndy Ritger 
231*90eb1077SAndy Ritger     // FSP will set QUEUE_HEAD = TAIL after each packet is received
232*90eb1077SAndy Ritger     return (cmdqHead == cmdqTail);
233*90eb1077SAndy Ritger }
234*90eb1077SAndy Ritger 
235*90eb1077SAndy Ritger /*!
236*90eb1077SAndy Ritger  * @brief Wait for FSP RM command queue to be empty
237*90eb1077SAndy Ritger  *
238*90eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
239*90eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
240*90eb1077SAndy Ritger  *
241*90eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_TIMEOUT
242*90eb1077SAndy Ritger  */
243*90eb1077SAndy Ritger NV_STATUS
244*90eb1077SAndy Ritger kfspPollForQueueEmpty_IMPL
245*90eb1077SAndy Ritger (
246*90eb1077SAndy Ritger     OBJGPU    *pGpu,
247*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
248*90eb1077SAndy Ritger )
249*90eb1077SAndy Ritger {
250*90eb1077SAndy Ritger     RMTIMEOUT timeout;
251*90eb1077SAndy Ritger 
252*90eb1077SAndy Ritger     gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0);
253*90eb1077SAndy Ritger 
254*90eb1077SAndy Ritger     while (!kfspIsQueueEmpty(pGpu, pKernelFsp))
255*90eb1077SAndy Ritger     {
256*90eb1077SAndy Ritger         //
257*90eb1077SAndy Ritger         // For now we assume that any response from FSP before RM message send is complete
258*90eb1077SAndy Ritger         // indicates an error and we should abort.
259*90eb1077SAndy Ritger         //
260*90eb1077SAndy Ritger         if (!kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
261*90eb1077SAndy Ritger         {
262*90eb1077SAndy Ritger             kfspReadMessage(pGpu, pKernelFsp, NULL, 0);
263*90eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "Received error message from FSP while waiting for CMDQ to be empty.\n");
264*90eb1077SAndy Ritger             return NV_ERR_GENERIC;
265*90eb1077SAndy Ritger         }
266*90eb1077SAndy Ritger 
267*90eb1077SAndy Ritger         if (gpuCheckTimeout(pGpu, &timeout) == NV_ERR_TIMEOUT)
268*90eb1077SAndy Ritger         {
269*90eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "Timed out waiting for FSP command queue to be empty.\n");
270*90eb1077SAndy Ritger             return NV_ERR_TIMEOUT;
271*90eb1077SAndy Ritger         }
272*90eb1077SAndy Ritger         osSpinLoop();
273*90eb1077SAndy Ritger     }
274*90eb1077SAndy Ritger 
275*90eb1077SAndy Ritger     return NV_OK;
276*90eb1077SAndy Ritger }
277*90eb1077SAndy Ritger 
278*90eb1077SAndy Ritger /*!
279*90eb1077SAndy Ritger  * @brief Check if FSP RM message queue is empty
280*90eb1077SAndy Ritger  *
281*90eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
282*90eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
283*90eb1077SAndy Ritger  *
284*90eb1077SAndy Ritger  * @return NV_TRUE if queue is empty, NV_FALSE otherwise
285*90eb1077SAndy Ritger  */
286*90eb1077SAndy Ritger NvBool
287*90eb1077SAndy Ritger kfspIsMsgQueueEmpty_IMPL
288*90eb1077SAndy Ritger (
289*90eb1077SAndy Ritger     OBJGPU    *pGpu,
290*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
291*90eb1077SAndy Ritger )
292*90eb1077SAndy Ritger {
293*90eb1077SAndy Ritger     NvU32 msgqHead, msgqTail;
294*90eb1077SAndy Ritger 
295*90eb1077SAndy Ritger     kfspGetMsgQueueHeadTail_HAL(pGpu, pKernelFsp, &msgqHead, &msgqTail);
296*90eb1077SAndy Ritger     return (msgqHead == msgqTail);
297*90eb1077SAndy Ritger }
298*90eb1077SAndy Ritger 
299*90eb1077SAndy Ritger /*!
300*90eb1077SAndy Ritger  * @brief Poll for response from FSP via RM message queue
301*90eb1077SAndy Ritger  *
302*90eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
303*90eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
304*90eb1077SAndy Ritger  *
305*90eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_TIMEOUT
306*90eb1077SAndy Ritger  */
307*90eb1077SAndy Ritger NV_STATUS
308*90eb1077SAndy Ritger kfspPollForResponse_IMPL
309*90eb1077SAndy Ritger (
310*90eb1077SAndy Ritger     OBJGPU    *pGpu,
311*90eb1077SAndy Ritger     KernelFsp *pKernelFsp
312*90eb1077SAndy Ritger )
313*90eb1077SAndy Ritger {
314*90eb1077SAndy Ritger     RMTIMEOUT timeout;
315*90eb1077SAndy Ritger     NV_STATUS status = NV_OK;
316*90eb1077SAndy Ritger 
317*90eb1077SAndy Ritger     // Poll for message queue to wait for FSP's reply
318*90eb1077SAndy Ritger     gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, 0);
319*90eb1077SAndy Ritger     while (kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
320*90eb1077SAndy Ritger     {
321*90eb1077SAndy Ritger         if (gpuCheckTimeout(pGpu, &timeout) == NV_ERR_TIMEOUT)
322*90eb1077SAndy Ritger         {
323*90eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "FSP command timed out\n");
324*90eb1077SAndy Ritger             return NV_ERR_TIMEOUT;
325*90eb1077SAndy Ritger         }
326*90eb1077SAndy Ritger 
327*90eb1077SAndy Ritger         osSpinLoop();
328*90eb1077SAndy Ritger     }
329*90eb1077SAndy Ritger 
330*90eb1077SAndy Ritger     return status;
331*90eb1077SAndy Ritger }
332*90eb1077SAndy Ritger 
333*90eb1077SAndy Ritger /*!
334*90eb1077SAndy Ritger  * @brief Read and process message from FSP via RM message queue.
335*90eb1077SAndy Ritger  *
336*90eb1077SAndy Ritger  * Supports both single and multi-packet message. For multi-packet messages, this
337*90eb1077SAndy Ritger  * loops until all packets are received, polling at each iteration for the next
338*90eb1077SAndy Ritger  * packet to come in. If a buffer is provided, the message payload will be
339*90eb1077SAndy Ritger  * returned there.
340*90eb1077SAndy Ritger  *
341*90eb1077SAndy Ritger  * @note: For multi-packet messages, a buffer in which the message payload will
342*90eb1077SAndy Ritger  * be reconstructed must be provided.
343*90eb1077SAndy Ritger  *
344*90eb1077SAndy Ritger  * @param[in]     pGpu              OBJGPU pointer
345*90eb1077SAndy Ritger  * @param[in]     pKernelFsp        KernelFsp pointer
346*90eb1077SAndy Ritger  * @param[in/out] pPayloadBuffer    Buffer in which to return message payload
347*90eb1077SAndy Ritger  * @param[in]     payloadBufferSize Payload buffer size
348*90eb1077SAndy Ritger  *
349*90eb1077SAndy Ritger  * @return NV_OK, NV_ERR_INVALID_DATA, NV_ERR_INSUFFICIENT_RESOURCES, or errors
350*90eb1077SAndy Ritger  *         from functions called within
351*90eb1077SAndy Ritger  */
352*90eb1077SAndy Ritger static NV_STATUS
353*90eb1077SAndy Ritger kfspReadMessage
354*90eb1077SAndy Ritger (
355*90eb1077SAndy Ritger     OBJGPU    *pGpu,
356*90eb1077SAndy Ritger     KernelFsp *pKernelFsp,
357*90eb1077SAndy Ritger     NvU8      *pPayloadBuffer,
358*90eb1077SAndy Ritger     NvU32      payloadBufferSize
359*90eb1077SAndy Ritger )
360*90eb1077SAndy Ritger {
361*90eb1077SAndy Ritger     NvU8             *pPacketBuffer;
362*90eb1077SAndy Ritger     NV_STATUS         status;
363*90eb1077SAndy Ritger     NvU32             totalPayloadSize = 0;
364*90eb1077SAndy Ritger     MCTP_PACKET_STATE packetState = MCTP_PACKET_STATE_START;
365*90eb1077SAndy Ritger 
366*90eb1077SAndy Ritger     if (kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
367*90eb1077SAndy Ritger     {
368*90eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "Tried to read FSP response but MSG queue is empty\n");
369*90eb1077SAndy Ritger         return NV_OK;
370*90eb1077SAndy Ritger     }
371*90eb1077SAndy Ritger 
372*90eb1077SAndy Ritger     pPacketBuffer = portMemAllocNonPaged(kfspGetRmChannelSize_HAL(pGpu, pKernelFsp));
373*90eb1077SAndy Ritger 
374*90eb1077SAndy Ritger     while ((packetState != MCTP_PACKET_STATE_END) && (packetState != MCTP_PACKET_STATE_SINGLE_PACKET))
375*90eb1077SAndy Ritger     {
376*90eb1077SAndy Ritger         NvU32 msgqHead, msgqTail;
377*90eb1077SAndy Ritger         NvU32 packetSize;
378*90eb1077SAndy Ritger         NvU32 curPayloadSize;
379*90eb1077SAndy Ritger         NvU8  curHeaderSize;
380*90eb1077SAndy Ritger         NvU8  tag;
381*90eb1077SAndy Ritger 
382*90eb1077SAndy Ritger         // Wait for next packet
383*90eb1077SAndy Ritger         status = kfspPollForResponse(pGpu, pKernelFsp);
384*90eb1077SAndy Ritger         if (status != NV_OK)
385*90eb1077SAndy Ritger         {
386*90eb1077SAndy Ritger             goto done;
387*90eb1077SAndy Ritger         }
388*90eb1077SAndy Ritger 
389*90eb1077SAndy Ritger         kfspGetMsgQueueHeadTail_HAL(pGpu, pKernelFsp, &msgqHead, &msgqTail);
390*90eb1077SAndy Ritger 
391*90eb1077SAndy Ritger         // Tail points to last DWORD in packet, not DWORD immediately following it
392*90eb1077SAndy Ritger         packetSize = (msgqTail - msgqHead) + sizeof(NvU32);
393*90eb1077SAndy Ritger 
394*90eb1077SAndy Ritger         if ((packetSize < sizeof(NvU32)) ||
395*90eb1077SAndy Ritger             (packetSize > kfspGetRmChannelSize_HAL(pGpu, pKernelFsp)))
396*90eb1077SAndy Ritger         {
397*90eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "FSP response packet is invalid size: size=0x%x bytes\n", packetSize);
398*90eb1077SAndy Ritger             status = NV_ERR_INVALID_DATA;
399*90eb1077SAndy Ritger             goto done;
400*90eb1077SAndy Ritger         }
401*90eb1077SAndy Ritger 
402*90eb1077SAndy Ritger         kfspReadFromEmem_HAL(pGpu, pKernelFsp, pPacketBuffer, packetSize);
403*90eb1077SAndy Ritger 
404*90eb1077SAndy Ritger         status = kfspGetPacketInfo_HAL(pGpu, pKernelFsp, pPacketBuffer, packetSize, &packetState, &tag);
405*90eb1077SAndy Ritger         if (status != NV_OK)
406*90eb1077SAndy Ritger         {
407*90eb1077SAndy Ritger             goto done;
408*90eb1077SAndy Ritger         }
409*90eb1077SAndy Ritger 
410*90eb1077SAndy Ritger         if ((packetState == MCTP_PACKET_STATE_START) || (packetState == MCTP_PACKET_STATE_SINGLE_PACKET))
411*90eb1077SAndy Ritger         {
412*90eb1077SAndy Ritger             // Packet contains payload header
413*90eb1077SAndy Ritger             curHeaderSize = sizeof(MCTP_HEADER);
414*90eb1077SAndy Ritger         }
415*90eb1077SAndy Ritger         else
416*90eb1077SAndy Ritger         {
417*90eb1077SAndy Ritger             curHeaderSize = sizeof(NvU32);
418*90eb1077SAndy Ritger         }
419*90eb1077SAndy Ritger 
420*90eb1077SAndy Ritger         curPayloadSize = packetSize - curHeaderSize;
421*90eb1077SAndy Ritger 
422*90eb1077SAndy Ritger         if ((pPayloadBuffer == NULL) && (packetState != MCTP_PACKET_STATE_SINGLE_PACKET))
423*90eb1077SAndy Ritger         {
424*90eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "No buffer provided when receiving multi-packet message. Buffer needed to reconstruct message\n");
425*90eb1077SAndy Ritger             status = NV_ERR_INSUFFICIENT_RESOURCES;
426*90eb1077SAndy Ritger             goto done;
427*90eb1077SAndy Ritger         }
428*90eb1077SAndy Ritger 
429*90eb1077SAndy Ritger         if (pPayloadBuffer != NULL)
430*90eb1077SAndy Ritger         {
431*90eb1077SAndy Ritger             if (payloadBufferSize < (totalPayloadSize + curPayloadSize))
432*90eb1077SAndy Ritger             {
433*90eb1077SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Buffer provided for message payload too small. Payload size: 0x%x Buffer size: 0x%x\n",
434*90eb1077SAndy Ritger                           totalPayloadSize + curPayloadSize, payloadBufferSize);
435*90eb1077SAndy Ritger                 status = NV_ERR_INSUFFICIENT_RESOURCES;
436*90eb1077SAndy Ritger                 goto done;
437*90eb1077SAndy Ritger             }
438*90eb1077SAndy Ritger             portMemCopy(pPayloadBuffer + totalPayloadSize, payloadBufferSize - totalPayloadSize ,
439*90eb1077SAndy Ritger                         pPacketBuffer + curHeaderSize, curPayloadSize);
440*90eb1077SAndy Ritger         }
441*90eb1077SAndy Ritger         totalPayloadSize += curPayloadSize;
442*90eb1077SAndy Ritger 
443*90eb1077SAndy Ritger         // Set TAIL = HEAD to indicate CPU received message
444*90eb1077SAndy Ritger         kfspUpdateMsgQueueHeadTail_HAL(pGpu, pKernelFsp, msgqHead, msgqHead);
445*90eb1077SAndy Ritger     }
446*90eb1077SAndy Ritger 
447*90eb1077SAndy Ritger     NvU8 *pMessagePayload = (pPayloadBuffer == NULL) ? (pPacketBuffer + sizeof(MCTP_HEADER)) : pPayloadBuffer;
448*90eb1077SAndy Ritger 
449*90eb1077SAndy Ritger     status = kfspProcessNvdmMessage_HAL(pGpu, pKernelFsp, pMessagePayload, totalPayloadSize);
450*90eb1077SAndy Ritger 
451*90eb1077SAndy Ritger done:
452*90eb1077SAndy Ritger     portMemFree(pPacketBuffer);
453*90eb1077SAndy Ritger     return status;
454*90eb1077SAndy Ritger }
455*90eb1077SAndy Ritger 
456*90eb1077SAndy Ritger /*!
457*90eb1077SAndy Ritger  * @brief Send one MCTP packet to FSP via EMEM
458*90eb1077SAndy Ritger  *
459*90eb1077SAndy Ritger  * @param[in] pGpu          OBJGPU pointer
460*90eb1077SAndy Ritger  * @param[in] pKernelFsp    KernelFsp pointer
461*90eb1077SAndy Ritger  * @param[in] pPacket       MCTP packet
462*90eb1077SAndy Ritger  * @param[in] packetSize    MCTP packet size in bytes
463*90eb1077SAndy Ritger  *
464*90eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_INSUFFICIENT_RESOURCES
465*90eb1077SAndy Ritger  */
466*90eb1077SAndy Ritger NV_STATUS
467*90eb1077SAndy Ritger kfspSendPacket_IMPL
468*90eb1077SAndy Ritger (
469*90eb1077SAndy Ritger     OBJGPU      *pGpu,
470*90eb1077SAndy Ritger     KernelFsp   *pKernelFsp,
471*90eb1077SAndy Ritger     NvU8        *pPacket,
472*90eb1077SAndy Ritger     NvU32        packetSize
473*90eb1077SAndy Ritger )
474*90eb1077SAndy Ritger {
475*90eb1077SAndy Ritger     NvU32 paddedSize;
476*90eb1077SAndy Ritger     NvU8 *pBuffer = NULL;
477*90eb1077SAndy Ritger     NV_STATUS status = NV_OK;
478*90eb1077SAndy Ritger 
479*90eb1077SAndy Ritger     // Check that queue is ready to receive data
480*90eb1077SAndy Ritger     status = kfspPollForQueueEmpty(pGpu, pKernelFsp);
481*90eb1077SAndy Ritger     if (status != NV_OK)
482*90eb1077SAndy Ritger     {
483*90eb1077SAndy Ritger         return NV_ERR_INSUFFICIENT_RESOURCES;
484*90eb1077SAndy Ritger     }
485*90eb1077SAndy Ritger 
486*90eb1077SAndy Ritger     // Pad to align size to 4-bytes boundary since EMEMC increments by DWORDS
487*90eb1077SAndy Ritger     paddedSize = NV_ALIGN_UP(packetSize, sizeof(NvU32));
488*90eb1077SAndy Ritger     pBuffer = portMemAllocNonPaged(paddedSize);
489*90eb1077SAndy Ritger     portMemSet(pBuffer, 0, paddedSize);
490*90eb1077SAndy Ritger     portMemCopy(pBuffer, paddedSize, pPacket, paddedSize);
491*90eb1077SAndy Ritger 
492*90eb1077SAndy Ritger     kfspWriteToEmem_HAL(pGpu, pKernelFsp, pBuffer, paddedSize);
493*90eb1077SAndy Ritger 
494*90eb1077SAndy Ritger     // Update HEAD and TAIL with new EMEM offset; RM always starts at offset 0.
495*90eb1077SAndy Ritger     kfspUpdateQueueHeadTail_HAL(pGpu, pKernelFsp, 0, paddedSize - sizeof(NvU32));
496*90eb1077SAndy Ritger 
497*90eb1077SAndy Ritger     portMemFree(pBuffer);
498*90eb1077SAndy Ritger     return status;
499*90eb1077SAndy Ritger }
500*90eb1077SAndy Ritger 
501*90eb1077SAndy Ritger /*!
502*90eb1077SAndy Ritger  * @brief Send a MCTP message to FSP via EMEM, and read response
503*90eb1077SAndy Ritger  *
504*90eb1077SAndy Ritger  *
505*90eb1077SAndy Ritger  * Response payload buffer is optional if response fits in a single packet.
506*90eb1077SAndy Ritger  *
507*90eb1077SAndy Ritger  * @param[in] pGpu               OBJGPU pointer
508*90eb1077SAndy Ritger  * @param[in] pKernelFsp         KernelFsp pointer
509*90eb1077SAndy Ritger  * @param[in] pPayload           Pointer to message payload
510*90eb1077SAndy Ritger  * @param[in] size               Message payload size
511*90eb1077SAndy Ritger  * @param[in] nvdmType           NVDM type of message being sent
512*90eb1077SAndy Ritger  * @param[in] pResponsePayload   Buffer in which to return response payload
513*90eb1077SAndy Ritger  * @param[in] responseBufferSize Response payload buffer size
514*90eb1077SAndy Ritger  *
515*90eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_*
516*90eb1077SAndy Ritger  */
517*90eb1077SAndy Ritger NV_STATUS
518*90eb1077SAndy Ritger kfspSendAndReadMessage_IMPL
519*90eb1077SAndy Ritger (
520*90eb1077SAndy Ritger     OBJGPU    *pGpu,
521*90eb1077SAndy Ritger     KernelFsp *pKernelFsp,
522*90eb1077SAndy Ritger     NvU8      *pPayload,
523*90eb1077SAndy Ritger     NvU32      size,
524*90eb1077SAndy Ritger     NvU32      nvdmType,
525*90eb1077SAndy Ritger     NvU8      *pResponsePayload,
526*90eb1077SAndy Ritger     NvU32      responseBufferSize
527*90eb1077SAndy Ritger )
528*90eb1077SAndy Ritger {
529*90eb1077SAndy Ritger     NvU32 dataSent, dataRemaining;
530*90eb1077SAndy Ritger     NvU32 packetPayloadCapacity;
531*90eb1077SAndy Ritger     NvU32 curPayloadSize;
532*90eb1077SAndy Ritger     NvU32 headerSize;
533*90eb1077SAndy Ritger     NvU32 fspEmemRmChannelSize;
534*90eb1077SAndy Ritger     NvBool bSinglePacket;
535*90eb1077SAndy Ritger     NV_STATUS status;
536*90eb1077SAndy Ritger     NvU8 *pBuffer = NULL;
537*90eb1077SAndy Ritger     NvU8  seq = 0;
538*90eb1077SAndy Ritger     NvU8  seid = 0;
539*90eb1077SAndy Ritger 
540*90eb1077SAndy Ritger     // Allocate buffer of same size as channel
541*90eb1077SAndy Ritger     fspEmemRmChannelSize = kfspGetRmChannelSize_HAL(pGpu, pKernelFsp);
542*90eb1077SAndy Ritger     pBuffer = portMemAllocNonPaged(fspEmemRmChannelSize);
543*90eb1077SAndy Ritger     portMemSet(pBuffer, 0, fspEmemRmChannelSize);
544*90eb1077SAndy Ritger 
545*90eb1077SAndy Ritger     //
546*90eb1077SAndy Ritger     // Check if message will fit in single packet
547*90eb1077SAndy Ritger     // We lose 2 DWORDS to MCTP and NVDM headers
548*90eb1077SAndy Ritger     //
549*90eb1077SAndy Ritger     headerSize = 2 * sizeof(NvU32);
550*90eb1077SAndy Ritger     packetPayloadCapacity = fspEmemRmChannelSize - headerSize;
551*90eb1077SAndy Ritger     bSinglePacket = (size <= packetPayloadCapacity);
552*90eb1077SAndy Ritger 
553*90eb1077SAndy Ritger     // First packet
554*90eb1077SAndy Ritger     seid = kfspNvdmToSeid_HAL(pGpu, pKernelFsp, nvdmType);
555*90eb1077SAndy Ritger     ((NvU32 *)pBuffer)[0] = kfspCreateMctpHeader_HAL(pGpu, pKernelFsp, 1, (NvU8)bSinglePacket, seid, seq); // SOM=1,EOM=?,SEID,SEQ=0
556*90eb1077SAndy Ritger     ((NvU32 *)pBuffer)[1] = kfspCreateNvdmHeader_HAL(pGpu, pKernelFsp, nvdmType);
557*90eb1077SAndy Ritger 
558*90eb1077SAndy Ritger     curPayloadSize = NV_MIN(size, packetPayloadCapacity);
559*90eb1077SAndy Ritger     portMemCopy(pBuffer + headerSize, packetPayloadCapacity, pPayload, curPayloadSize);
560*90eb1077SAndy Ritger 
561*90eb1077SAndy Ritger     status = kfspSendPacket(pGpu, pKernelFsp, pBuffer, curPayloadSize + headerSize);
562*90eb1077SAndy Ritger     if (status != NV_OK)
563*90eb1077SAndy Ritger     {
564*90eb1077SAndy Ritger         goto failed;
565*90eb1077SAndy Ritger     }
566*90eb1077SAndy Ritger 
567*90eb1077SAndy Ritger     if (!bSinglePacket)
568*90eb1077SAndy Ritger     {
569*90eb1077SAndy Ritger         // Multi packet case
570*90eb1077SAndy Ritger         dataSent = curPayloadSize;
571*90eb1077SAndy Ritger         dataRemaining = size - dataSent;
572*90eb1077SAndy Ritger         headerSize = sizeof(NvU32); // No longer need NVDM header
573*90eb1077SAndy Ritger         packetPayloadCapacity = fspEmemRmChannelSize - headerSize;
574*90eb1077SAndy Ritger 
575*90eb1077SAndy Ritger         while (dataRemaining > 0)
576*90eb1077SAndy Ritger         {
577*90eb1077SAndy Ritger             NvBool bLastPacket = (dataRemaining <= packetPayloadCapacity);
578*90eb1077SAndy Ritger             curPayloadSize = (bLastPacket) ? dataRemaining : packetPayloadCapacity;
579*90eb1077SAndy Ritger 
580*90eb1077SAndy Ritger             portMemSet(pBuffer, 0, fspEmemRmChannelSize);
581*90eb1077SAndy Ritger             ((NvU32 *)pBuffer)[0] = kfspCreateMctpHeader_HAL(pGpu, pKernelFsp, 0, (NvU8)bLastPacket, seid, (++seq) % 4);
582*90eb1077SAndy Ritger 
583*90eb1077SAndy Ritger             portMemCopy(pBuffer + headerSize, packetPayloadCapacity,
584*90eb1077SAndy Ritger                         pPayload + dataSent, curPayloadSize);
585*90eb1077SAndy Ritger 
586*90eb1077SAndy Ritger             status = kfspSendPacket(pGpu, pKernelFsp, pBuffer, curPayloadSize + headerSize);
587*90eb1077SAndy Ritger             if (status != NV_OK)
588*90eb1077SAndy Ritger             {
589*90eb1077SAndy Ritger                 goto failed;
590*90eb1077SAndy Ritger             }
591*90eb1077SAndy Ritger 
592*90eb1077SAndy Ritger             dataSent += curPayloadSize;
593*90eb1077SAndy Ritger             dataRemaining -= curPayloadSize;
594*90eb1077SAndy Ritger         }
595*90eb1077SAndy Ritger 
596*90eb1077SAndy Ritger     }
597*90eb1077SAndy Ritger 
598*90eb1077SAndy Ritger     status = kfspPollForResponse(pGpu, pKernelFsp);
599*90eb1077SAndy Ritger     if (status != NV_OK)
600*90eb1077SAndy Ritger     {
601*90eb1077SAndy Ritger         goto failed;
602*90eb1077SAndy Ritger     }
603*90eb1077SAndy Ritger     status = kfspReadMessage(pGpu, pKernelFsp, pResponsePayload, responseBufferSize);
604*90eb1077SAndy Ritger 
605*90eb1077SAndy Ritger failed:
606*90eb1077SAndy Ritger     portMemFree(pBuffer);
607*90eb1077SAndy Ritger 
608*90eb1077SAndy Ritger     return status;
609*90eb1077SAndy Ritger }
610