1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 2023-2024 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_CONF_COMPUTE_H_PRIVATE_ACCESS_ALLOWED
25 
26 #include "kernel/gpu/conf_compute/conf_compute.h"
27 #include "class/cl2080.h"
28 
29 #include "kernel/gpu/mem_mgr/mem_mgr.h"
30 #include "class/clc86fsw.h"
31 #include "ctrl/ctrl2080/ctrl2080internal.h"
32 #include "nvrm_registry.h"
33 
34 static void initKeyRotationRegistryOverrides(OBJGPU *pGpu, ConfidentialCompute *pConfCompute);
35 static void getKeyPairForKeySpace(NvU32 keySpace, NvBool bKernel, NvU32 *pGlobalH2DKey, NvU32 *pGlobalD2HKey);
36 static NV_STATUS triggerKeyRotationByKeyPair(OBJGPU *pGpu, ConfidentialCompute *pConfCompute, NvU32 h2dKey, NvU32 d2hKey);
37 static NV_STATUS calculateEncryptionStatsByKeyPair(OBJGPU *pGpu, ConfidentialCompute *pConfCompute, NvU32 h2dKey, NvU32 d2hKey);
38 static NV_STATUS notifyKeyRotationByKeyPair(OBJGPU *pGpu, ConfidentialCompute *pConfCompute, NvU32 h2dKey);
39 static NvBool isLowerThresholdCrossed(ConfidentialCompute *pConfCompute, KEY_ROTATION_STATS_INFO *pH2DInfo,
40                                       KEY_ROTATION_STATS_INFO *pD2HInfo);
41 static NvBool isUpperThresholdCrossed(ConfidentialCompute *pConfCompute, KEY_ROTATION_STATS_INFO *pH2DInfo,
42                                       KEY_ROTATION_STATS_INFO *pD2HInfo);
43 static NV_STATUS keyRotationTimeoutCallback(OBJGPU *pGpu, OBJTMR *pTmr, TMR_EVENT *pTmrEvent);
44 
45 /*!
46  * Conditionally enables key rotation support
47  *
48  * @param[in]     pGpu                     : OBJGPU Pointer
49  * @param[in]     pConfCompute             : ConfidentialCompute pointer
50  */
51 NV_STATUS
52 confComputeEnableKeyRotationSupport_GH100
53 (
54     OBJGPU *pGpu,
55     ConfidentialCompute *pConfCompute
56 )
57 {
58 
59     if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_ENABLED) &&
60         pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_CC_FEATURE_ENABLED))
61     {
62         pConfCompute->setProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_KEY_ROTATION_SUPPORTED, NV_TRUE);
63 
64         //
65         // TODO: sbellock default values need to be defined and set separately
66         // for prod flow based on attacker advantage table.
67         //
68         pConfCompute->lowerThreshold.totalBytesEncrypted = NV_U64_MAX;
69         pConfCompute->lowerThreshold.totalEncryptOps = 500;
70         pConfCompute->upperThreshold.totalBytesEncrypted = NV_U64_MAX;
71         pConfCompute->upperThreshold.totalEncryptOps = 1000;
72         initKeyRotationRegistryOverrides(pGpu, pConfCompute);
73     }
74     return NV_OK;
75 }
76 
77 /*!
78  * Enables/disables key rotation by setting up the 1 sec callback for key rotation
79  *
80  * @param[in]     pGpu                     : OBJGPU Pointer
81  * @param[in]     pConfCompute             : ConfidentialCompute pointer
82  * @param[in]     bEnable                  : If key rotation should be enabled
83  */
84 NV_STATUS
85 confComputeEnableKeyRotationCallback_GH100
86 (
87     OBJGPU *pGpu,
88     ConfidentialCompute *pConfCompute,
89     NvBool bEnable
90 )
91 {
92     if (bEnable)
93     {
94         // Hook into the 1 Hz OS timer
95         osSchedule1HzCallback(pGpu,
96                               confComputeKeyRotationCallback,
97                               NULL /* pData */,
98                               NV_OS_1HZ_REPEAT);
99     }
100     else
101     {
102         osRemove1HzCallback(pGpu,
103                             confComputeKeyRotationCallback,
104                             NULL /* pData */);
105     }
106     return NV_OK;
107 }
108 
109  /*!
110   * Calculates encryption statistics and triggers key rotation if thresholds are crossed.
111   *
112   * @param[in]     pGpu                     : OBJGPU Pointer
113   * @param[in]     pConfCompute             : ConfidentialCompute pointer
114   */
115 NV_STATUS
116 confComputeTriggerKeyRotation_GH100
117 (
118     OBJGPU *pGpu,
119     ConfidentialCompute *pConfCompute
120 )
121 {
122     NV_STATUS tempStatus, status = NV_OK;
123     NvU32 globalD2HKey, globalH2DKey, keySpace;
124 
125     if ((pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED)) &&
126         (pConfCompute->keyRotationChannelRefCount > 0))
127     {
128         pConfCompute->keyRotationCallbackCount++;
129         NV_PRINTF(LEVEL_ERROR, "DUMMY KR: COUNT = %d\n", pConfCompute->keyRotationCallbackCount);
130     }
131     for (keySpace = 0; keySpace < CC_KEYSPACE_SIZE; keySpace++)
132     {
133         if (keySpace == CC_KEYSPACE_GSP)
134             continue;
135 
136         if ((pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED)) &&
137             !(pConfCompute->keyRotationEnableMask & NVBIT(keySpace)))
138         {
139             NV_PRINTF(LEVEL_INFO, "Skipping keyspace = %d since mask = 0x%x\n", keySpace, pConfCompute->keyRotationEnableMask);
140             continue;
141         }
142 
143         // calculate kernel channels stats for keyspace
144         if ((!pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED)) ||
145             (FLD_TEST_DRF(_REG_STR, _RM_CONF_COMPUTE_DUMMY_KEY_ROTATION, _KERNEL_KEYS, _YES, pConfCompute->keyRotationEnableMask)))
146         {
147             getKeyPairForKeySpace(keySpace, NV_TRUE, &globalH2DKey, &globalD2HKey);
148             tempStatus = triggerKeyRotationByKeyPair(pGpu, pConfCompute, globalH2DKey, globalD2HKey);
149             if (tempStatus != NV_OK)
150             {
151                 NV_ASSERT(tempStatus == NV_OK);
152                 NV_PRINTF(LEVEL_ERROR, "Failed to calculate encryption statistics for H2D key 0x%x with status 0x%x\n", globalH2DKey, tempStatus);
153                 status = tempStatus;
154             }
155         }
156 
157         // calculate user channels stats for keyspace
158         if ((!pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED)) ||
159             (FLD_TEST_DRF(_REG_STR, _RM_CONF_COMPUTE_DUMMY_KEY_ROTATION, _USER_KEYS, _YES, pConfCompute->keyRotationEnableMask)))
160         {
161             getKeyPairForKeySpace(keySpace, NV_FALSE, &globalH2DKey, &globalD2HKey);
162             tempStatus = triggerKeyRotationByKeyPair(pGpu, pConfCompute, globalH2DKey, globalD2HKey);
163             if (tempStatus != NV_OK)
164             {
165                 NV_ASSERT(tempStatus == NV_OK);
166                 NV_PRINTF(LEVEL_ERROR, "Failed to calculate encryption statistics for H2D key 0x%x with status 0x%x\n", globalH2DKey, tempStatus);
167                 status = tempStatus;
168             }
169         }
170     }
171     return status;
172 }
173 
174 static NV_STATUS
175 triggerKeyRotationByKeyPair
176 (
177     OBJGPU *pGpu,
178     ConfidentialCompute *pConfCompute,
179     NvU32 h2dKey,
180     NvU32 d2hKey
181 )
182 {
183     KEY_ROTATION_STATUS state;
184     NV_ASSERT_OK_OR_RETURN(confComputeGetKeyRotationStatus(pConfCompute, h2dKey, &state));
185     CHANNEL_ITERATOR iter = {0};
186     KernelChannel *pKernelChannel = NULL;
187     NvU32 h2dIndex, d2hIndex;
188 
189     // we won't need this once we have encryption statistics since unused keys will have stats = 0
190     if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED))
191     {
192         NV_ASSERT_OK_OR_RETURN(confComputeInitChannelIterForKey(pGpu, pConfCompute, h2dKey, &iter));
193         if (confComputeGetNextChannelForKey(pGpu, pConfCompute, &iter, h2dKey, &pKernelChannel) != NV_OK)
194         {
195             //
196             // If this is the last key and we haven't done KR yet even after crossing upper threshold then
197             // it means there are no channels alive and we need to manually reset our counter
198             //
199             if ((h2dKey == CC_GKEYID_GEN(CC_KEYSPACE_LCE7, CC_LKEYID_LCE_H2D_USER)) &&
200                 (pConfCompute->keyRotationCallbackCount > pConfCompute->upperThreshold.totalEncryptOps))
201             {
202                 pConfCompute->keyRotationCallbackCount = 1;
203             }
204             return NV_OK;
205         }
206     }
207 
208     //
209     // If key rotation is alredy scheduled because we crossed upper threshold or hit timeout
210     // then we dont need to update encryption statistics as they will be zeroed out soon.
211     //
212     if ((state == KEY_ROTATION_STATUS_FAILED_THRESHOLD) ||
213         (state == KEY_ROTATION_STATUS_FAILED_TIMEOUT))
214     {
215         return NV_OK;
216     }
217 
218     //
219     // CC session doesn't exist if key rotation failed
220     // TODO CONFCOMP-984: RC all channels and other cleanup (kpadwal is working on adding this call)
221     //
222     if (state == KEY_ROTATION_STATUS_FAILED_ROTATION)
223         return NV_ERR_INVALID_STATE;
224 
225     NV_ASSERT_OK_OR_RETURN(calculateEncryptionStatsByKeyPair(pGpu, pConfCompute, h2dKey, d2hKey));
226 
227     NV_ASSERT_OK_OR_RETURN(confComputeGetKeySlotFromGlobalKeyId(pConfCompute, h2dKey, &h2dIndex));
228     NV_ASSERT_OK_OR_RETURN(confComputeGetKeySlotFromGlobalKeyId(pConfCompute, d2hKey, &d2hIndex));
229 
230     if (isUpperThresholdCrossed(pConfCompute, &pConfCompute->aggregateStats[h2dIndex],
231                                 &pConfCompute->aggregateStats[d2hIndex]))
232     {
233         NV_PRINTF(LEVEL_ERROR, "Crossed UPPER threshold for key = 0x%x\n", h2dKey);
234         NV_ASSERT_OK_OR_RETURN(confComputeSetKeyRotationStatus(pConfCompute, h2dKey, KEY_ROTATION_STATUS_FAILED_THRESHOLD));
235         NV_ASSERT_OK_OR_RETURN(confComputeScheduleKeyRotationWorkItem(pGpu, pConfCompute, h2dKey, d2hKey));
236     }
237     else if (isLowerThresholdCrossed(pConfCompute, &pConfCompute->aggregateStats[h2dIndex],
238                                      &pConfCompute->aggregateStats[d2hIndex]))
239     {
240         NV_PRINTF(LEVEL_INFO, "Crossed LOWER threshold for key = 0x%x\n", h2dKey);
241         if (state == KEY_ROTATION_STATUS_IDLE)
242         {
243             NV_ASSERT_OK_OR_RETURN(confComputeSetKeyRotationStatus(pConfCompute, h2dKey, KEY_ROTATION_STATUS_PENDING));
244 
245             //
246             // Start the timeout timer once lower threshold is crossed.
247             //
248             // If timer is not already created then create it now. Else, just schedule a callback.
249             // make sure callback is canceled if we schedule the KR task (after crossing lower or upper threshold)
250             // make sure all these timer events are deleted as part of RM shutdown
251             //
252             OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
253             if (pConfCompute->ppKeyRotationTimer[h2dIndex] == NULL)
254             {
255                 NvU32 *pH2DKey = portMemAllocNonPaged(sizeof(NvU32));
256                 *pH2DKey = h2dKey;
257                 NV_ASSERT_OK_OR_RETURN(tmrEventCreate(pTmr, &pConfCompute->ppKeyRotationTimer[h2dIndex],
258                                                       keyRotationTimeoutCallback, (void*)pH2DKey, TMR_FLAGS_NONE));
259             }
260 
261             //
262             // Schedule first callback.
263             // TODO sbellock: don't use hardcoded 12.5 sec vaule
264             //
265             NV_ASSERT_OK_OR_RETURN(tmrEventScheduleRelSec(pTmr, pConfCompute->ppKeyRotationTimer[h2dIndex], 12.5));
266 
267             //
268             // Notify clients of pending KR
269             // We can't schedule a workitem for this since it may get scheduled too late and
270             // we might have already crossed the upper threshold by then.
271             //
272             NV_ASSERT_OK_OR_RETURN(notifyKeyRotationByKeyPair(pGpu, pConfCompute, h2dKey));
273         }
274     }
275     return NV_OK;
276 }
277 
278 static NV_STATUS
279 keyRotationTimeoutCallback
280 (
281     OBJGPU *pGpu,
282     OBJTMR *pTmr,
283     TMR_EVENT *pEvent
284 )
285 {
286     ConfidentialCompute *pConfCompute = GPU_GET_CONF_COMPUTE(pGpu);
287     NvU32 h2dKey, d2hKey;
288     NvU32 key = *(NvU32*)pEvent->pUserData;
289     confComputeGetKeyPairByKey(pConfCompute, key, &h2dKey, &d2hKey);
290     NV_ASSERT_OK_OR_RETURN(confComputeSetKeyRotationStatus(pConfCompute, h2dKey, KEY_ROTATION_STATUS_FAILED_TIMEOUT));
291     return confComputeScheduleKeyRotationWorkItem(pGpu, pConfCompute, h2dKey, d2hKey);
292 }
293 
294 static NV_STATUS
295 calculateEncryptionStatsByKeyPair
296 (
297     OBJGPU *pGpu,
298     ConfidentialCompute *pConfCompute,
299     NvU32 h2dKey,
300     NvU32 d2hKey
301 )
302 {
303     CHANNEL_ITERATOR iter = {0};
304     NvU64 totalH2Dbytes = 0;
305     NvU64 totalD2Hbytes = 0;
306     NvU64 totalEncryptOpsH2D = 0;
307     NvU64 totalEncryptOpsD2H = 0;
308     NvU32 h2dIndex, d2hIndex;
309 
310     // Iterate through all channels using the key pair and compute totals
311     KernelChannel *pKernelChannel = NULL;
312 
313     NV_ASSERT_OK_OR_RETURN(confComputeGetKeySlotFromGlobalKeyId(pConfCompute, h2dKey, &h2dIndex));
314     NV_ASSERT_OK_OR_RETURN(confComputeGetKeySlotFromGlobalKeyId(pConfCompute, d2hKey, &d2hIndex));
315 
316     NV_ASSERT_OK_OR_RETURN(confComputeInitChannelIterForKey(pGpu, pConfCompute, h2dKey, &iter));
317     while(confComputeGetNextChannelForKey(pGpu, pConfCompute, &iter, h2dKey, &pKernelChannel) == NV_OK)
318     {
319         // TODO: Make this fatal
320         if (pKernelChannel->pEncStatsBufMemDesc == NULL)
321             continue;
322 
323         CC_CRYPTOBUNDLE_STATS *pEncStats = pKernelChannel->pEncStatsBuf;
324         if (pEncStats == NULL)
325         {
326             NV_ASSERT(pEncStats != NULL);
327             NV_PRINTF(LEVEL_ERROR, "Failed to get stats for chid = 0x%x RM engineId = 0x%x\n",
328                 kchannelGetDebugTag(pKernelChannel), kchannelGetEngineType(pKernelChannel));
329             return NV_ERR_INVALID_STATE;
330         }
331         totalH2Dbytes += pEncStats->bytesEncryptedH2D;
332         totalD2Hbytes += pEncStats->bytesEncryptedD2H;
333         totalEncryptOpsH2D += pEncStats->numEncryptionsH2D;
334         totalEncryptOpsD2H += pEncStats->numEncryptionsD2H;
335         NV_PRINTF(LEVEL_INFO, "Encryption stats for chid 0x%x with h2dKey 0x%x\n", kchannelGetDebugTag(pKernelChannel), h2dKey);
336         NV_PRINTF(LEVEL_INFO, "Total h2d bytes encrypted  = 0x%llx\n", pEncStats->bytesEncryptedH2D);
337         NV_PRINTF(LEVEL_INFO, "Total d2h bytes encrypted  = 0x%llx\n", pEncStats->bytesEncryptedD2H);
338         NV_PRINTF(LEVEL_INFO, "Total h2d encrypt ops  = 0x%llx\n", pEncStats->numEncryptionsH2D);
339         NV_PRINTF(LEVEL_INFO, "Total d2h encrypt ops  = 0x%llx\n", pEncStats->numEncryptionsD2H);
340     }
341 
342     // Add stats for freed channels
343     totalH2Dbytes      += pConfCompute->freedChannelAggregateStats[h2dIndex].totalBytesEncrypted;
344     totalEncryptOpsH2D += pConfCompute->freedChannelAggregateStats[h2dIndex].totalEncryptOps;
345     totalD2Hbytes      += pConfCompute->freedChannelAggregateStats[d2hIndex].totalBytesEncrypted;
346     totalEncryptOpsD2H += pConfCompute->freedChannelAggregateStats[d2hIndex].totalEncryptOps;
347 
348     pConfCompute->aggregateStats[h2dIndex].totalBytesEncrypted = totalH2Dbytes;
349     pConfCompute->aggregateStats[h2dIndex].totalEncryptOps     = totalEncryptOpsH2D;
350     pConfCompute->aggregateStats[d2hIndex].totalBytesEncrypted = totalD2Hbytes;
351     pConfCompute->aggregateStats[d2hIndex].totalEncryptOps     = totalEncryptOpsD2H;
352 
353     if ((pConfCompute->aggregateStats[h2dIndex].totalBytesEncrypted > 0) ||
354         (pConfCompute->aggregateStats[d2hIndex].totalBytesEncrypted > 0))
355     {
356         NV_PRINTF(LEVEL_INFO, "Aggregate stats for h2dKey 0x%x and d2hKey 0x%x\n", h2dKey, d2hKey);
357         NV_PRINTF(LEVEL_INFO, "Total h2d bytes encrypted  = 0x%llx\n", pConfCompute->aggregateStats[h2dIndex].totalBytesEncrypted);
358         NV_PRINTF(LEVEL_INFO, "Total d2h bytes encrypted  = 0x%llx\n", pConfCompute->aggregateStats[h2dIndex].totalEncryptOps);
359         NV_PRINTF(LEVEL_INFO, "Total h2d encrypt ops  = 0x%llx\n", pConfCompute->aggregateStats[d2hIndex].totalBytesEncrypted);
360         NV_PRINTF(LEVEL_INFO, "Total d2h encrypt ops  = 0x%llx\n", pConfCompute->aggregateStats[d2hIndex].totalEncryptOps);
361     }
362     return NV_OK;
363 }
364 
365 static NvBool
366 isUpperThresholdCrossed
367 (
368     ConfidentialCompute *pConfCompute,
369     KEY_ROTATION_STATS_INFO *pH2DInfo,
370     KEY_ROTATION_STATS_INFO *pD2HInfo
371 )
372 {
373     if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED))
374     {
375         return (pConfCompute->keyRotationCallbackCount > pConfCompute->upperThreshold.totalEncryptOps);
376     }
377     else
378     {
379         return (confComputeIsUpperThresholdCrossed(pConfCompute, pH2DInfo) ||
380                 confComputeIsUpperThresholdCrossed(pConfCompute, pD2HInfo));
381     }
382 }
383 
384 static NvBool
385 isLowerThresholdCrossed
386 (
387     ConfidentialCompute *pConfCompute,
388     KEY_ROTATION_STATS_INFO *pH2DInfo,
389     KEY_ROTATION_STATS_INFO *pD2HInfo
390 )
391 {
392     if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED))
393     {
394         return (pConfCompute->keyRotationCallbackCount > pConfCompute->lowerThreshold.totalEncryptOps);
395     }
396     else
397     {
398         return (confComputeIsLowerThresholdCrossed(pConfCompute, pH2DInfo) ||
399                 confComputeIsLowerThresholdCrossed(pConfCompute, pD2HInfo));
400     }
401 }
402 
403 static void
404 getKeyPairForKeySpace(NvU32 keySpace, NvBool bKernel, NvU32 *pGlobalH2DKey, NvU32 *pGlobalD2HKey)
405 {
406     NvU32 localH2DKey, localD2HKey;
407     if (keySpace == CC_KEYSPACE_SEC2)
408     {
409         if (bKernel)
410         {
411             localH2DKey = CC_LKEYID_CPU_SEC2_DATA_KERN;
412             localD2HKey = CC_LKEYID_CPU_SEC2_HMAC_KERN;
413         }
414         else
415         {
416             localH2DKey = CC_LKEYID_CPU_SEC2_DATA_USER;
417             localD2HKey = CC_LKEYID_CPU_SEC2_HMAC_USER;
418         }
419     }
420     else
421     {
422         if (bKernel)
423         {
424             localH2DKey = CC_LKEYID_LCE_H2D_KERN;
425             localD2HKey = CC_LKEYID_LCE_D2H_KERN;
426         }
427         else
428         {
429             localH2DKey = CC_LKEYID_LCE_H2D_USER;
430             localD2HKey = CC_LKEYID_LCE_D2H_USER;
431         }
432     }
433     *pGlobalH2DKey = CC_GKEYID_GEN(keySpace, localH2DKey);
434     *pGlobalD2HKey = CC_GKEYID_GEN(keySpace, localD2HKey);
435 }
436 
437 static NV_STATUS
438 notifyKeyRotationByKeyPair
439 (
440     OBJGPU *pGpu,
441     ConfidentialCompute *pConfCompute,
442     NvU32 h2dKey
443 )
444 {
445     KEY_ROTATION_STATUS status;
446     CHANNEL_ITERATOR iter = {0};
447     KernelChannel *pKernelChannel = NULL;
448     NvU32 notifyStatus = 0;
449     NV_ASSERT_OK_OR_RETURN(confComputeGetKeyRotationStatus(pConfCompute, h2dKey, &status));
450     //
451     // We expect this work item to be called soon after RM detects lower threshold is
452     // crossed and schedules this.
453     //
454     NV_ASSERT_OR_RETURN(status == KEY_ROTATION_STATUS_PENDING, NV_ERR_INVALID_STATE);
455 
456 	// notify all channels
457 	NV_ASSERT_OK_OR_RETURN(confComputeInitChannelIterForKey(pGpu, pConfCompute, h2dKey, &iter));
458 	while(confComputeGetNextChannelForKey(pGpu, pConfCompute, &iter, h2dKey, &pKernelChannel) == NV_OK)
459 	{
460 		// update notifier memory
461 		notifyStatus =
462 			FLD_SET_DRF(_CHANNELGPFIFO, _NOTIFICATION_STATUS, _IN_PROGRESS, _TRUE, notifyStatus);
463 
464 		notifyStatus =
465 			FLD_SET_DRF_NUM(_CHANNELGPFIFO, _NOTIFICATION_STATUS, _VALUE, status, notifyStatus);
466 
467 		NV_ASSERT_OK_OR_RETURN(kchannelUpdateNotifierMem(pKernelChannel, NV_CHANNELGPFIFO_NOTIFICATION_TYPE_KEY_ROTATION_STATUS,
468 											             0, 0, notifyStatus));
469 		NV_PRINTF(LEVEL_INFO, "chid 0x%x has pending key rotation, writing notifier with val 0x%x\n", kchannelGetDebugTag(pKernelChannel), (NvU32)notifyStatus);
470 
471 		// send events to clients if registered
472 		kchannelNotifyEvent(pKernelChannel, NVC86F_NOTIFIERS_KEY_ROTATION, 0, status, NULL, 0);
473 	}
474     return NV_OK;
475 }
476 
477 static void
478 initKeyRotationRegistryOverrides
479 (
480     OBJGPU *pGpu,
481     ConfidentialCompute *pConfCompute
482 )
483 {
484     //
485     // Temp CONFCOMP-984: This will be removed once all RM clients support
486     // key rotation by default.
487     //
488     if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_KEY_ROTATION_SUPPORTED))
489     {
490         NvU32 data;
491         if (osReadRegistryDword(pGpu, NV_REG_STR_RM_CONF_COMPUTE_DUMMY_KEY_ROTATION, &data) == NV_OK)
492         {
493             if (FLD_TEST_DRF(_REG_STR, _RM_CONF_COMPUTE_DUMMY_KEY_ROTATION, _ENABLED, _YES, data))
494             {
495                 NV_PRINTF(LEVEL_INFO, "Confidential Compute dummy key rotation enabled via regkey override.\n");
496                 pConfCompute->setProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED, NV_TRUE);
497             }
498             else if (FLD_TEST_DRF(_REG_STR, _RM_CONF_COMPUTE_DUMMY_KEY_ROTATION, _ENABLED, _NO, data))
499             {
500                 NV_PRINTF(LEVEL_INFO, "Confidential Compute dummy key rotation disabled via regkey override.\n");
501                 pConfCompute->setProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED, NV_FALSE);
502             }
503             if (pConfCompute->getProperty(pConfCompute, PDB_PROP_CONFCOMPUTE_DUMMY_KEY_ROTATION_ENABLED))
504             {
505                 pConfCompute->keyRotationEnableMask = data;
506 
507                 //
508                 // Set lower and upper thresholds to default values
509                 // this will go away once we stop supporting dummy KR
510                 //
511                 pConfCompute->lowerThreshold.totalBytesEncrypted = NV_U64_MAX;
512                 pConfCompute->lowerThreshold.totalEncryptOps = KEY_ROTATION_LOWER_THRESHOLD;
513                 pConfCompute->upperThreshold.totalBytesEncrypted = NV_U64_MAX;
514                 pConfCompute->upperThreshold.totalEncryptOps = KEY_ROTATION_UPPER_THRESHOLD;
515 
516                 if (osReadRegistryDword(pGpu, NV_REG_STR_RM_CONF_COMPUTE_DUMMY_KEY_ROTATION_LOWER_THRESHOLD, &data) == NV_OK)
517                 {
518                     pConfCompute->lowerThreshold.totalEncryptOps = data;
519                 }
520 
521                 if (osReadRegistryDword(pGpu, NV_REG_STR_RM_CONF_COMPUTE_DUMMY_KEY_ROTATION_UPPER_THRESHOLD, &data) == NV_OK)
522                 {
523                     pConfCompute->upperThreshold.totalEncryptOps = data;
524                 }
525             }
526         }
527     }
528 }