190eb1077SAndy Ritger /*
2b5bf85a8SAndy Ritger  * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
390eb1077SAndy Ritger  * SPDX-License-Identifier: MIT
490eb1077SAndy Ritger  *
590eb1077SAndy Ritger  * Permission is hereby granted, free of charge, to any person obtaining a
690eb1077SAndy Ritger  * copy of this software and associated documentation files (the "Software"),
790eb1077SAndy Ritger  * to deal in the Software without restriction, including without limitation
890eb1077SAndy Ritger  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
990eb1077SAndy Ritger  * and/or sell copies of the Software, and to permit persons to whom the
1090eb1077SAndy Ritger  * Software is furnished to do so, subject to the following conditions:
1190eb1077SAndy Ritger  *
1290eb1077SAndy Ritger  * The above copyright notice and this permission notice shall be included in
1390eb1077SAndy Ritger  * all copies or substantial portions of the Software.
1490eb1077SAndy Ritger  *
1590eb1077SAndy Ritger  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1690eb1077SAndy Ritger  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1790eb1077SAndy Ritger  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
1890eb1077SAndy Ritger  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
1990eb1077SAndy Ritger  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2090eb1077SAndy Ritger  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
2190eb1077SAndy Ritger  * DEALINGS IN THE SOFTWARE.
2290eb1077SAndy Ritger  */
2390eb1077SAndy Ritger 
2490eb1077SAndy Ritger  /*!
2590eb1077SAndy Ritger   *
2690eb1077SAndy Ritger   * @file   kern_fsp.c
2790eb1077SAndy Ritger   * @brief  Provides all kernel side interfaces for tracking the FSP state,
2890eb1077SAndy Ritger   *         submitting commands and parsing replies needed from the CPU.
2990eb1077SAndy Ritger   */
3090eb1077SAndy Ritger #include "gpu/gpu.h"
3190eb1077SAndy Ritger #include "gpu/fsp/kern_fsp.h"
3290eb1077SAndy Ritger #include "nvrm_registry.h"
3390eb1077SAndy Ritger 
3490eb1077SAndy Ritger #if RMCFG_MODULE_ENABLED (GSP)
3590eb1077SAndy Ritger #include "gpu/gsp/gsp.h"
3690eb1077SAndy Ritger #include "objflcnable.h"
3790eb1077SAndy Ritger #endif
3890eb1077SAndy Ritger 
3990eb1077SAndy Ritger /*!
4090eb1077SAndy Ritger * Local object related functions
4190eb1077SAndy Ritger */
4290eb1077SAndy Ritger static void kfspInitRegistryOverrides(OBJGPU *, KernelFsp *);
4390eb1077SAndy Ritger 
4490eb1077SAndy Ritger static NV_STATUS kfspReadMessage(OBJGPU *pGpu, KernelFsp *pKernelFsp, NvU8 *pPayloadBuffer, NvU32 payloadBufferSize);
4590eb1077SAndy Ritger 
4690eb1077SAndy Ritger NV_STATUS
kfspConstructEngine_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp,ENGDESCRIPTOR engDesc)4790eb1077SAndy Ritger kfspConstructEngine_IMPL(OBJGPU *pGpu, KernelFsp *pKernelFsp, ENGDESCRIPTOR engDesc)
4890eb1077SAndy Ritger {
4990eb1077SAndy Ritger 
5090eb1077SAndy Ritger     // Initialize based on registry keys
5190eb1077SAndy Ritger     kfspInitRegistryOverrides(pGpu, pKernelFsp);
5290eb1077SAndy Ritger     if (pKernelFsp->getProperty(pKernelFsp, PDB_PROP_KFSP_IS_MISSING))
5390eb1077SAndy Ritger     {
5490eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "KernelFsp is disabled\n");
5590eb1077SAndy Ritger         return NV_ERR_OBJECT_NOT_FOUND;
5690eb1077SAndy Ritger     }
5790eb1077SAndy Ritger     return NV_OK;
5890eb1077SAndy Ritger }
5990eb1077SAndy Ritger 
6090eb1077SAndy Ritger /*!
6190eb1077SAndy Ritger  * Initialize all registry overrides for this object
6290eb1077SAndy Ritger  *
6390eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
6490eb1077SAndy Ritger  * @param[in]  pKernelFsp KernelFsp object pointer
6590eb1077SAndy Ritger  */
6690eb1077SAndy Ritger static void
kfspInitRegistryOverrides(OBJGPU * pGpu,KernelFsp * pKernelFsp)6790eb1077SAndy Ritger kfspInitRegistryOverrides
6890eb1077SAndy Ritger (
6990eb1077SAndy Ritger     OBJGPU    *pGpu,
7090eb1077SAndy Ritger     KernelFsp *pKernelFsp
7190eb1077SAndy Ritger )
7290eb1077SAndy Ritger {
7390eb1077SAndy Ritger     NvU32 data = 0;
7490eb1077SAndy Ritger 
7590eb1077SAndy Ritger     if (((osReadRegistryDword(pGpu, NV_REG_STR_RM_DISABLE_FSP, &data) == NV_OK) &&
7690eb1077SAndy Ritger         (data == NV_REG_STR_RM_DISABLE_FSP_YES) && IS_EMULATION(pGpu)) ||
77b5bf85a8SAndy Ritger         IS_FMODEL(pGpu) || IS_RTLSIM(pGpu))
7890eb1077SAndy Ritger     {
7990eb1077SAndy Ritger         //
8090eb1077SAndy Ritger         // Force disable FSP engine, used only on emulation because some
8190eb1077SAndy Ritger         // emulation netlists stub out FSP but leave the engine in PTOP
8290eb1077SAndy Ritger         //
8390eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "FSP disabled due to regkey override.\n");
8490eb1077SAndy Ritger         pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_IS_MISSING, NV_TRUE);
8590eb1077SAndy Ritger     }
8690eb1077SAndy Ritger 
8790eb1077SAndy Ritger     if (osReadRegistryDword(pGpu, NV_REG_STR_RM_DISABLE_COT_CMD, &data) == NV_OK)
8890eb1077SAndy Ritger     {
8990eb1077SAndy Ritger         // Assume non-zero value only has NV_REG_STR_RM_DISABLE_COT_CMD_YES
9090eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_FRTS_SYSMEM))
9190eb1077SAndy Ritger         {
9290eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_SYSMEM, NV_TRUE);
9390eb1077SAndy Ritger         }
9490eb1077SAndy Ritger 
9590eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_FRTS_VIDMEM))
9690eb1077SAndy Ritger         {
9790eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_VIDMEM, NV_TRUE);
9890eb1077SAndy Ritger         }
9990eb1077SAndy Ritger 
10090eb1077SAndy Ritger         if (data & DRF_SHIFTMASK(NV_REG_STR_RM_DISABLE_COT_CMD_GSPFMC))
10190eb1077SAndy Ritger         {
10290eb1077SAndy Ritger             pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_GSPFMC, NV_TRUE);
10390eb1077SAndy Ritger         }
10490eb1077SAndy Ritger     }
10590eb1077SAndy Ritger 
106b5bf85a8SAndy Ritger     // Inst-in-sys must only set up FRTS in SYSMEM. This includes FB broken and cache only.
107b5bf85a8SAndy Ritger     if (pGpu->getProperty(pGpu, PDB_PROP_GPU_IS_ALL_INST_IN_SYSMEM) ||
108b5bf85a8SAndy Ritger         pGpu->getProperty(pGpu, PDB_PROP_GPU_BROKEN_FB) ||
109b5bf85a8SAndy Ritger         gpuIsCacheOnlyModeEnabled(pGpu))
11090eb1077SAndy Ritger     {
11190eb1077SAndy Ritger         pKernelFsp->setProperty(pKernelFsp, PDB_PROP_KFSP_DISABLE_FRTS_VIDMEM, NV_TRUE);
11290eb1077SAndy Ritger     }
11390eb1077SAndy Ritger }
11490eb1077SAndy Ritger 
11590eb1077SAndy Ritger 
11690eb1077SAndy Ritger /*!
11790eb1077SAndy Ritger  * @brief FSP State Initialization.
11890eb1077SAndy Ritger  *
11990eb1077SAndy Ritger  * Initializes all software states including allocating the dbg memory surface
12090eb1077SAndy Ritger  * and the initialization of FSP HAL layer.
12190eb1077SAndy Ritger  *
12290eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
12390eb1077SAndy Ritger  * @param[in]  pKernelFsp FSP object pointer
12490eb1077SAndy Ritger  *
12590eb1077SAndy Ritger  * @return 'NV_OK' if state-initialization was successful.
12690eb1077SAndy Ritger  * @return other   bubbles up errors from @ref kfspStateInitHal_HAL on failure
12790eb1077SAndy Ritger  */
12890eb1077SAndy Ritger NV_STATUS
kfspStateInitUnlocked_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)12990eb1077SAndy Ritger kfspStateInitUnlocked_IMPL
13090eb1077SAndy Ritger (
13190eb1077SAndy Ritger     OBJGPU    *pGpu,
13290eb1077SAndy Ritger     KernelFsp *pKernelFsp
13390eb1077SAndy Ritger )
13490eb1077SAndy Ritger {
13590eb1077SAndy Ritger     return NV_OK;
13690eb1077SAndy Ritger }
13790eb1077SAndy Ritger 
13890eb1077SAndy Ritger /*!
13991676d66SBernhard Stoeckner  * @brief Clean up objects used when sending GSP-FMC and FRTS info to FSP
14090eb1077SAndy Ritger  *
14190eb1077SAndy Ritger  * @param[in]  pGpu        GPU object pointer
14290eb1077SAndy Ritger  * @param[in]  pKernelFsp  FSP object pointer
14390eb1077SAndy Ritger  */
14490eb1077SAndy Ritger void
kfspCleanupBootState_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)14591676d66SBernhard Stoeckner kfspCleanupBootState_IMPL
14690eb1077SAndy Ritger (
14790eb1077SAndy Ritger     OBJGPU    *pGpu,
14890eb1077SAndy Ritger     KernelFsp *pKernelFsp
14990eb1077SAndy Ritger )
15090eb1077SAndy Ritger {
15190eb1077SAndy Ritger     portMemFree(pKernelFsp->pCotPayload);
15290eb1077SAndy Ritger     pKernelFsp->pCotPayload = NULL;
15390eb1077SAndy Ritger 
15490eb1077SAndy Ritger     if (pKernelFsp->pSysmemFrtsMemdesc != NULL)
15590eb1077SAndy Ritger     {
15691676d66SBernhard Stoeckner         kfspFrtsSysmemLocationClear_HAL(pGpu, pKernelFsp);
15790eb1077SAndy Ritger         memdescUnmap(pKernelFsp->pSysmemFrtsMemdesc, NV_TRUE, 0,
15890eb1077SAndy Ritger             memdescGetKernelMapping(pKernelFsp->pSysmemFrtsMemdesc),
15990eb1077SAndy Ritger             memdescGetKernelMappingPriv(pKernelFsp->pSysmemFrtsMemdesc));
16090eb1077SAndy Ritger         memdescFree(pKernelFsp->pSysmemFrtsMemdesc);
16190eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pSysmemFrtsMemdesc);
16290eb1077SAndy Ritger         pKernelFsp->pSysmemFrtsMemdesc = NULL;
16390eb1077SAndy Ritger     }
16490eb1077SAndy Ritger 
16590eb1077SAndy Ritger     if (pKernelFsp->pGspFmcMemdesc != NULL)
16690eb1077SAndy Ritger     {
16790eb1077SAndy Ritger         memdescFree(pKernelFsp->pGspFmcMemdesc);
16890eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pGspFmcMemdesc);
16990eb1077SAndy Ritger         pKernelFsp->pGspFmcMemdesc = NULL;
17090eb1077SAndy Ritger     }
17190eb1077SAndy Ritger 
17290eb1077SAndy Ritger     if (pKernelFsp->pGspBootArgsMemdesc != NULL)
17390eb1077SAndy Ritger     {
17490eb1077SAndy Ritger         memdescFree(pKernelFsp->pGspBootArgsMemdesc);
17590eb1077SAndy Ritger         memdescDestroy(pKernelFsp->pGspBootArgsMemdesc);
17690eb1077SAndy Ritger         pKernelFsp->pGspBootArgsMemdesc = NULL;
17790eb1077SAndy Ritger     }
17890eb1077SAndy Ritger 
17990eb1077SAndy Ritger }
18090eb1077SAndy Ritger 
18190eb1077SAndy Ritger /*!
18291676d66SBernhard Stoeckner  * @brief Destroy FSP state
18391676d66SBernhard Stoeckner  *
18491676d66SBernhard Stoeckner  * @param[in]  pGpu        GPU object pointer
18591676d66SBernhard Stoeckner  * @param[in]  pKernelFsp  FSP object pointer
18691676d66SBernhard Stoeckner  */
18791676d66SBernhard Stoeckner void
kfspStateDestroy_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)18891676d66SBernhard Stoeckner kfspStateDestroy_IMPL
18991676d66SBernhard Stoeckner (
19091676d66SBernhard Stoeckner     OBJGPU    *pGpu,
19191676d66SBernhard Stoeckner     KernelFsp *pKernelFsp
19291676d66SBernhard Stoeckner )
19391676d66SBernhard Stoeckner {
19491676d66SBernhard Stoeckner     kfspCleanupBootState(pGpu, pKernelFsp);
19591676d66SBernhard Stoeckner 
19691676d66SBernhard Stoeckner     if (pKernelFsp->pVidmemFrtsMemdesc != NULL)
19791676d66SBernhard Stoeckner     {
19891676d66SBernhard Stoeckner         memdescFree(pKernelFsp->pVidmemFrtsMemdesc);
19991676d66SBernhard Stoeckner         memdescDestroy(pKernelFsp->pVidmemFrtsMemdesc);
20091676d66SBernhard Stoeckner         pKernelFsp->pVidmemFrtsMemdesc = NULL;
20191676d66SBernhard Stoeckner     }
20291676d66SBernhard Stoeckner }
20391676d66SBernhard Stoeckner 
20491676d66SBernhard Stoeckner /*!
20590eb1077SAndy Ritger  * @brief Override default behaviour of reset
20690eb1077SAndy Ritger  *
20790eb1077SAndy Ritger  * @param[in]  pGpu       GPU object pointer
20890eb1077SAndy Ritger  * @param[in]  pKernelFsp FSP object pointer
20990eb1077SAndy Ritger  */
21090eb1077SAndy Ritger void
kfspSecureReset_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)21190eb1077SAndy Ritger kfspSecureReset_IMPL
21290eb1077SAndy Ritger (
21390eb1077SAndy Ritger     OBJGPU    *pGpu,
21490eb1077SAndy Ritger     KernelFsp *pKernelFsp
21590eb1077SAndy Ritger )
21690eb1077SAndy Ritger {
21790eb1077SAndy Ritger     // Should not reset FSP
21890eb1077SAndy Ritger     NV_PRINTF(LEVEL_ERROR, "FSP cannot be reset by CPU.\n");
21990eb1077SAndy Ritger     NV_ASSERT(0);
22090eb1077SAndy Ritger     return;
22190eb1077SAndy Ritger }
22290eb1077SAndy Ritger 
22390eb1077SAndy Ritger 
22490eb1077SAndy Ritger /*!
22590eb1077SAndy Ritger  * @brief Check if FSP RM command queue is empty
22690eb1077SAndy Ritger  *
22790eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
22890eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
22990eb1077SAndy Ritger  *
23090eb1077SAndy Ritger  * @return NV_TRUE if queue is empty, NV_FALSE otherwise
23190eb1077SAndy Ritger  */
23290eb1077SAndy Ritger NvBool
kfspIsQueueEmpty_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)23390eb1077SAndy Ritger kfspIsQueueEmpty_IMPL
23490eb1077SAndy Ritger (
23590eb1077SAndy Ritger     OBJGPU    *pGpu,
23690eb1077SAndy Ritger     KernelFsp *pKernelFsp
23790eb1077SAndy Ritger )
23890eb1077SAndy Ritger {
23990eb1077SAndy Ritger     NvU32 cmdqHead, cmdqTail;
24090eb1077SAndy Ritger 
24190eb1077SAndy Ritger     kfspGetQueueHeadTail_HAL(pGpu, pKernelFsp, &cmdqHead, &cmdqTail);
24290eb1077SAndy Ritger 
24390eb1077SAndy Ritger     // FSP will set QUEUE_HEAD = TAIL after each packet is received
24490eb1077SAndy Ritger     return (cmdqHead == cmdqTail);
24590eb1077SAndy Ritger }
24690eb1077SAndy Ritger 
24790eb1077SAndy Ritger /*!
24890eb1077SAndy Ritger  * @brief Wait for FSP RM command queue to be empty
24990eb1077SAndy Ritger  *
25090eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
25190eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
25290eb1077SAndy Ritger  *
25390eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_TIMEOUT
25490eb1077SAndy Ritger  */
25590eb1077SAndy Ritger NV_STATUS
kfspPollForQueueEmpty_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)25690eb1077SAndy Ritger kfspPollForQueueEmpty_IMPL
25790eb1077SAndy Ritger (
25890eb1077SAndy Ritger     OBJGPU    *pGpu,
25990eb1077SAndy Ritger     KernelFsp *pKernelFsp
26090eb1077SAndy Ritger )
26190eb1077SAndy Ritger {
262*3bf16b89SBernhard Stoeckner     NV_STATUS status = NV_OK;
26390eb1077SAndy Ritger     RMTIMEOUT timeout;
26490eb1077SAndy Ritger 
265*3bf16b89SBernhard Stoeckner     gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout,
266*3bf16b89SBernhard Stoeckner         GPU_TIMEOUT_FLAGS_OSTIMER |
267*3bf16b89SBernhard Stoeckner         GPU_TIMEOUT_FLAGS_BYPASS_THREAD_STATE);
26890eb1077SAndy Ritger 
26990eb1077SAndy Ritger     while (!kfspIsQueueEmpty(pGpu, pKernelFsp))
27090eb1077SAndy Ritger     {
27190eb1077SAndy Ritger         //
272*3bf16b89SBernhard Stoeckner         // For now we assume that any response from FSP before RM message
273*3bf16b89SBernhard Stoeckner         // send is complete indicates an error and we should abort.
274*3bf16b89SBernhard Stoeckner         //
275*3bf16b89SBernhard Stoeckner         // Ongoing dicussion on usefullness of this check. Bug to be filed.
27690eb1077SAndy Ritger         //
27790eb1077SAndy Ritger         if (!kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
27890eb1077SAndy Ritger         {
27990eb1077SAndy Ritger             kfspReadMessage(pGpu, pKernelFsp, NULL, 0);
280*3bf16b89SBernhard Stoeckner             NV_PRINTF(LEVEL_ERROR,
281*3bf16b89SBernhard Stoeckner                 "Received error message from FSP while waiting for CMDQ to be empty.\n");
282*3bf16b89SBernhard Stoeckner             status = NV_ERR_GENERIC;
283*3bf16b89SBernhard Stoeckner             break;
28490eb1077SAndy Ritger         }
28590eb1077SAndy Ritger 
28690eb1077SAndy Ritger         osSpinLoop();
287*3bf16b89SBernhard Stoeckner 
288*3bf16b89SBernhard Stoeckner         status = gpuCheckTimeout(pGpu, &timeout);
289*3bf16b89SBernhard Stoeckner         if (status != NV_OK)
290*3bf16b89SBernhard Stoeckner         {
291*3bf16b89SBernhard Stoeckner             if ((status == NV_ERR_TIMEOUT) &&
292*3bf16b89SBernhard Stoeckner                 kfspIsQueueEmpty(pGpu, pKernelFsp))
293*3bf16b89SBernhard Stoeckner             {
294*3bf16b89SBernhard Stoeckner                 status = NV_OK;
295*3bf16b89SBernhard Stoeckner             }
296*3bf16b89SBernhard Stoeckner             else
297*3bf16b89SBernhard Stoeckner             {
298*3bf16b89SBernhard Stoeckner                 NV_PRINTF(LEVEL_ERROR,
299*3bf16b89SBernhard Stoeckner                     "Timed out waiting for FSP command queue to be empty.\n");
300*3bf16b89SBernhard Stoeckner             }
301*3bf16b89SBernhard Stoeckner             break;
302*3bf16b89SBernhard Stoeckner         }
30390eb1077SAndy Ritger     }
30490eb1077SAndy Ritger 
305*3bf16b89SBernhard Stoeckner     return status;
30690eb1077SAndy Ritger }
30790eb1077SAndy Ritger 
30890eb1077SAndy Ritger /*!
30990eb1077SAndy Ritger  * @brief Check if FSP RM message queue is empty
31090eb1077SAndy Ritger  *
31190eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
31290eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
31390eb1077SAndy Ritger  *
31490eb1077SAndy Ritger  * @return NV_TRUE if queue is empty, NV_FALSE otherwise
31590eb1077SAndy Ritger  */
31690eb1077SAndy Ritger NvBool
kfspIsMsgQueueEmpty_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)31790eb1077SAndy Ritger kfspIsMsgQueueEmpty_IMPL
31890eb1077SAndy Ritger (
31990eb1077SAndy Ritger     OBJGPU    *pGpu,
32090eb1077SAndy Ritger     KernelFsp *pKernelFsp
32190eb1077SAndy Ritger )
32290eb1077SAndy Ritger {
32390eb1077SAndy Ritger     NvU32 msgqHead, msgqTail;
32490eb1077SAndy Ritger 
32590eb1077SAndy Ritger     kfspGetMsgQueueHeadTail_HAL(pGpu, pKernelFsp, &msgqHead, &msgqTail);
32690eb1077SAndy Ritger     return (msgqHead == msgqTail);
32790eb1077SAndy Ritger }
32890eb1077SAndy Ritger 
32990eb1077SAndy Ritger /*!
33090eb1077SAndy Ritger  * @brief Poll for response from FSP via RM message queue
33190eb1077SAndy Ritger  *
33290eb1077SAndy Ritger  * @param[in] pGpu       OBJGPU pointer
33390eb1077SAndy Ritger  * @param[in] pKernelFsp KernelFsp pointer
33490eb1077SAndy Ritger  *
33590eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_TIMEOUT
33690eb1077SAndy Ritger  */
33790eb1077SAndy Ritger NV_STATUS
kfspPollForResponse_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp)33890eb1077SAndy Ritger kfspPollForResponse_IMPL
33990eb1077SAndy Ritger (
34090eb1077SAndy Ritger     OBJGPU    *pGpu,
34190eb1077SAndy Ritger     KernelFsp *pKernelFsp
34290eb1077SAndy Ritger )
34390eb1077SAndy Ritger {
34490eb1077SAndy Ritger     RMTIMEOUT timeout;
34590eb1077SAndy Ritger     NV_STATUS status = NV_OK;
34690eb1077SAndy Ritger 
34790eb1077SAndy Ritger     // Poll for message queue to wait for FSP's reply
348758b4ee8SAndy Ritger     gpuSetTimeout(pGpu, GPU_TIMEOUT_DEFAULT, &timeout, GPU_TIMEOUT_FLAGS_OSTIMER | GPU_TIMEOUT_FLAGS_BYPASS_THREAD_STATE);
34990eb1077SAndy Ritger     while (kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
35090eb1077SAndy Ritger     {
35190eb1077SAndy Ritger         if (gpuCheckTimeout(pGpu, &timeout) == NV_ERR_TIMEOUT)
35290eb1077SAndy Ritger         {
35390eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "FSP command timed out\n");
35490eb1077SAndy Ritger             return NV_ERR_TIMEOUT;
35590eb1077SAndy Ritger         }
35690eb1077SAndy Ritger 
35790eb1077SAndy Ritger         osSpinLoop();
35890eb1077SAndy Ritger     }
35990eb1077SAndy Ritger 
36090eb1077SAndy Ritger     return status;
36190eb1077SAndy Ritger }
36290eb1077SAndy Ritger 
36390eb1077SAndy Ritger /*!
36490eb1077SAndy Ritger  * @brief Read and process message from FSP via RM message queue.
36590eb1077SAndy Ritger  *
36690eb1077SAndy Ritger  * Supports both single and multi-packet message. For multi-packet messages, this
36790eb1077SAndy Ritger  * loops until all packets are received, polling at each iteration for the next
36890eb1077SAndy Ritger  * packet to come in. If a buffer is provided, the message payload will be
36990eb1077SAndy Ritger  * returned there.
37090eb1077SAndy Ritger  *
37190eb1077SAndy Ritger  * @note: For multi-packet messages, a buffer in which the message payload will
37290eb1077SAndy Ritger  * be reconstructed must be provided.
37390eb1077SAndy Ritger  *
37490eb1077SAndy Ritger  * @param[in]     pGpu              OBJGPU pointer
37590eb1077SAndy Ritger  * @param[in]     pKernelFsp        KernelFsp pointer
37690eb1077SAndy Ritger  * @param[in/out] pPayloadBuffer    Buffer in which to return message payload
37790eb1077SAndy Ritger  * @param[in]     payloadBufferSize Payload buffer size
37890eb1077SAndy Ritger  *
37990eb1077SAndy Ritger  * @return NV_OK, NV_ERR_INVALID_DATA, NV_ERR_INSUFFICIENT_RESOURCES, or errors
38090eb1077SAndy Ritger  *         from functions called within
38190eb1077SAndy Ritger  */
38290eb1077SAndy Ritger static NV_STATUS
kfspReadMessage(OBJGPU * pGpu,KernelFsp * pKernelFsp,NvU8 * pPayloadBuffer,NvU32 payloadBufferSize)38390eb1077SAndy Ritger kfspReadMessage
38490eb1077SAndy Ritger (
38590eb1077SAndy Ritger     OBJGPU    *pGpu,
38690eb1077SAndy Ritger     KernelFsp *pKernelFsp,
38790eb1077SAndy Ritger     NvU8      *pPayloadBuffer,
38890eb1077SAndy Ritger     NvU32      payloadBufferSize
38990eb1077SAndy Ritger )
39090eb1077SAndy Ritger {
39190eb1077SAndy Ritger     NvU8             *pPacketBuffer;
39290eb1077SAndy Ritger     NV_STATUS         status;
39390eb1077SAndy Ritger     NvU32             totalPayloadSize = 0;
39490eb1077SAndy Ritger     MCTP_PACKET_STATE packetState = MCTP_PACKET_STATE_START;
39590eb1077SAndy Ritger 
39690eb1077SAndy Ritger     if (kfspIsMsgQueueEmpty(pGpu, pKernelFsp))
39790eb1077SAndy Ritger     {
39890eb1077SAndy Ritger         NV_PRINTF(LEVEL_WARNING, "Tried to read FSP response but MSG queue is empty\n");
39990eb1077SAndy Ritger         return NV_OK;
40090eb1077SAndy Ritger     }
40190eb1077SAndy Ritger 
40290eb1077SAndy Ritger     pPacketBuffer = portMemAllocNonPaged(kfspGetRmChannelSize_HAL(pGpu, pKernelFsp));
403811073c5SAndy Ritger     NV_CHECK_OR_RETURN(LEVEL_ERROR, pPacketBuffer != NULL, NV_ERR_NO_MEMORY);
40490eb1077SAndy Ritger 
40590eb1077SAndy Ritger     while ((packetState != MCTP_PACKET_STATE_END) && (packetState != MCTP_PACKET_STATE_SINGLE_PACKET))
40690eb1077SAndy Ritger     {
40790eb1077SAndy Ritger         NvU32 msgqHead, msgqTail;
40890eb1077SAndy Ritger         NvU32 packetSize;
40990eb1077SAndy Ritger         NvU32 curPayloadSize;
41090eb1077SAndy Ritger         NvU8  curHeaderSize;
41190eb1077SAndy Ritger         NvU8  tag;
41290eb1077SAndy Ritger 
41390eb1077SAndy Ritger         // Wait for next packet
41490eb1077SAndy Ritger         status = kfspPollForResponse(pGpu, pKernelFsp);
41590eb1077SAndy Ritger         if (status != NV_OK)
41690eb1077SAndy Ritger         {
41790eb1077SAndy Ritger             goto done;
41890eb1077SAndy Ritger         }
41990eb1077SAndy Ritger 
42090eb1077SAndy Ritger         kfspGetMsgQueueHeadTail_HAL(pGpu, pKernelFsp, &msgqHead, &msgqTail);
42190eb1077SAndy Ritger 
42290eb1077SAndy Ritger         // Tail points to last DWORD in packet, not DWORD immediately following it
42390eb1077SAndy Ritger         packetSize = (msgqTail - msgqHead) + sizeof(NvU32);
42490eb1077SAndy Ritger 
42590eb1077SAndy Ritger         if ((packetSize < sizeof(NvU32)) ||
42690eb1077SAndy Ritger             (packetSize > kfspGetRmChannelSize_HAL(pGpu, pKernelFsp)))
42790eb1077SAndy Ritger         {
42890eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "FSP response packet is invalid size: size=0x%x bytes\n", packetSize);
42990eb1077SAndy Ritger             status = NV_ERR_INVALID_DATA;
43090eb1077SAndy Ritger             goto done;
43190eb1077SAndy Ritger         }
43290eb1077SAndy Ritger 
43390eb1077SAndy Ritger         kfspReadFromEmem_HAL(pGpu, pKernelFsp, pPacketBuffer, packetSize);
43490eb1077SAndy Ritger 
43590eb1077SAndy Ritger         status = kfspGetPacketInfo_HAL(pGpu, pKernelFsp, pPacketBuffer, packetSize, &packetState, &tag);
43690eb1077SAndy Ritger         if (status != NV_OK)
43790eb1077SAndy Ritger         {
43890eb1077SAndy Ritger             goto done;
43990eb1077SAndy Ritger         }
44090eb1077SAndy Ritger 
44190eb1077SAndy Ritger         if ((packetState == MCTP_PACKET_STATE_START) || (packetState == MCTP_PACKET_STATE_SINGLE_PACKET))
44290eb1077SAndy Ritger         {
44390eb1077SAndy Ritger             // Packet contains payload header
44490eb1077SAndy Ritger             curHeaderSize = sizeof(MCTP_HEADER);
44590eb1077SAndy Ritger         }
44690eb1077SAndy Ritger         else
44790eb1077SAndy Ritger         {
44890eb1077SAndy Ritger             curHeaderSize = sizeof(NvU32);
44990eb1077SAndy Ritger         }
45090eb1077SAndy Ritger 
45190eb1077SAndy Ritger         curPayloadSize = packetSize - curHeaderSize;
45290eb1077SAndy Ritger 
45390eb1077SAndy Ritger         if ((pPayloadBuffer == NULL) && (packetState != MCTP_PACKET_STATE_SINGLE_PACKET))
45490eb1077SAndy Ritger         {
45590eb1077SAndy Ritger             NV_PRINTF(LEVEL_ERROR, "No buffer provided when receiving multi-packet message. Buffer needed to reconstruct message\n");
45690eb1077SAndy Ritger             status = NV_ERR_INSUFFICIENT_RESOURCES;
45790eb1077SAndy Ritger             goto done;
45890eb1077SAndy Ritger         }
45990eb1077SAndy Ritger 
46090eb1077SAndy Ritger         if (pPayloadBuffer != NULL)
46190eb1077SAndy Ritger         {
46290eb1077SAndy Ritger             if (payloadBufferSize < (totalPayloadSize + curPayloadSize))
46390eb1077SAndy Ritger             {
46490eb1077SAndy Ritger                 NV_PRINTF(LEVEL_ERROR, "Buffer provided for message payload too small. Payload size: 0x%x Buffer size: 0x%x\n",
46590eb1077SAndy Ritger                           totalPayloadSize + curPayloadSize, payloadBufferSize);
46690eb1077SAndy Ritger                 status = NV_ERR_INSUFFICIENT_RESOURCES;
46790eb1077SAndy Ritger                 goto done;
46890eb1077SAndy Ritger             }
46990eb1077SAndy Ritger             portMemCopy(pPayloadBuffer + totalPayloadSize, payloadBufferSize - totalPayloadSize ,
47090eb1077SAndy Ritger                         pPacketBuffer + curHeaderSize, curPayloadSize);
47190eb1077SAndy Ritger         }
47290eb1077SAndy Ritger         totalPayloadSize += curPayloadSize;
47390eb1077SAndy Ritger 
47490eb1077SAndy Ritger         // Set TAIL = HEAD to indicate CPU received message
47590eb1077SAndy Ritger         kfspUpdateMsgQueueHeadTail_HAL(pGpu, pKernelFsp, msgqHead, msgqHead);
47690eb1077SAndy Ritger     }
47790eb1077SAndy Ritger 
47890eb1077SAndy Ritger     NvU8 *pMessagePayload = (pPayloadBuffer == NULL) ? (pPacketBuffer + sizeof(MCTP_HEADER)) : pPayloadBuffer;
47990eb1077SAndy Ritger 
48090eb1077SAndy Ritger     status = kfspProcessNvdmMessage_HAL(pGpu, pKernelFsp, pMessagePayload, totalPayloadSize);
48190eb1077SAndy Ritger 
48290eb1077SAndy Ritger done:
48390eb1077SAndy Ritger     portMemFree(pPacketBuffer);
48490eb1077SAndy Ritger     return status;
48590eb1077SAndy Ritger }
48690eb1077SAndy Ritger 
48790eb1077SAndy Ritger /*!
48890eb1077SAndy Ritger  * @brief Send one MCTP packet to FSP via EMEM
48990eb1077SAndy Ritger  *
49090eb1077SAndy Ritger  * @param[in] pGpu          OBJGPU pointer
49190eb1077SAndy Ritger  * @param[in] pKernelFsp    KernelFsp pointer
49290eb1077SAndy Ritger  * @param[in] pPacket       MCTP packet
49390eb1077SAndy Ritger  * @param[in] packetSize    MCTP packet size in bytes
49490eb1077SAndy Ritger  *
49590eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_INSUFFICIENT_RESOURCES
49690eb1077SAndy Ritger  */
49790eb1077SAndy Ritger NV_STATUS
kfspSendPacket_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp,NvU8 * pPacket,NvU32 packetSize)49890eb1077SAndy Ritger kfspSendPacket_IMPL
49990eb1077SAndy Ritger (
50090eb1077SAndy Ritger     OBJGPU      *pGpu,
50190eb1077SAndy Ritger     KernelFsp   *pKernelFsp,
50290eb1077SAndy Ritger     NvU8        *pPacket,
50390eb1077SAndy Ritger     NvU32        packetSize
50490eb1077SAndy Ritger )
50590eb1077SAndy Ritger {
50690eb1077SAndy Ritger     NvU32 paddedSize;
50790eb1077SAndy Ritger     NvU8 *pBuffer = NULL;
50890eb1077SAndy Ritger     NV_STATUS status = NV_OK;
50990eb1077SAndy Ritger 
51090eb1077SAndy Ritger     // Check that queue is ready to receive data
51190eb1077SAndy Ritger     status = kfspPollForQueueEmpty(pGpu, pKernelFsp);
51290eb1077SAndy Ritger     if (status != NV_OK)
51390eb1077SAndy Ritger     {
51490eb1077SAndy Ritger         return NV_ERR_INSUFFICIENT_RESOURCES;
51590eb1077SAndy Ritger     }
51690eb1077SAndy Ritger 
51790eb1077SAndy Ritger     // Pad to align size to 4-bytes boundary since EMEMC increments by DWORDS
51890eb1077SAndy Ritger     paddedSize = NV_ALIGN_UP(packetSize, sizeof(NvU32));
51990eb1077SAndy Ritger     pBuffer = portMemAllocNonPaged(paddedSize);
520811073c5SAndy Ritger     NV_CHECK_OR_RETURN(LEVEL_ERROR, pBuffer != NULL, NV_ERR_NO_MEMORY);
52190eb1077SAndy Ritger     portMemSet(pBuffer, 0, paddedSize);
52290eb1077SAndy Ritger     portMemCopy(pBuffer, paddedSize, pPacket, paddedSize);
52390eb1077SAndy Ritger 
52490eb1077SAndy Ritger     kfspWriteToEmem_HAL(pGpu, pKernelFsp, pBuffer, paddedSize);
52590eb1077SAndy Ritger 
52690eb1077SAndy Ritger     // Update HEAD and TAIL with new EMEM offset; RM always starts at offset 0.
52790eb1077SAndy Ritger     kfspUpdateQueueHeadTail_HAL(pGpu, pKernelFsp, 0, paddedSize - sizeof(NvU32));
52890eb1077SAndy Ritger 
52990eb1077SAndy Ritger     portMemFree(pBuffer);
53090eb1077SAndy Ritger     return status;
53190eb1077SAndy Ritger }
53290eb1077SAndy Ritger 
53390eb1077SAndy Ritger /*!
53490eb1077SAndy Ritger  * @brief Send a MCTP message to FSP via EMEM, and read response
53590eb1077SAndy Ritger  *
53690eb1077SAndy Ritger  *
53790eb1077SAndy Ritger  * Response payload buffer is optional if response fits in a single packet.
53890eb1077SAndy Ritger  *
53990eb1077SAndy Ritger  * @param[in] pGpu               OBJGPU pointer
54090eb1077SAndy Ritger  * @param[in] pKernelFsp         KernelFsp pointer
54190eb1077SAndy Ritger  * @param[in] pPayload           Pointer to message payload
54290eb1077SAndy Ritger  * @param[in] size               Message payload size
54390eb1077SAndy Ritger  * @param[in] nvdmType           NVDM type of message being sent
54490eb1077SAndy Ritger  * @param[in] pResponsePayload   Buffer in which to return response payload
54590eb1077SAndy Ritger  * @param[in] responseBufferSize Response payload buffer size
54690eb1077SAndy Ritger  *
54790eb1077SAndy Ritger  * @return NV_OK, or NV_ERR_*
54890eb1077SAndy Ritger  */
54990eb1077SAndy Ritger NV_STATUS
kfspSendAndReadMessage_IMPL(OBJGPU * pGpu,KernelFsp * pKernelFsp,NvU8 * pPayload,NvU32 size,NvU32 nvdmType,NvU8 * pResponsePayload,NvU32 responseBufferSize)55090eb1077SAndy Ritger kfspSendAndReadMessage_IMPL
55190eb1077SAndy Ritger (
55290eb1077SAndy Ritger     OBJGPU    *pGpu,
55390eb1077SAndy Ritger     KernelFsp *pKernelFsp,
55490eb1077SAndy Ritger     NvU8      *pPayload,
55590eb1077SAndy Ritger     NvU32      size,
55690eb1077SAndy Ritger     NvU32      nvdmType,
55790eb1077SAndy Ritger     NvU8      *pResponsePayload,
55890eb1077SAndy Ritger     NvU32      responseBufferSize
55990eb1077SAndy Ritger )
56090eb1077SAndy Ritger {
56190eb1077SAndy Ritger     NvU32 dataSent, dataRemaining;
56290eb1077SAndy Ritger     NvU32 packetPayloadCapacity;
56390eb1077SAndy Ritger     NvU32 curPayloadSize;
56490eb1077SAndy Ritger     NvU32 headerSize;
56590eb1077SAndy Ritger     NvU32 fspEmemRmChannelSize;
56690eb1077SAndy Ritger     NvBool bSinglePacket;
56790eb1077SAndy Ritger     NV_STATUS status;
56890eb1077SAndy Ritger     NvU8 *pBuffer = NULL;
56990eb1077SAndy Ritger     NvU8  seq = 0;
57090eb1077SAndy Ritger     NvU8  seid = 0;
57190eb1077SAndy Ritger 
57290eb1077SAndy Ritger     // Allocate buffer of same size as channel
57390eb1077SAndy Ritger     fspEmemRmChannelSize = kfspGetRmChannelSize_HAL(pGpu, pKernelFsp);
57490eb1077SAndy Ritger     pBuffer = portMemAllocNonPaged(fspEmemRmChannelSize);
575811073c5SAndy Ritger     NV_CHECK_OR_RETURN(LEVEL_ERROR, pBuffer != NULL, NV_ERR_NO_MEMORY);
57690eb1077SAndy Ritger     portMemSet(pBuffer, 0, fspEmemRmChannelSize);
57790eb1077SAndy Ritger 
57890eb1077SAndy Ritger     //
57990eb1077SAndy Ritger     // Check if message will fit in single packet
58090eb1077SAndy Ritger     // We lose 2 DWORDS to MCTP and NVDM headers
58190eb1077SAndy Ritger     //
58290eb1077SAndy Ritger     headerSize = 2 * sizeof(NvU32);
58390eb1077SAndy Ritger     packetPayloadCapacity = fspEmemRmChannelSize - headerSize;
58490eb1077SAndy Ritger     bSinglePacket = (size <= packetPayloadCapacity);
58590eb1077SAndy Ritger 
58690eb1077SAndy Ritger     // First packet
58790eb1077SAndy Ritger     seid = kfspNvdmToSeid_HAL(pGpu, pKernelFsp, nvdmType);
58890eb1077SAndy Ritger     ((NvU32 *)pBuffer)[0] = kfspCreateMctpHeader_HAL(pGpu, pKernelFsp, 1, (NvU8)bSinglePacket, seid, seq); // SOM=1,EOM=?,SEID,SEQ=0
58990eb1077SAndy Ritger     ((NvU32 *)pBuffer)[1] = kfspCreateNvdmHeader_HAL(pGpu, pKernelFsp, nvdmType);
59090eb1077SAndy Ritger 
59190eb1077SAndy Ritger     curPayloadSize = NV_MIN(size, packetPayloadCapacity);
59290eb1077SAndy Ritger     portMemCopy(pBuffer + headerSize, packetPayloadCapacity, pPayload, curPayloadSize);
59390eb1077SAndy Ritger 
59490eb1077SAndy Ritger     status = kfspSendPacket(pGpu, pKernelFsp, pBuffer, curPayloadSize + headerSize);
59590eb1077SAndy Ritger     if (status != NV_OK)
59690eb1077SAndy Ritger     {
59790eb1077SAndy Ritger         goto failed;
59890eb1077SAndy Ritger     }
59990eb1077SAndy Ritger 
60090eb1077SAndy Ritger     if (!bSinglePacket)
60190eb1077SAndy Ritger     {
60290eb1077SAndy Ritger         // Multi packet case
60390eb1077SAndy Ritger         dataSent = curPayloadSize;
60490eb1077SAndy Ritger         dataRemaining = size - dataSent;
60590eb1077SAndy Ritger         headerSize = sizeof(NvU32); // No longer need NVDM header
60690eb1077SAndy Ritger         packetPayloadCapacity = fspEmemRmChannelSize - headerSize;
60790eb1077SAndy Ritger 
60890eb1077SAndy Ritger         while (dataRemaining > 0)
60990eb1077SAndy Ritger         {
61090eb1077SAndy Ritger             NvBool bLastPacket = (dataRemaining <= packetPayloadCapacity);
61190eb1077SAndy Ritger             curPayloadSize = (bLastPacket) ? dataRemaining : packetPayloadCapacity;
61290eb1077SAndy Ritger 
61390eb1077SAndy Ritger             portMemSet(pBuffer, 0, fspEmemRmChannelSize);
61490eb1077SAndy Ritger             ((NvU32 *)pBuffer)[0] = kfspCreateMctpHeader_HAL(pGpu, pKernelFsp, 0, (NvU8)bLastPacket, seid, (++seq) % 4);
61590eb1077SAndy Ritger 
61690eb1077SAndy Ritger             portMemCopy(pBuffer + headerSize, packetPayloadCapacity,
61790eb1077SAndy Ritger                         pPayload + dataSent, curPayloadSize);
61890eb1077SAndy Ritger 
61990eb1077SAndy Ritger             status = kfspSendPacket(pGpu, pKernelFsp, pBuffer, curPayloadSize + headerSize);
62090eb1077SAndy Ritger             if (status != NV_OK)
62190eb1077SAndy Ritger             {
62290eb1077SAndy Ritger                 goto failed;
62390eb1077SAndy Ritger             }
62490eb1077SAndy Ritger 
62590eb1077SAndy Ritger             dataSent += curPayloadSize;
62690eb1077SAndy Ritger             dataRemaining -= curPayloadSize;
62790eb1077SAndy Ritger         }
62890eb1077SAndy Ritger 
62990eb1077SAndy Ritger     }
63090eb1077SAndy Ritger 
63190eb1077SAndy Ritger     status = kfspPollForResponse(pGpu, pKernelFsp);
63290eb1077SAndy Ritger     if (status != NV_OK)
63390eb1077SAndy Ritger     {
63490eb1077SAndy Ritger         goto failed;
63590eb1077SAndy Ritger     }
63690eb1077SAndy Ritger     status = kfspReadMessage(pGpu, pKernelFsp, pResponsePayload, responseBufferSize);
63790eb1077SAndy Ritger 
63890eb1077SAndy Ritger failed:
63990eb1077SAndy Ritger     portMemFree(pBuffer);
64090eb1077SAndy Ritger 
64190eb1077SAndy Ritger     return status;
64290eb1077SAndy Ritger }
643