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 
24 #define NVOC_KERNEL_MIG_MANAGER_H_PRIVATE_ACCESS_ALLOWED
25 
26 #include "kernel/gpu/mem_mgr/mem_mgr.h"
27 #include "kernel/gpu/mem_mgr/heap.h"
28 #include "kernel/gpu/mig_mgr/kernel_mig_manager.h"
29 #include "kernel/gpu/fifo/kernel_fifo.h"
30 #include "gpu/bus/kern_bus.h"
31 
32 #include "published/ampere/ga100/dev_bus.h"
33 #include "published/ampere/ga100/dev_bus_addendum.h"
34 
35 /*!
36  * @brief   Checks Devinit owned scratch bit to see if MIG is enabled or not
37  *
38  * @return  NV_TRUE if scratch bit is set else NV_FALSE
39  */
40 NvBool
41 kmigmgrIsDevinitMIGBitSet_GA100
42 (
43     OBJGPU *pGpu,
44     KernelMIGManager *pKernelMIGManager
45 )
46 {
47     NvU32 regVal;
48 
49     regVal = GPU_REG_RD32(pGpu, NV_PBUS_SW_SCRATCH(1));
50 
51     return FLD_TEST_DRF(_PBUS, _SW_SCRATCH1_SMC,_MODE, _ON, regVal);
52 }
53 
54 /*!
55  * @brief   Peforms checks to determine whether instancing can be enabled on
56  *          this GPU, such as determining whether any partitionable engines are
57  *          currently active.
58  */
59 NV_STATUS
60 kmigmgrCreateGPUInstanceCheck_GA100
61 (
62     OBJGPU *pGpu,
63     KernelMIGManager *pKernelMIGManager,
64     NvBool bMemoryPartitioningNeeded
65 )
66 {
67     Heap             *pHeap;
68     KernelFifo       *pKernelFifo = GPU_GET_KERNEL_FIFO(pGpu);
69     RM_ENGINE_TYPE    engines[RM_ENGINE_TYPE_LAST];
70     NvU32             engineCount;
71     NvU32             i;
72     NvU64             largestFreeSize;
73     NvU64             base;
74     NvU64             unused;
75     NV_RANGE          freeBlock;
76     MemoryManager    *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
77     NV_RANGE          partitionableMemoryRange = memmgrGetMIGPartitionableMemoryRange(pGpu, pMemoryManager);
78 
79     // Ensure the engine DB is up-to-date
80     NV_ASSERT_OK_OR_RETURN(gpuUpdateEngineTable(pGpu));
81 
82     // Store all engine tags of partitionable engines in the system
83     engineCount = 0;
84     for (i = 0; i < pGpu->engineDB.size; ++i)
85     {
86         if (kmigmgrIsEnginePartitionable(pGpu, pKernelMIGManager, pGpu->engineDB.pType[i]))
87         {
88             //
89             // If memory partitioning isnt needed, scrubber channel will be active, and
90             // partitioning isn't really a destructive operation anyway, so
91             // skip checking for copy engines
92             //
93             if (RM_ENGINE_TYPE_IS_COPY(pGpu->engineDB.pType[i]) &&
94                 !bMemoryPartitioningNeeded)
95             {
96                 continue;
97             }
98 
99             if (RM_ENGINE_TYPE_IS_GR(pGpu->engineDB.pType[i]) &&
100                 (RM_ENGINE_TYPE_GR_IDX(pGpu->engineDB.pType[i]) > 0))
101             {
102                 //
103                 // This check is used during GPU instance creation, prior to which
104                 // it is impossible to use GR1-7, so as an optimization, skip
105                 // checking for those.
106                 //
107                 continue;
108             }
109 
110             engines[engineCount++] = pGpu->engineDB.pType[i];
111         }
112     }
113 
114     // Make sure there are no channels alive on any of these engines
115     if (kfifoEngineListHasChannel(pGpu, pKernelFifo, engines, engineCount))
116         return NV_ERR_STATE_IN_USE;
117 
118     //
119     // Check for any alive P2P references to this GPU. P2P objects must
120     // be re-created after disabling MIG. If it is allowed for  MIG to
121     // continue enablement without all P2P objects torn down, there is
122     // the possibility that P2P mappings and state will never be updated.
123     //
124     if (bMemoryPartitioningNeeded || !kmigmgrIsMIGNvlinkP2PSupportOverridden(pGpu, pKernelMIGManager))
125     {
126         NV_CHECK_OR_RETURN(LEVEL_ERROR,
127             !kbusIsGpuP2pAlive(pGpu, GPU_GET_KERNEL_BUS(pGpu)),
128             NV_ERR_STATE_IN_USE);
129     }
130 
131     pHeap = GPU_GET_HEAP(pGpu);
132     if (!memmgrIsPmaInitialized(pMemoryManager))
133     {
134         NV_ASSERT_OK_OR_RETURN(
135             heapInfo(pHeap, &unused, &unused, &unused, &base, &largestFreeSize));
136     }
137     else
138     {
139         pmaGetLargestFree(&pHeap->pmaObject, &largestFreeSize, &base, &unused);
140     }
141 
142     // Make sure that no memory has been claimed from our partitionable range
143     freeBlock = rangeMake(base, base + largestFreeSize - 1);
144     if (!rangeContains(freeBlock, partitionableMemoryRange))
145         return NV_ERR_STATE_IN_USE;
146 
147     return NV_OK;
148 }
149 
150 /*!
151  * @brief   Function to determine whether gpu instance flags are valid
152  *          for this GPU
153  *
154  * @param[IN]   pGpu
155  * @param[IN]   pKernelMIGManager
156  * @param[IN]   gpuInstanceFlag       NV2080_CTRL_GPU_PARTITION_FLAG_*
157  *
158  * @return  Returns true if flags are valid
159  */
160 NvBool
161 kmigmgrIsGPUInstanceFlagValid_GA100
162 (
163     OBJGPU *pGpu,
164     KernelMIGManager *pGrMgr,
165     NvU32 gpuInstanceFlag
166 )
167 {
168     NvU32 memSizeFlag = DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG,
169                                 _MEMORY_SIZE, gpuInstanceFlag);
170     NvU32 computeSizeFlag = DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG,
171                                     _COMPUTE_SIZE, gpuInstanceFlag);
172 
173     switch (memSizeFlag)
174     {
175         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_FULL:
176         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_HALF:
177         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_QUARTER:
178         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_EIGHTH:
179             break;
180         default:
181             NV_PRINTF(LEVEL_ERROR, "Unrecognized GPU mem partitioning flag 0x%x\n",
182                       memSizeFlag);
183             return NV_FALSE;
184     }
185 
186     switch (computeSizeFlag)
187     {
188         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_FULL:
189         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_HALF:
190         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_HALF:
191         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_QUARTER:
192         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_QUARTER:
193         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_EIGHTH:
194             break;
195         default:
196             NV_PRINTF(LEVEL_ERROR, "Unrecognized GPU compute partitioning flag 0x%x\n",
197                       computeSizeFlag);
198             return NV_FALSE;
199     }
200 
201     return NV_TRUE;
202 }
203 
204 /*!
205  * @brief   Function to determine whether gpu instance flag combinations are valid
206  *          for this GPU
207  */
208 NvBool
209 kmigmgrIsGPUInstanceCombinationValid_GA100
210 (
211     OBJGPU *pGpu,
212     KernelMIGManager *pKernelMIGManager,
213     NvU32 gpuInstanceFlag
214 )
215 {
216     NvU32 memSizeFlag = DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG, _MEMORY_SIZE, gpuInstanceFlag);
217     NvU32 computeSizeFlag = DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG, _COMPUTE_SIZE, gpuInstanceFlag);
218 
219     if (!kmigmgrIsGPUInstanceFlagValid_HAL(pGpu, pKernelMIGManager, gpuInstanceFlag))
220     {
221         return NV_FALSE;
222     }
223 
224     // JPG_OFA profile is only available on the smallest partition
225     if (FLD_TEST_REF(NV2080_CTRL_GPU_PARTITION_FLAG_REQ_DEC_JPG_OFA, _ENABLE, gpuInstanceFlag))
226     {
227         if (kmigmgrIsA100ReducedConfig(pGpu, pKernelMIGManager))
228         {
229             if ((computeSizeFlag != NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_HALF) &&
230                 (computeSizeFlag != NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_QUARTER))
231             {
232                 return NV_FALSE;
233             }
234         }
235         else if (computeSizeFlag != NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_EIGHTH)
236         {
237             return NV_FALSE;
238         }
239     }
240 
241     if (kmigmgrIsA100ReducedConfig(pGpu, pKernelMIGManager) &&
242         ((computeSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_HALF) ||
243          (computeSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_QUARTER)))
244     {
245         return NV_FALSE;
246     }
247 
248     switch (computeSizeFlag)
249     {
250         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_FULL:
251             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_FULL,
252                                NV_FALSE);
253             break;
254         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_HALF:
255             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_HALF,
256                                NV_FALSE);
257             break;
258         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_HALF:
259             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_HALF,
260                                NV_FALSE);
261             break;
262         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_QUARTER:
263             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_QUARTER,
264                                NV_FALSE);
265             break;
266         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_MINI_QUARTER:
267             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_QUARTER,
268                                NV_FALSE);
269             break;
270         case NV2080_CTRL_GPU_PARTITION_FLAG_COMPUTE_SIZE_EIGHTH:
271             NV_CHECK_OR_RETURN(LEVEL_SILENT, memSizeFlag == NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_EIGHTH,
272                                NV_FALSE);
273             break;
274         default:
275             NV_ASSERT(0);
276             return NV_FALSE;
277     }
278 
279     return NV_TRUE;
280 }
281 
282 /*!
283  * @brief   Returns the range of swizzids which can be assigned to a GPU
284  *          instance of the given size.
285  *
286  * @param[IN]   pGpu
287  * @param[IN]   pKernelMIGManager
288  * @param[IN]   memSizeFlag       NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_*
289  */
290 NV_RANGE
291 kmigmgrMemSizeFlagToSwizzIdRange_GA100
292 (
293     OBJGPU *pGpu,
294     KernelMIGManager *pKernelMIGManager,
295     NvU32 memSizeFlag
296 )
297 {
298     NV_RANGE ret;
299 
300     switch (DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG, _MEMORY_SIZE, memSizeFlag))
301     {
302         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_FULL:
303         {
304             ret = rangeMake(0, 0);
305             break;
306         }
307 
308         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_HALF:
309         {
310             ret = rangeMake(1, 2);
311             break;
312         }
313 
314         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_QUARTER:
315         {
316             ret = rangeMake(3, 6);
317             break;
318         }
319 
320         case NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_EIGHTH:
321         {
322             ret = rangeMake(7, 14);
323             break;
324         }
325 
326         default:
327         {
328             NV_PRINTF(LEVEL_ERROR, "Unsupported mem size flag 0x%x\n",
329                       memSizeFlag);
330             DBG_BREAKPOINT();
331             ret = NV_RANGE_EMPTY;
332             break;
333         }
334     }
335     return ret;
336 }
337 /*!
338  * @brief   Checks if user requested a configuration that should require memory partitioning
339  *
340  * @param[IN]   pGpu
341  * @param[IN]   pKernelMIGManager
342  * @param[IN]   partitionFlags    Client request flags
343  */
344 NvBool
345 kmigmgrIsMemoryPartitioningRequested_GA100
346 (
347     OBJGPU *pGpu,
348     KernelMIGManager *pKernelMIGManager,
349     NvU32 partitionFlags
350 )
351 {
352     NvU32 memSizeFlag = DRF_VAL(2080_CTRL_GPU, _PARTITION_FLAG, _MEMORY_SIZE, partitionFlags);
353     return (memSizeFlag != NV2080_CTRL_GPU_PARTITION_FLAG_MEMORY_SIZE_FULL);
354 }
355 
356 /*!
357  * @brief   Checks if memory partitioning will be needed for a given swizzId
358  */
359 NvBool
360 kmigmgrIsMemoryPartitioningNeeded_GA100
361 (
362     OBJGPU *pGpu,
363     KernelMIGManager *pKernelMIGManager,
364     NvU32 swizzId
365 )
366 {
367     // Memory partitioning is needed for non-zero swizzIds
368     return (swizzId != 0);
369 }
370