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