1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2015-2022 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 /*!
25  * @file
26  * @brief Implementation of the Sync Gpu Boost Manager methods.
27  */
28 
29 /*------------------------------Includes--------------------------------------*/
30 #include "power/gpu_boost_mgr.h"
31 #include "os/os.h"
32 #include "core/locks.h"
33 #include "gpu/gpu_access.h"
34 #include "gpu/gpu.h"
35 #include "syncgpuboost.h"
36 #include "nvlimits.h"
37 #include "gpu_mgr/gpu_mgr.h"
38 #include "gpu/gsp/gsp_static_config.h"
39 #include "vgpu/vgpu_events.h"
40 #include "gpu/perf/kern_perf_gpuboostsync.h"
41 #include "nvdevid.h"
42 
43 /*-----------------------Static Private Method Prototypes---------------------*/
44 static NV_STATUS _gpuboostmgrApplyPolicyFilters(NV0000_SYNC_GPU_BOOST_GROUP_CONFIG *);
45 
46 /*----------------------------Object Methods----------------------------------*/
47 
48 /*!
49  * @brief OBJGPUBOOSTMGR object method to create a Sync Gpu Boost Group (SGBG)
50  *
51  * This method will create a new SGBG if none of the  GPUs specified in the input
52  * params is already a part of another SGBG.
53  *
54  * @param [in]  pBoostConfig                @ref NV0000_SYNC_GPU_BOOST_GROUP_CONFIG
55  * @param [out] pBoostConfig::boostGroupId  If SGBG creation succeeds, this field
56  *                                          has the assigned group ID. This ID is
57  *                                          unique across RM.
58  * @returns     NV_OK                             Success
59  * @returns     NV_ERR_INSUFFICIENT_RESOURCES     No new groups possible.
60  * @returns     NV_ERR_INVALID_STATE              Internal state messed up.
61  * and a few more returned from second level functions.
62  */
63 NV_STATUS
64 gpuboostmgrCreateGroup_IMPL
65 (
66     OBJGPUBOOSTMGR                      *pBoostMgr,
67     NV0000_SYNC_GPU_BOOST_GROUP_CONFIG  *pBoostConfig
68 )
69 {
70     NV_STATUS  status      = NV_OK;
71     NODE      *pGpuIdNode  = NULL;
72     NvBool     bCleanup    = NV_FALSE;
73     NvU32      i;
74 
75     // See if we can accomodate one more SGBG
76     NV_ASSERT_OR_RETURN(pBoostMgr->groupCount < NV0000_SYNC_GPU_BOOST_MAX_GROUPS,
77                           NV_ERR_INSUFFICIENT_RESOURCES);
78 
79     // Check if requested config is valid.
80     status = gpuboostmgrCheckConfig(pBoostMgr, pBoostConfig);
81     if (NV_OK != status)
82     {
83         NV_PRINTF(LEVEL_ERROR,
84                   "Invalid Boost Config. Failing Boost Group creation.\n");
85         NV_ASSERT_OR_GOTO(NV_OK == status, gpuboostmgrCreateGroup_exit);
86     }
87 
88     //
89     // Allocate a @ref SYNC_GPU_BOOST_GROUP for the requested group at the first
90     // available index.
91     //
92     // Note: A linear search is sufficient for practical purposes currently.
93     //
94     for (i = 0; i < NV0000_SYNC_GPU_BOOST_MAX_GROUPS; i++)
95     {
96         // Found an unused index.
97         if (0 == pBoostMgr->pBoostGroups[i].gpuCount)
98         {
99             NvU32 j;
100 
101             // Setup the internal state for the new group
102             for(j = 0; j < pBoostConfig->gpuCount; j++)
103             {
104                 // Allocate GPU ID node.
105                 pGpuIdNode = portMemAllocNonPaged(sizeof(*pGpuIdNode));
106                 if (NULL == pGpuIdNode)
107                 {
108                     bCleanup = NV_TRUE;
109                     NV_ASSERT_OR_GOTO((pGpuIdNode != NULL), gpuboostmgrCreateGroup_exit);
110                 }
111 
112                 // Add each unique GPU ID in the GPU ID tree
113                 portMemSet(pGpuIdNode, 0, sizeof(*pGpuIdNode));
114                 pGpuIdNode->keyStart = pBoostConfig->gpuIds[j];
115                 pGpuIdNode->keyEnd   = pBoostConfig->gpuIds[j];
116                 status               = btreeInsert(pGpuIdNode, &pBoostMgr->pGpuIdTree);
117                 if (NV_OK != status)
118                 {
119                     bCleanup = NV_TRUE;
120                     NV_ASSERT_OR_GOTO(NV_OK == status, gpuboostmgrCreateGroup_exit);
121                 }
122 
123                 pBoostMgr->pBoostGroups[i].gpuIds[j] = pBoostConfig->gpuIds[j];
124             }
125 
126             pBoostMgr->groupCount++;
127             pBoostMgr->pBoostGroups[i].gpuCount    = pBoostConfig->gpuCount;
128             pBoostMgr->pBoostGroups[i].bBridgeless = pBoostConfig->bBridgeless;
129 
130             // Set the out param
131             pBoostConfig->boostGroupId = i;
132 
133             // We are done.
134             break;
135         }
136     }
137 
138     // Since we've come so far, there can't be 0 unused entries
139     if (i == NV0000_SYNC_GPU_BOOST_MAX_GROUPS)
140     {
141         NV_PRINTF(LEVEL_ERROR, "Inconsistency in pBoostGroups state.\n");
142         status = NV_ERR_INVALID_STATE;
143         NV_ASSERT_OR_GOTO(0, gpuboostmgrCreateGroup_exit);
144     }
145 
146 gpuboostmgrCreateGroup_exit:
147     if (bCleanup)
148     {
149         NvU32 k;
150 
151         // Clean up stray state in case of failure
152         for(k = 0; k < pBoostConfig->gpuCount; k++)
153         {
154             btreeSearch(pBoostConfig->gpuIds[k],
155                         &pGpuIdNode,
156                         pBoostMgr->pGpuIdTree);
157             if (NULL != pGpuIdNode)
158             {
159                 btreeUnlink(pGpuIdNode, &pBoostMgr->pGpuIdTree);
160                 portMemFree(pGpuIdNode);
161             }
162         }
163 
164         // Destroy @ref SYNC_GPU_BOOST_GROUP object
165         portMemSet(&(pBoostMgr->pBoostGroups[i]), 0, sizeof(SYNC_GPU_BOOST_GROUP));
166     }
167 
168     return status;
169 }
170 
171 /*!
172  * @brief OBJGPUBOOSTMGR object method to destroy a Sync Gpu Boost Group (SGBG)
173  *
174  * This method will destroy an existing SGBG
175  *
176  * @param [in]  boostGroupId       Unique ID of the SGBG to be destroyed
177 
178  * @returns     NV_OK                     Success
179  * @returns     NV_ERR_ILLEGAL_ACTION     No SGBGs to destroy in the first place
180  *                                        Or the requested SGBG is already destroyed.
181  *  and a few more returned from second level functions.
182  */
183 NV_STATUS
184 gpuboostmgrDestroyGroup_IMPL
185 (
186     OBJGPUBOOSTMGR  *pBoostMgr,
187     NvU32            boostGroupId
188 )
189 {
190     NV_STATUS  status = NV_OK;
191     NODE      *pGpuIdNode = NULL;
192     NvU32      i;
193 
194     // Can't try to destroy a non-existing group
195     NV_ASSERT_OR_RETURN(pBoostMgr->groupCount > 0, NV_ERR_ILLEGAL_ACTION);
196     NV_ASSERT_OR_RETURN(NV0000_SYNC_GPU_BOOST_MAX_GROUPS > boostGroupId, NV_ERR_OUT_OF_RANGE);
197     NV_ASSERT_OR_RETURN(0 != pBoostMgr->pBoostGroups[boostGroupId].gpuCount, NV_ERR_ILLEGAL_ACTION);
198 
199     // Remove each GPU ID from the ID tree before destorying the group.
200     for(i = 0; i < pBoostMgr->pBoostGroups[boostGroupId].gpuCount; i++)
201     {
202         status = btreeSearch(pBoostMgr->pBoostGroups[boostGroupId].gpuIds[i],
203                              &pGpuIdNode,
204                              pBoostMgr->pGpuIdTree);
205         NV_ASSERT_OR_RETURN(((NV_OK == status) && (NULL != pGpuIdNode)), status);
206         btreeUnlink(pGpuIdNode, &pBoostMgr->pGpuIdTree);
207         portMemFree(pGpuIdNode);
208     }
209 
210     // Destroy @ref SYNC_GPU_BOOST_GROUP object
211     portMemSet(&(pBoostMgr->pBoostGroups[boostGroupId]), 0, sizeof(SYNC_GPU_BOOST_GROUP));
212 
213     // Decrement groupCount
214     pBoostMgr->groupCount--;
215 
216     return NV_OK;
217 }
218 
219 /*!
220  * @brief Returns information about each Sync Gpu Boost Group defined in the system
221  */
222 NV_STATUS
223 gpuboostmgrQueryGroups_IMPL
224 (
225     OBJGPUBOOSTMGR                          *pBoostMgr,
226     NV0000_SYNC_GPU_BOOST_GROUP_INFO_PARAMS *pParams
227 )
228 {
229     NvU32     i;
230     NvU32     j;
231 
232     j = 0;
233     for (i = 0; i < NV0000_SYNC_GPU_BOOST_MAX_GROUPS; i++)
234     {
235         if (NV_OK == gpuboostmgrValidateGroupId(pBoostMgr, i))
236         {
237             pParams->pBoostGroups[j].gpuCount     = pBoostMgr->pBoostGroups[i].gpuCount;
238             pParams->pBoostGroups[j].boostGroupId = i;
239             portMemCopy(pParams->pBoostGroups[j].gpuIds,
240                         sizeof(pParams->pBoostGroups[j].gpuIds),
241                         pBoostMgr->pBoostGroups[i].gpuIds,
242                         sizeof(pParams->pBoostGroups[j].gpuIds));
243             j++;
244         }
245     }
246 
247     pParams->groupCount = j;
248 
249     return NV_OK;
250 }
251 
252 /*!
253  * @brief OBJGPUBOOSTMGR object method to validate a config for a Sync Gpu Boost Group (SGBG)
254  *        @ref NV0000_SYNC_GPU_BOOST_GROUP_CONFIG
255  *
256  * The following checks needs to be met for a config to be converted to an SGBG
257  *   1. There is room for a new SGBG to be tracked in RM.
258  *   2. Valid GPU IDs are specified
259  *   3. None of the GPUs specified is already a part of an existing SGBG
260  *
261  * @param [in]  boostConfig                @ref NV0000_SYNC_GPU_BOOST_GROUP_CONFIG
262  *
263  * @returns     NV_OK                             Success
264  * @returns     other values                      Config specified cannot be accepted.
265  */
266 NV_STATUS
267 gpuboostmgrCheckConfig_IMPL
268 (
269     OBJGPUBOOSTMGR                     *pBoostMgr,
270     NV0000_SYNC_GPU_BOOST_GROUP_CONFIG *pBoostConfig
271 )
272 {
273     NV_STATUS  status = NV_OK;
274     OBJGPU    *pGpu   = NULL;
275     NODE      *pNode  = NULL;
276     NvU32      i;
277 
278     NV_ASSERT_OR_RETURN(NULL != pBoostConfig, NV_ERR_INVALID_ARGUMENT);
279 
280     if (0 == pBoostConfig->gpuCount ||
281         NV_MAX_DEVICES < pBoostConfig->gpuCount)
282     {
283         status = NV_ERR_OUT_OF_RANGE;
284         NV_PRINTF(LEVEL_ERROR, "Invalid Gpu Count 0x%x\n", pBoostConfig->gpuCount);
285         DBG_BREAKPOINT();
286         goto gpuboostmgrCheckConfig_exit;
287     }
288 
289     // Policy filters will specify if we can support a given config.
290     status = _gpuboostmgrApplyPolicyFilters(pBoostConfig);
291     NV_ASSERT_OR_GOTO(NV_OK == status, gpuboostmgrCheckConfig_exit);
292 
293     for (i = 0; i < pBoostConfig->gpuCount; i++)
294     {
295         // Check for invalid GPU ID
296         if (NV0000_CTRL_GPU_INVALID_ID == pBoostConfig->gpuIds[i])
297         {
298             status = NV_ERR_INVALID_ARGUMENT;
299             NV_PRINTF(LEVEL_ERROR,
300                       "Invalid GPU ID 0x%x at index 0x%x\n",
301                       pBoostConfig->gpuIds[i], i);
302             DBG_BREAKPOINT();
303             goto gpuboostmgrCheckConfig_exit;
304         }
305 
306         //
307         // Check for OBJGPU being available.
308         //
309         // We do not need to take a GPU lock here, as currently, the API lock
310         // guarantees that OBJ* will not be destroyed while the API
311         // lock is being held. If at all the check needs to read/write OBJGPU state,
312         // we will need the GPU lock.
313         //
314         // We expect that going ahead, client locks will provide similar guarantees
315         // on the GPU state.
316         //
317         pGpu = gpumgrGetGpuFromId(pBoostConfig->gpuIds[i]);
318         if (NULL == pGpu)
319         {
320             status = NV_ERR_INVALID_ARGUMENT;
321             NV_PRINTF(LEVEL_ERROR,
322                       "OBJGPU not constructed yet for ID 0x%x at index 0x%x\n",
323                       pBoostConfig->gpuIds[i], i);
324             DBG_BREAKPOINT();
325             goto gpuboostmgrCheckConfig_exit;
326         }
327 
328         // A GPU cannot be in more than one Boost Group
329         if (NV_OK == btreeSearch(pBoostConfig->gpuIds[i], &pNode, pBoostMgr->pGpuIdTree))
330         {
331             status = NV_ERR_INVALID_ARGUMENT;
332             NV_PRINTF(LEVEL_ERROR,
333                       "GPU with ID 0x%x already in use in another group\n",
334                       pBoostConfig->gpuIds[i]);
335             DBG_BREAKPOINT();
336             goto gpuboostmgrCheckConfig_exit;
337         }
338     }
339 
340 gpuboostmgrCheckConfig_exit:
341     return status;
342 }
343 
344 /*!
345  * @brief Constructor
346  */
347 NV_STATUS
348 gpuboostmgrConstruct_IMPL(OBJGPUBOOSTMGR *pBoostMgr)
349 {
350     return NV_OK;
351 }
352 
353 /*!
354  * @brief Destructor
355  */
356 void
357 gpuboostmgrDestruct_IMPL(OBJGPUBOOSTMGR *pBoostMgr)
358 {
359     btreeDestroyNodes(pBoostMgr->pGpuIdTree);
360     portMemSet(pBoostMgr->pBoostGroups, 0, NV0000_SYNC_GPU_BOOST_MAX_GROUPS * sizeof(SYNC_GPU_BOOST_GROUP));
361     pBoostMgr->groupCount = 0;
362 }
363 
364 
365 /*!
366  * @brief Checks if the boost group ID belongs to a valid Sync Gpu Boost Group
367  *
368  * @param [in] boostGroupId    ID to be checked
369  *
370  * @returns    NV_OK                 group ID belongs to a valid Group.
371  * @returns    NV_ERR_INVALID_INDEX  group ID is not used by  any SGBG
372  */
373 NV_STATUS
374 gpuboostmgrValidateGroupId_IMPL
375 (
376     OBJGPUBOOSTMGR *pBoostMgr,
377     NvU32           boostGroupId
378 )
379 {
380     if (NV0000_SYNC_GPU_BOOST_MAX_GROUPS <= boostGroupId)
381         return NV_ERR_INVALID_INDEX;
382 
383     // If group count is 0, the group index points to an invalid/empty boost group
384     if (0 == pBoostMgr->pBoostGroups[boostGroupId].gpuCount)
385         return NV_ERR_INVALID_INDEX;
386 
387     return NV_OK;
388 }
389 
390 /*!
391  * @brief       Increments the ref count for a Sync Gpu Boost Group
392  *
393  * @param [in]  boostGroupId   ID of the SGBG whose ref count needs incrementing.
394  *
395  * @returns     NV_OK          Ref count incremented successfully
396  *
397  */
398 NV_STATUS
399 gpuboostmgrIncrementRefCount_IMPL
400 (
401     OBJGPUBOOSTMGR *pBoostMgr,
402     NvU32           boostGroupId
403 )
404 {
405     NV_STATUS status = NV_OK;
406 
407     status = gpuboostmgrValidateGroupId(pBoostMgr, boostGroupId);
408     if (NV_OK != status)
409     {
410         NV_PRINTF(LEVEL_ERROR, "Invalid group ID 0x%x\n", boostGroupId);
411         NV_ASSERT_OR_RETURN(0, status);
412     }
413 
414     if (NV_U32_MAX == pBoostMgr->pBoostGroups[boostGroupId].refCount)
415     {
416         NV_PRINTF(LEVEL_ERROR,
417                   "Max limit reached for ref count on group 0x%x\n",
418                   boostGroupId);
419         NV_ASSERT_OR_RETURN(0, NV_ERR_INSUFFICIENT_RESOURCES);
420     }
421 
422     //
423     // Increment the ref count on the SGBG in @ref OJGPUBOOSTMGR
424     // Trigger state change for the SGB Algorithm if this is the first client
425     // referencing the group
426     //
427     pBoostMgr->pBoostGroups[boostGroupId].refCount++;
428     if (1 == pBoostMgr->pBoostGroups[boostGroupId].refCount)
429     {
430         status = kperfGpuBoostSyncStateUpdate(pBoostMgr, boostGroupId, NV_TRUE);
431         if (NV_OK != status)
432         {
433             NV_PRINTF(LEVEL_ERROR,
434                       "Could not activate Sync GPU Boost on group 0x%x. Status: 0x%08x\n",
435                       boostGroupId, status);
436             pBoostMgr->pBoostGroups[boostGroupId].refCount--;
437             NV_ASSERT(0);
438         }
439     }
440 
441     return status;
442 }
443 
444 /*!
445  * @brief       Decrements the ref count for a Sync Gpu Boost
446  * Group
447  *
448  * @param [in]  boostGroupId   ID of the SGBG whose ref count needs decrementing.
449  *
450  * @returns     NV_OK          Ref count decremented successfully
451  *
452  */
453 NV_STATUS
454 gpuboostmgrDecrementRefCount_IMPL
455 (
456     OBJGPUBOOSTMGR *pBoostMgr,
457     NvU32           boostGroupId
458 )
459 {
460     NV_STATUS status = NV_OK;
461 
462     status = gpuboostmgrValidateGroupId(pBoostMgr, boostGroupId);
463     if (NV_OK != status)
464     {
465         NV_PRINTF(LEVEL_ERROR, "Invalid group ID 0x%x\n", boostGroupId);
466         NV_ASSERT_OR_RETURN(0, status);
467     }
468 
469     if (0 == pBoostMgr->pBoostGroups[boostGroupId].refCount)
470     {
471         NV_PRINTF(LEVEL_ERROR, "Ref count on group 0x%x is already 0\n",
472                   boostGroupId);
473         NV_ASSERT_OR_RETURN(0, NV_ERR_INVALID_REQUEST);
474     }
475 
476     //
477     // Decrement the ref count on the SGBG in @ref OJGPUBOOSTMGR
478     // Trigger state change for the SGB Algorithm if this was the last client
479     // referencing the group
480     //
481     pBoostMgr->pBoostGroups[boostGroupId].refCount--;
482     if (0 == pBoostMgr->pBoostGroups[boostGroupId].refCount)
483     {
484         status = kperfGpuBoostSyncStateUpdate(pBoostMgr, boostGroupId, NV_FALSE);
485         if (NV_OK != status)
486         {
487             NV_PRINTF(LEVEL_ERROR,
488                       "Could not deactivate Sync GPU Boost on group 0x%x. Status: 0x%08x\n",
489                       boostGroupId, status);
490             NV_ASSERT(0);
491         }
492     }
493 
494     return status;
495 }
496 
497 /*!
498  * This iterator function return the GPU at given index from the given SGBG
499  *
500  * @params [in] pBoostGrp   Pointer to the SGBG to iterate over
501  * @params [in] grpId       ID of the Boost Group over which to iterate.
502  *                          ID corresponds to index in @ref OBJGPUBOOSTMGR::pBoostGroups
503  * @params [in] pIndex      0 based index into the pBoostGrp, at which the
504  *                          iteration commences.
505  *
506  * @returns  OBJGPU* if a GPU object is found.
507  *           NULL otherwise
508  *
509  * Note: Always pass in an initial index of 0, when beginning the iteration. This
510  *       method lends itself to a while() construct  like so -
511  *       while (NULL != (pGpu = ItrMethod(pBoostGrp, &index)){ //foo };
512  */
513 POBJGPU
514 gpuboostmgrGpuItr_IMPL
515 (
516     OBJGPUBOOSTMGR       *pBoostMgr,
517     NvU32                 grpId,
518     NvU32                *pIndex
519 )
520 {
521     NV_ASSERT_OR_RETURN(NULL != pIndex, NULL);
522 
523     if (0 == pBoostMgr->pBoostGroups[grpId].gpuCount)
524     {
525         NV_PRINTF(LEVEL_ERROR, "Gpu Count is 0 for group ID: 0x%x\n", grpId);
526         return NULL;
527     }
528     if (*pIndex == pBoostMgr->pBoostGroups[grpId].gpuCount)
529     {
530         return NULL;
531     }
532 
533     return gpumgrGetGpuFromId(pBoostMgr->pBoostGroups[grpId].gpuIds[(*pIndex)++]);
534 }
535 
536 /*!
537  * @brief Retrieves the ID of the SGBG to which a GPU belongs
538  *
539  * @param [in]  pBoostMgr
540  * @param [in]  pGpu
541  * @param [out] pBoostGrpId   ID of the @ref SYNC_GPU_BOOST_GROUP to which the
542  *                             given GPU belongs.
543  *                             NV0000_SYNC_GPU_BOOST_INVALID_GROUP_ID value if
544  *                             group is not found
545  *
546  * @return NV_OK                   if SGBG is found
547  * @return NV_ERR_OBJECT_NOT_FOUND if SGBG is not found
548  * @return  NV_ERR_INVALID_ARGUMENT Null or incorrect arguments passed in.
549  */
550 NV_STATUS
551 gpuboostmgrGetBoostGrpIdFromGpu_IMPL
552 (
553     OBJGPUBOOSTMGR *pBoostMgr,
554     OBJGPU         *pGpu,
555     NvU32          *pBoostGrpId
556 )
557 {
558     NvU32   i;
559     NvU32   index = 0;
560     OBJGPU *pGpuTemp = NULL;
561 
562     *pBoostGrpId = NV0000_SYNC_GPU_BOOST_INVALID_GROUP_ID;
563 
564     NV_ASSERT_OR_RETURN(NULL != pGpu, NV_ERR_INVALID_ARGUMENT);
565     NV_ASSERT_OR_RETURN(NULL != pBoostGrpId, NV_ERR_INVALID_ARGUMENT);
566 
567     for (i = 0; i < pBoostMgr->groupCount; i++)
568     {
569         while (NULL != (pGpuTemp = gpuboostmgrGpuItr(pBoostMgr, i, &index)))
570         {
571             if (pGpuTemp->gpuId == pGpu->gpuId)
572             {
573                 *pBoostGrpId = i;
574                 return NV_OK;
575             }
576         }
577     }
578 
579     NV_PRINTF(LEVEL_INFO,
580               "No Boost Group found for the gpu with ID: 0x%08x\n",
581               pGpu->gpuId);
582 
583     return NV_ERR_OBJECT_NOT_FOUND;
584 }
585 
586 /*!
587  * @return NV_TRUE  If the Sync GPU Boost Group at the given ID has the algorithm
588  *                  active.
589  *         NV_FALSE If the group ID is invalid or the algorithm is inactive.
590  */
591 NvBool
592 gpuboostmgrIsBoostGrpActive_IMPL
593 (
594     OBJGPUBOOSTMGR  *pBoostMgr,
595     NvU32            grpId
596 )
597 {
598     if (grpId == NV0000_SYNC_GPU_BOOST_INVALID_GROUP_ID)
599     {
600         return NV_FALSE;
601     }
602 
603     return ((0 != pBoostMgr->pBoostGroups[grpId].gpuCount) &&
604             (0 != pBoostMgr->pBoostGroups[grpId].refCount));
605 }
606 
607 /*------------------------------Static Private Methods------------------------*/
608 
609 /*!
610  * Applies filter policies which determine whether or not to allow the given GPUs
611  * to be in the same SGBG.
612  */
613 static NV_STATUS
614 _gpuboostmgrApplyPolicyFilters(NV0000_SYNC_GPU_BOOST_GROUP_CONFIG *pBoostConfig)
615 {
616     NV_STATUS  status           = NV_ERR_NOT_COMPATIBLE;
617     OBJGPU    *pGpu             = NULL;
618     OBJGPU    *pGpuItr          = NULL;
619     OBJGPUGRP *pGpuGrp          = NULL;
620     NvBool     bIsSli           = NV_TRUE;
621     NvBool     bIsUnlinkedSli   = NV_TRUE;
622     NvBool     bMatchingDevId   = NV_TRUE;
623     NvU32      i;
624 
625     NV_ASSERT_OR_RETURN(NULL != pBoostConfig, NV_ERR_INVALID_ARGUMENT);
626 
627     pGpu = gpumgrGetGpuFromId(pBoostConfig->gpuIds[0]);
628     NV_ASSERT_OR_RETURN(NULL != pGpu, NV_ERR_OBJECT_NOT_FOUND);
629     pGpuGrp = gpumgrGetGpuGrpFromGpu(pGpu);
630 
631     //
632     // Group Filter Policy:
633     // If GPUs are in same SLI device - Allow
634     // else if GPUs have the same (devid, subsystem id, subvendor id, board proj id, board sku id) - Allow
635     // else - Disallow
636     //
637 
638     //
639     // Check if all GPUs are in same SLI Device.
640     // We compare @ref OBJGPUGRP for each GPU as opposed to PBJGPU:deviceInstance
641     // because in the future we may move away from the SLI Device Model.
642     //
643     for (i = 1; i < pBoostConfig->gpuCount; i++)
644     {
645         pGpuItr = gpumgrGetGpuFromId(pBoostConfig->gpuIds[i]);
646         NV_ASSERT_OR_RETURN(NULL != pGpuItr, NV_ERR_OBJECT_NOT_FOUND);
647 
648         if (pGpuGrp == gpumgrGetGpuGrpFromGpu(pGpuItr))
649         {
650             continue;
651         }
652         else
653         {
654             bIsSli = NV_FALSE;
655             break;
656         }
657     }
658     if (bIsSli)
659     {
660         status = NV_OK;
661         goto _gpuboostmgrApplyPolicyFilters_exit;
662     }
663 
664     //
665     // Check if Unlinked SLI is enabled for all GPUs within the group
666     //
667     for (i = 0; i < pBoostConfig->gpuCount; i++)
668     {
669         pGpuItr = gpumgrGetGpuFromId(pBoostConfig->gpuIds[i]);
670         NV_ASSERT_OR_RETURN(NULL != pGpuItr, NV_ERR_OBJECT_NOT_FOUND);
671 
672         if (IsUnlinkedSLIEnabled(pGpuItr))
673         {
674             continue;
675         }
676         else
677         {
678             bIsUnlinkedSli = NV_FALSE;
679             break;
680         }
681     }
682     if (bIsUnlinkedSli)
683     {
684         status = NV_OK;
685         goto _gpuboostmgrApplyPolicyFilters_exit;
686     }
687 
688     //
689     // Check if all the GPUs have same dev id. This needs to be ensured for the Sync
690     // Boost algorithm to provide the expected benefits, unless otherwise specified.
691     //
692     NvU32 pciDevId = 0;
693     NvU64 boardProjNum = 0;
694     NvU64 boardSkuNum  = 0;
695     NvU16 subVendor    = 0;
696     NvU16 subDevice    = 0;
697     GspStaticConfigInfo *pGSCI = NULL;
698 
699     pciDevId = DRF_VAL(_PCI, _DEVID, _DEVICE, pGpu->idInfo.PCIDeviceID);
700 
701     // Cache all necessary values for one of the GPUs
702     {
703         if ( IS_GSP_CLIENT(pGpu) )
704         {
705             pGSCI = GPU_GET_GSP_STATIC_INFO(pGpu);
706         }
707 
708         if ( !IS_GSP_CLIENT(pGpu)  || !pGSCI->bVbiosValid )
709         {
710             status = NV_ERR_NOT_SUPPORTED;
711             NV_ASSERT_OR_GOTO(NV_FALSE, _gpuboostmgrApplyPolicyFilters_exit);
712         }
713 
714         portMemCopy(&boardSkuNum, sizeof(boardSkuNum), pGSCI->SKUInfo.projectSKU, sizeof(pGSCI->SKUInfo.projectSKU));
715         portMemCopy(&boardProjNum, sizeof(boardProjNum), pGSCI->SKUInfo.project, sizeof(pGSCI->SKUInfo.project));
716         subVendor = pGSCI->vbiosSubVendor;
717         subDevice = pGSCI->vbiosSubDevice;
718     }
719 
720     // Compare each GPU's values with the cached values.
721     for (i = 1; i < pBoostConfig->gpuCount; i++)
722     {
723         NvU64 boardProjNumItr = 0;
724         NvU64 boardSkuNumItr  = 0;
725         NvU16 subVendorItr    = 0;
726         NvU16 subDeviceItr    = 0;
727 
728         pGpuItr = gpumgrGetGpuFromId(pBoostConfig->gpuIds[i]);
729         NV_ASSERT_OR_RETURN(NULL != pGpuItr, NV_ERR_OBJECT_NOT_FOUND);
730 
731         // Extract values for the GPU in the iteration.
732         {
733             if ( IS_GSP_CLIENT(pGpuItr) )
734             {
735                 pGSCI = GPU_GET_GSP_STATIC_INFO(pGpuItr);
736             }
737 
738             if ( !IS_GSP_CLIENT(pGpuItr)  || !pGSCI->bVbiosValid )
739             {
740                 status = NV_ERR_OBJECT_NOT_FOUND;
741                 bMatchingDevId = NV_FALSE;
742                 NV_ASSERT_OR_GOTO(NV_FALSE, _gpuboostmgrApplyPolicyFilters_exit);
743             }
744             portMemCopy(&boardSkuNumItr, sizeof(boardSkuNumItr), pGSCI->SKUInfo.projectSKU, sizeof(pGSCI->SKUInfo.projectSKU));
745             portMemCopy(&boardProjNumItr, sizeof(boardProjNumItr), pGSCI->SKUInfo.project, sizeof(pGSCI->SKUInfo.project));
746             subVendorItr = pGSCI->vbiosSubVendor;
747             subDeviceItr = pGSCI->vbiosSubDevice;
748         }
749 
750         // Go to the next GPU if all values match
751         if ((pciDevId     == DRF_VAL(_PCI, _DEVID, _DEVICE, pGpuItr->idInfo.PCIDeviceID)) &&
752             (boardSkuNum  == boardSkuNumItr)  &&
753             (boardProjNum == boardProjNumItr) &&
754             (subVendor    == subVendorItr)    &&
755             (subDevice    == subDeviceItr))
756         {
757             continue;
758         }
759         else
760         {
761             // At least one mismatch.
762             bMatchingDevId = NV_FALSE;
763             break;
764         }
765     }
766     if (bMatchingDevId)
767     {
768         status = NV_OK;
769         goto _gpuboostmgrApplyPolicyFilters_exit;
770     }
771 
772 _gpuboostmgrApplyPolicyFilters_exit:
773     if (status != NV_OK)
774     {
775         NV_PRINTF(LEVEL_ERROR,
776                   "GPUs not compatible to be put in the same group\n");
777         DBG_BREAKPOINT();
778     }
779 
780     return status;
781 }
782 
783 NV_STATUS
784 syncgpuboostConstruct_IMPL
785 (
786     SyncGpuBoost    *pSyncGpuBoost,
787     CALL_CONTEXT    *pCallContext,
788     RS_RES_ALLOC_PARAMS_INTERNAL *pParams
789 )
790 {
791     OBJSYS                  *pSys       = SYS_GET_INSTANCE();
792     OBJGPUBOOSTMGR          *pBoostMgr  = SYS_GET_GPUBOOSTMGR(pSys);
793     NV_STATUS                rmStatus   = NV_OK;
794     NV0060_ALLOC_PARAMETERS *p0060Params = pParams->pAllocParams;
795 
796     NV_ASSERT_OR_RETURN(NULL != p0060Params, NV_ERR_INVALID_ARGUMENT);
797     NV_ASSERT_OK_OR_RETURN(gpuboostmgrIncrementRefCount(pBoostMgr, p0060Params->gpuBoostGroupId));
798 
799     pSyncGpuBoost->gpuBoostGroupId = p0060Params->gpuBoostGroupId;
800 
801     return rmStatus;
802 }
803 
804 void
805 syncgpuboostDestruct_IMPL
806 (
807     SyncGpuBoost *pSyncGpuBoost
808 )
809 {
810     RS_RES_FREE_PARAMS_INTERNAL *pParams = NULL;
811     OBJSYS          *pSys       = SYS_GET_INSTANCE();
812     OBJGPUBOOSTMGR  *pBoostMgr  = SYS_GET_GPUBOOSTMGR(pSys);
813     NV_STATUS        rmStatus   = NV_OK;
814 
815     resGetFreeParams(staticCast(pSyncGpuBoost, RsResource), NULL, &pParams);
816 
817     // Can't do much if ref count decrement failed. Assert and continue deletion.
818     rmStatus = gpuboostmgrDecrementRefCount(pBoostMgr, pSyncGpuBoost->gpuBoostGroupId);
819     NV_ASSERT(NV_OK == rmStatus);
820 
821     pParams->status = rmStatus;
822 
823     return;
824 }
825