1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2021-2023 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21  * DEALINGS IN THE SOFTWARE.
22  */
23 #include "gpu/falcon/kernel_falcon.h"
24 #include "gpu/nvlink/kernel_nvlink.h"
25 #include "gpu/fifo/kernel_fifo.h"
26 #include "gpu/fifo/kernel_channel.h"
27 #include "gpu/fifo/kernel_channel_group.h"
28 #include "gpu/fifo/kernel_channel_group_api.h"
29 #include "gpu/subdevice/subdevice.h"
30 #include "gpu/mem_mgr/mem_mgr.h"
31 #include "vgpu/rpc.h"
32 #include "ctrl/ctrl2080/ctrl2080flcn.h"
33 
34 NV_STATUS subdeviceCtrlCmdFlcnGetCtxBufferInfo_IMPL
35 (   Subdevice *pSubdevice,
36     NV2080_CTRL_FLCN_GET_CTX_BUFFER_INFO_PARAMS *pParams
37 )
38 {
39     POBJGPU pGpu = GPU_RES_GET_GPU(pSubdevice);
40     PMEMORY_DESCRIPTOR pMemDesc, pRootMemDesc;
41     RsClient *pUserClient;
42     KernelChannel *pKernelChannel = NULL;
43     NV_STATUS status = NV_OK;
44     NvU64 pageSize;
45     NvU8 *pUuid = NULL;
46 
47     //
48     // vGPU:
49     //
50     // Since vGPU does all real hardware management in the
51     // host, if we are in guest OS (where IS_VIRTUAL(pGpu) is true),
52     // do an RPC to the host to get context buffers information.
53     //
54     if (IS_VIRTUAL_WITHOUT_SRIOV(pGpu) ||
55         (IS_VIRTUAL_WITH_SRIOV(pGpu) && gpuIsWarBug200577889SriovHeavyEnabled(pGpu)))
56     {
57         CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
58         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
59 
60         NV_RM_RPC_CONTROL(pGpu,
61                           pRmCtrlParams->hClient,
62                           pRmCtrlParams->hObject,
63                           pRmCtrlParams->cmd,
64                           pRmCtrlParams->pParams,
65                           pRmCtrlParams->paramsSize,
66                           status);
67         return status;
68     }
69 
70     NV_CHECK_OK_OR_RETURN(LEVEL_INFO,
71         serverGetClientUnderLock(&g_resServ, pParams->hUserClient, &pUserClient));
72 
73     NV_CHECK_OK_OR_RETURN(LEVEL_INFO,
74         CliGetKernelChannel(pUserClient, pParams->hChannel, &pKernelChannel));
75     NV_ASSERT_OR_RETURN(pKernelChannel != NULL, NV_ERR_INVALID_CHANNEL);
76 
77     switch (kchannelGetEngineType(pKernelChannel))
78     {
79         case RM_ENGINE_TYPE_SEC2:
80         {
81             break;
82         }
83         default:
84         {
85             return NV_ERR_NOT_SUPPORTED;
86         }
87     }
88 
89     NV_ASSERT_OK_OR_RETURN(kchangrpGetEngineContextMemDesc(pGpu, pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup, &pMemDesc));
90     pRootMemDesc = memdescGetRootMemDesc(pMemDesc, NULL);
91 
92     pParams->bufferHandle = NV_PTR_TO_NvP64(pMemDesc);
93     pParams->bIsContigous = memdescGetContiguity(pMemDesc, AT_GPU);
94     pParams->aperture = memdescGetAddressSpace(pMemDesc);
95     pParams->pageCount = pMemDesc->PageCount;
96     pParams->kind = memdescGetPteKindForGpu(pMemDesc, pMemDesc->pGpu);
97 
98     {
99         NvU64 physAddr;
100         GMMU_APERTURE aperture = kgmmuGetExternalAllocAperture(pParams->aperture);
101 
102         memdescGetPhysAddrsForGpu(pMemDesc, pMemDesc->pGpu,
103                                   AT_GPU, 0, 0, 1,
104                                   &physAddr);
105 
106         pParams->physAddr =
107             kgmmuEncodePhysAddr(GPU_GET_KERNEL_GMMU(pMemDesc->pGpu), aperture, physAddr, NVLINK_INVALID_FABRIC_ADDR);
108     }
109 
110     pageSize = memdescGetPageSize(pMemDesc, AT_GPU);
111     if (pageSize == 0)
112     {
113         status = memmgrSetMemDescPageSize_HAL(pMemDesc->pGpu,
114                                               GPU_GET_MEMORY_MANAGER(pMemDesc->pGpu),
115                                               pMemDesc,
116                                               AT_GPU,
117                                               RM_ATTR_PAGE_SIZE_DEFAULT);
118         if (status != NV_OK)
119             return status;
120 
121         pageSize = memdescGetPageSize(pMemDesc, AT_GPU);
122         NV_ASSERT(pageSize != 0);
123     }
124 
125     //
126     // Alignment is used to adjust the mapping VA. Hence, we need to make sure
127     // that it is at least pageSize to make mapping calculation work correctly.
128     //
129     pParams->alignment = (pMemDesc->Alignment != 0) ?
130         NV_ALIGN_UP(pMemDesc->Alignment, pageSize) : pageSize;
131 
132     pParams->size = pMemDesc->ActualSize;
133 
134     NV_ASSERT_OR_RETURN(pageSize <= NV_U32_MAX, NV_ERR_INVALID_STATE);
135     pParams->pageSize = (NvU32)pageSize;
136 
137     pParams->bDeviceDescendant = pRootMemDesc->pGpu != NULL;
138 
139     if (pParams->bDeviceDescendant)
140     {
141         NvU32 flags = DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _TYPE, _SHA1) |
142             DRF_DEF(2080_GPU_CMD, _GPU_GET_GID_FLAGS, _FORMAT, _BINARY);
143         NvU32 uuidLength;
144         // allocates memory for pUuid on success
145         NV_ASSERT_OK_OR_RETURN(gpuGetGidInfo(pGpu, &pUuid, &uuidLength, flags));
146         if (uuidLength == sizeof(pParams->uuid))
147             portMemCopy(pParams->uuid, uuidLength, pUuid, uuidLength);
148         else
149         {
150             status = NV_ERR_INVALID_ARGUMENT;
151             goto done;
152         }
153     }
154 
155 done:
156     portMemFree(pUuid);
157     return status;
158 }
159 
160 NV_STATUS
161 subdeviceCtrlCmdFlcnGetCtxBufferSize_IMPL
162 (
163     Subdevice *pSubdevice,
164     NV2080_CTRL_FLCN_GET_CTX_BUFFER_SIZE_PARAMS *pParams
165 )
166 {
167     POBJGPU pGpu = GPU_RES_GET_GPU(pSubdevice);
168     PMEMORY_DESCRIPTOR pMemDesc;
169     KernelChannel *pKernelChannel = NULL;
170     NV_STATUS status = NV_OK;
171     NvU64 alignment;
172     NvU64 pageSize;
173     NvU64 totalBufferSize;
174 
175     //
176     // vGPU:
177     //
178     // Since vGPU does all real hardware management in the
179     // host, if we are in guest OS (where IS_VIRTUAL(pGpu) is true),
180     // do an RPC to the host to fetch the engine context buffer size.
181     //
182     if (IS_VIRTUAL_WITHOUT_SRIOV(pGpu) ||
183         (IS_VIRTUAL_WITH_SRIOV(pGpu) && gpuIsWarBug200577889SriovHeavyEnabled(pGpu)))
184     {
185         CALL_CONTEXT *pCallContext = resservGetTlsCallContext();
186         RmCtrlParams *pRmCtrlParams = pCallContext->pControlParams;
187 
188         NV_RM_RPC_CONTROL(pGpu,
189                           pRmCtrlParams->hClient,
190                           pRmCtrlParams->hObject,
191                           pRmCtrlParams->cmd,
192                           pRmCtrlParams->pParams,
193                           pRmCtrlParams->paramsSize,
194                           status);
195         return status;
196     }
197 
198     NV_CHECK_OK_OR_RETURN(LEVEL_INFO,
199         CliGetKernelChannel(RES_GET_CLIENT(pSubdevice), pParams->hChannel,
200             &pKernelChannel));
201     NV_ASSERT_OR_RETURN(pKernelChannel != NULL, NV_ERR_INVALID_CHANNEL);
202 
203     switch (kchannelGetEngineType(pKernelChannel))
204     {
205         case RM_ENGINE_TYPE_SEC2:
206         {
207             break;
208         }
209         default:
210         {
211             return NV_ERR_NOT_SUPPORTED;
212         }
213     }
214 
215     NV_ASSERT_OK_OR_RETURN(kchangrpGetEngineContextMemDesc(pGpu, pKernelChannel->pKernelChannelGroupApi->pKernelChannelGroup, &pMemDesc));
216 
217     pageSize = memdescGetPageSize(pMemDesc, AT_GPU);
218     if (pageSize == 0)
219     {
220         status = memmgrSetMemDescPageSize_HAL(pMemDesc->pGpu,
221                                               GPU_GET_MEMORY_MANAGER(pMemDesc->pGpu),
222                                               pMemDesc,
223                                               AT_GPU,
224                                               RM_ATTR_PAGE_SIZE_DEFAULT);
225         if (status != NV_OK)
226             return status;
227 
228         pageSize = memdescGetPageSize(pMemDesc, AT_GPU);
229         NV_ASSERT(pageSize != 0);
230     }
231 
232     //
233     // Adjust the total size by adding the alignment so that the mapping VA can
234     // be adjusted.
235     //
236     alignment = (pMemDesc->Alignment != 0) ? NV_ALIGN_UP(pMemDesc->Alignment, pageSize) : pageSize;
237     totalBufferSize = 0;
238     totalBufferSize += alignment;
239     totalBufferSize += (alignment != 0) ? NV_ALIGN_UP(pMemDesc->ActualSize, alignment) : pMemDesc->ActualSize;
240     pParams->totalBufferSize = totalBufferSize;
241 
242     return status;
243 }
244