1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-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 /********************************* DMA Manager *****************************\
25 *                                                                           *
26 *   Method notifications are handled in this module.  DMA report and OS     *
27 *   action are dealt with on a per-object basis.                            *
28 *                                                                           *
29 ****************************************************************************/
30 
31 #include "core/core.h"
32 #include "gpu/gpu.h"
33 #include "gpu/mem_mgr/virt_mem_allocator.h"
34 #include "gpu/mem_mgr/virt_mem_allocator_common.h"
35 #include "gpu/mem_mgr/context_dma.h"
36 #include "os/os.h"
37 #include "objtmr.h"
38 #include "gpu/device/device.h"
39 #include "gpu/bus/kern_bus.h"
40 #include "gpu/mem_mgr/mem_mgr.h"
41 #include "platform/sli/sli.h"
42 
43 //---------------------------------------------------------------------------
44 //
45 //  Notification completion.
46 //
47 //---------------------------------------------------------------------------
48 
notifyMethodComplete(OBJGPU * pGpu,ChannelDescendant * pObject,NvU32 Offset,NvV32 Data,NvU32 info32,NvU16 info16,NV_STATUS CompletionStatus)49 void notifyMethodComplete
50 (
51     OBJGPU   *pGpu,
52     ChannelDescendant *pObject,
53     NvU32     Offset,
54     NvV32     Data,
55     NvU32     info32,
56     NvU16     info16,
57     NV_STATUS CompletionStatus
58 )
59 {
60     if (pObject->bNotifyTrigger)
61     {
62         pObject->bNotifyTrigger = NV_FALSE;
63 
64         //
65         // Do any OS specified action related to this notification.
66         //
67         if (pObject->notifyAction)
68         {
69             PEVENTNOTIFICATION pEventNotifications = inotifyGetNotificationList(staticCast(pObject, INotifier));
70             notifyEvents(pGpu, pEventNotifications, 0, Offset, Data, CompletionStatus, pObject->notifyAction);
71         }
72     }
73 }
74 
notifyWriteNotifier(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU64 Offset,NvBool TimeSupplied,NvU64 Time)75 static NV_STATUS notifyWriteNotifier
76 (
77     OBJGPU    *pGpu,
78     ContextDma *NotifyXlate,
79     NvV32      Info32,
80     NvV16      Info16,
81     NV_STATUS  CompletionStatus,
82     NvU64      Offset,
83     NvBool     TimeSupplied,
84     NvU64      Time
85 )
86 {
87     NV_STATUS status;
88     NOTIFICATION *pNotifyBuffer;
89 
90     //
91     // Fill in the notification structure.
92     //
93     status = ctxdmaGetKernelVA( NotifyXlate, Offset, sizeof(*pNotifyBuffer),
94         (void **)&(pNotifyBuffer),
95         gpumgrGetSubDeviceInstanceFromGpu(gpumgrGetParentGPU(pGpu)));
96 
97     if (status != NV_OK)
98     {
99         return status;
100     }
101 
102     notifyFillNOTIFICATION(pGpu, pNotifyBuffer, Info32, Info16,
103                            CompletionStatus, TimeSupplied, Time);
104     return status;
105 }
106 
107 void
notifyFillNOTIFICATION(OBJGPU * pGpu,NOTIFICATION * pNotifyBuffer,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvBool TimeSupplied,NvU64 Time)108 notifyFillNOTIFICATION
109 (
110     OBJGPU       *pGpu,
111     NOTIFICATION *pNotifyBuffer,
112     NvV32         Info32,
113     NvV16         Info16,
114     NV_STATUS     CompletionStatus,
115     NvBool        TimeSupplied,
116     NvU64         Time
117 )
118 {
119     INFO16_STATUS infoStatus;
120     NvU32         TimeHi, TimeLo;
121 
122     if (!TimeSupplied)
123     {
124         OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
125         tmrGetCurrentTime(pTmr, &Time);
126     }
127 
128     TimeLo = NvU64_LO32(Time);
129     TimeHi = NvU64_HI32(Time);
130 
131     //
132     // Since notifiers are not read by the GPU, and only the CPU, these
133     // writes to not need to be flushed. A subsequent CPU read to this data
134     // will be serialized with these writes
135     //
136     MEM_WR32(&pNotifyBuffer->OtherInfo32, Info32);
137     MEM_WR32(&pNotifyBuffer->TimeHi, TimeHi);
138     MEM_WR32(&pNotifyBuffer->TimeLo, TimeLo);
139 
140     //
141     // Combine into 32b write to avoid issues in environments that don't
142     // support 16b writes.  For example, when routing all memory requests
143     // through IFB we are limited to 32b read/writes only.
144     //
145     infoStatus.Info16Status_16.Status = (NvV16) CompletionStatus;
146     infoStatus.Info16Status_16.OtherInfo16 = Info16;
147     MEM_WR32(&pNotifyBuffer->Info16Status.Info16Status_32,
148              infoStatus.Info16Status_32);
149 }
150 
151 void
notifyFillNvNotification(OBJGPU * pGpu,NvNotification * pNotification,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvBool TimeSupplied,NvU64 Time)152 notifyFillNvNotification
153 (
154     OBJGPU         *pGpu,
155     NvNotification *pNotification,
156     NvV32           Info32,
157     NvV16           Info16,
158     NV_STATUS       CompletionStatus,
159     NvBool          TimeSupplied,
160     NvU64           Time
161 )
162 {
163     NvU32 TimeHi, TimeLo;
164 
165     if (!TimeSupplied)
166     {
167         OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
168         tmrGetCurrentTime(pTmr, &Time);
169     }
170 
171     TimeLo = NvU64_LO32(Time);
172     TimeHi = NvU64_HI32(Time);
173 
174     //
175     // Since notifiers are not read by the GPU, and only the CPU, these
176     // writes do not need to be flushed. A subsequent CPU read to this data
177     // will be serialized with these writes
178     //
179     MEM_WR16(&pNotification->info16, Info16);
180     MEM_WR32(&pNotification->info32, Info32);
181     MEM_WR32(&pNotification->timeStamp.nanoseconds[0], TimeHi);
182     MEM_WR32(&pNotification->timeStamp.nanoseconds[1], TimeLo);
183     MEM_WR16(&pNotification->status, CompletionStatus);
184 }
185 
notifyFillNotifier(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus)186 NV_STATUS notifyFillNotifier
187 (
188     OBJGPU    *pGpu,
189     ContextDma *NotifyXlate,
190     NvV32      Info32,
191     NvV16      Info16,
192     NV_STATUS  CompletionStatus
193 )
194 {
195     return notifyWriteNotifier(pGpu, NotifyXlate, Info32,
196                                Info16, CompletionStatus,
197                                0, NV_FALSE, 0);
198 }
199 
notifyFillNotifierOffsetTimestamp(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU64 Offset,NvU64 Time)200 NV_STATUS notifyFillNotifierOffsetTimestamp
201 (
202     OBJGPU    *pGpu,
203     ContextDma *NotifyXlate,
204     NvV32      Info32,
205     NvV16      Info16,
206     NV_STATUS  CompletionStatus,
207     NvU64      Offset,
208     NvU64      Time
209 )
210 {
211     return notifyWriteNotifier(pGpu, NotifyXlate, Info32,
212                                Info16, CompletionStatus,
213                                Offset,
214                                NV_TRUE, Time);
215 }
216 
notifyFillNotifierOffset(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU64 Offset)217 NV_STATUS notifyFillNotifierOffset
218 (
219     OBJGPU    *pGpu,
220     ContextDma *NotifyXlate,
221     NvV32      Info32,
222     NvV16      Info16,
223     NV_STATUS  CompletionStatus,
224     NvU64      Offset
225 )
226 {
227     return notifyWriteNotifier(pGpu, NotifyXlate, Info32,
228                                Info16, CompletionStatus,
229                                Offset,
230                                NV_FALSE, 0);
231 }
232 
notifyFillNotifierArrayTimestamp(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index,NvU64 Time)233 NV_STATUS notifyFillNotifierArrayTimestamp
234 (
235     OBJGPU    *pGpu,
236     ContextDma *NotifyXlate,
237     NvV32      Info32,
238     NvV16      Info16,
239     NV_STATUS  CompletionStatus,
240     NvU32      Index,
241     NvU64      Time
242 )
243 {
244     return notifyWriteNotifier(pGpu, NotifyXlate, Info32,
245                                Info16, CompletionStatus,
246                                Index * sizeof(NOTIFICATION),
247                                NV_TRUE, Time);
248 }
249 
notifyFillNotifierArray(OBJGPU * pGpu,ContextDma * NotifyXlate,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index)250 NV_STATUS notifyFillNotifierArray
251 (
252     OBJGPU    *pGpu,
253     ContextDma *NotifyXlate,
254     NvV32      Info32,
255     NvV16      Info16,
256     NV_STATUS  CompletionStatus,
257     NvU32      Index
258 )
259 {
260     return notifyWriteNotifier(pGpu, NotifyXlate, Info32,
261                                Info16, CompletionStatus,
262                                Index * sizeof(NOTIFICATION),
263                                NV_FALSE, 0);
264 }
265 
266 /*
267  * @brief fills notifier at GPU VA base + index with given info,
268  * time and completion status
269  *
270  * Looks up dma memory mapping with given GPU VA and performs writes.
271  * Notifier write is skipped when CPU kernel mapping is missing.
272  *
273  * @param[in] pGpu              OBJGPU pointer
274  * @param[in] pDevice           Device pointer
275  * @param[in] hMemoryCtx        Handle of a memory object to which NotifyGPUVABase belongs
276  * @param[in] NotifyGPUVABase   64b GPU VA base address of semaphore
277  * @param[in] Info32            32b info part
278  * @param[in] Info16            16b info part
279  * @param[in] CompletionStatus  NV_STATUS value to write to notifier status
280  * @param[in] Index             index of notifier in notifier array
281  * @param[in] Time              64b time stamp
282  *
283  * @return NV_ERR_INVALID_ADDRESS on wrong GPU VA address or out of bound index,
284  *         NV_OK on success
285  *
286  */
notifyFillNotifierGPUVATimestamp(OBJGPU * pGpu,Device * pDevice,NvHandle hMemoryCtx,NvU64 NotifyGPUVABase,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index,NvU64 Time)287 NV_STATUS notifyFillNotifierGPUVATimestamp
288 (
289     OBJGPU    *pGpu,
290     Device    *pDevice,
291     NvHandle   hMemoryCtx,
292     NvU64      NotifyGPUVABase,
293     NvV32      Info32,
294     NvV16      Info16,
295     NV_STATUS  CompletionStatus,
296     NvU32      Index,
297     NvU64      Time
298 )
299 {
300     NvU64                 notifyGPUVA;
301     NvBool                bFound;
302     CLI_DMA_MAPPING_INFO *pDmaMappingInfo;
303     NvU64                 offset;
304     NvU32                 subdeviceInstance;
305     NOTIFICATION         *pNotifier;
306 
307     notifyGPUVA = NotifyGPUVABase + (Index * sizeof(NOTIFICATION));
308 
309     // Memory context is required for mapping lookup
310     bFound = CliGetDmaMappingInfo(RES_GET_CLIENT(pDevice),
311                                   RES_GET_HANDLE(pDevice),
312                                   hMemoryCtx,
313                                   notifyGPUVA,
314                                   gpumgrGetDeviceGpuMask(pGpu->deviceInstance),
315                                   &pDmaMappingInfo);
316     if (!bFound)
317     {
318         NV_PRINTF(LEVEL_ERROR, "Can't find mapping; notifier not written\n");
319         return NV_ERR_INVALID_ADDRESS;
320     }
321 
322     offset = notifyGPUVA - pDmaMappingInfo->DmaOffset;
323     if ((offset + sizeof(NOTIFICATION)) > pDmaMappingInfo->pMemDesc->Size)
324     {
325         NV_PRINTF(LEVEL_ERROR,
326                   "offset+size doesn't fit into mapping; notifier not written\n");
327         return NV_ERR_INVALID_ADDRESS;
328     }
329 
330     //
331     // Set idx to default position in the dma mapped address array
332     //
333     subdeviceInstance = gpumgrGetSubDeviceInstanceFromGpu(gpumgrGetParentGPU(pGpu));
334 
335     SLI_LOOP_START(SLI_LOOP_FLAGS_NONE)
336 
337     if (IsSLIEnabled(pGpu) &&
338         (memdescGetAddressSpace(pDmaMappingInfo->pMemDesc) == ADDR_FBMEM))
339     {
340         //
341         // If SLI and it is vidmem, replace idx with appropriate SLI index
342         // otherwise, this just stays the default value.
343         //
344         subdeviceInstance = gpumgrGetSubDeviceInstanceFromGpu(pGpu);
345     }
346 
347     if (!pDmaMappingInfo->KernelVAddr[subdeviceInstance])
348     {
349         NV_PRINTF(LEVEL_ERROR, "KernelVAddr==NULL; notifier not written\n");
350     }
351     else
352     {
353         pNotifier = (PNOTIFICATION)((NvU8*)pDmaMappingInfo->KernelVAddr[subdeviceInstance] + offset);
354 
355         notifyFillNOTIFICATION(pGpu, pNotifier, Info32, Info16,
356                                CompletionStatus, NV_TRUE, Time);
357     }
358 
359     SLI_LOOP_END
360 
361     return NV_OK;
362 }
363 
364 /*
365  * @brief fills notifier at GPU VA base + index with current time, given info,
366  * and completion status
367  *
368  * Use this function to fill notifier through BAR1 when you have GPU VA.
369  *
370  * Wrapper for notifyFillNotifierGPUVATimestamp.
371  * Gets current time and routes data to notifyFillNotifierGPUVATimestamp
372  *
373  * @param[in] pGpu              OBJGPU pointer
374  * @param[in] pDevice           Device pointer
375  * @param[in] hMemoryCtx        Handle of a memory object to which NotifyGPUVABase belongs
376  * @param[in] NotifyGPUVABase   64b GPU VA base address of semaphore
377  * @param[in] Info32            32b info part
378  * @param[in] Info16            16b info part
379  * @param[in] CompletionStatus  NV_STATUS value to write to notifier status
380  * @param[in] Index             index of notifier in notifier array
381  * @param[in] Time              64b time stamp
382  *
383  * @return status of notifyFillNotifierGPUVATimestamp
384  */
notifyFillNotifierGPUVA(OBJGPU * pGpu,Device * pDevice,NvHandle hMemoryCtx,NvU64 NotifyGPUVABase,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index)385 NV_STATUS notifyFillNotifierGPUVA
386 (
387     OBJGPU    *pGpu,
388     Device    *pDevice,
389     NvHandle   hMemoryCtx,
390     NvU64      NotifyGPUVABase,
391     NvV32      Info32,
392     NvV16      Info16,
393     NV_STATUS  CompletionStatus,
394     NvU32      Index
395 )
396 {
397     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
398     NvU64   Time;
399 
400     tmrGetCurrentTime(pTmr, &Time);
401 
402     return notifyFillNotifierGPUVATimestamp(pGpu,
403                                             pDevice,
404                                             hMemoryCtx,
405                                             NotifyGPUVABase,
406                                             Info32,
407                                             Info16,
408                                             CompletionStatus,
409                                             Index,
410                                             Time);
411 }
412 
413 /*
414  * @brief fills notifiers by given memory info and index with given time, info,
415  * and completion status
416  *
417  * Use this function to fill notifier through BAR2 when you have memory info.
418  *
419 
420  * @param[in] pGpu              OBJGPU pointer
421  * @param[in] hClient           NvU32 client handle
422  * @param[in] NotifyGPUVABase   64b GPU VA base address of semaphore
423  * @param[in] Info32            32b info part
424  * @param[in] Info16            16b info part
425  * @param[in] CompletionStatus  NV_STATUS value to write to notifier status
426  * @param[in] Index             index of notifier in notifier array
427  *
428  * @return NV_ERR_GENERIC if RM aperture mapping failed.
429  */
notifyFillNotifierMemoryTimestamp(OBJGPU * pGpu,Memory * pMemory,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index,NvU64 Time)430 NV_STATUS notifyFillNotifierMemoryTimestamp
431 (
432     OBJGPU       *pGpu,
433     Memory       *pMemory,
434     NvV32         Info32,
435     NvV16         Info16,
436     NV_STATUS     CompletionStatus,
437     NvU32         Index,
438     NvU64         Time
439 )
440 {
441     NvNotification * pDebugNotifier = NULL;
442     MemoryManager *pMemoryManager = GPU_GET_MEMORY_MANAGER(pGpu);
443     KernelBus *pKernelBus = GPU_GET_KERNEL_BUS(pGpu);
444     TRANSFER_SURFACE surf = {0};
445 
446     //
447     // Check if there's already a CPU mapping we can use. If not, attempt to
448     // map the notifier, which may fail if we're in a context where we can't
449     // create mappings.
450     //
451     pDebugNotifier = (NvNotification *)((NvUPtr)pMemory->KernelVAddr);
452     if (pDebugNotifier == NULL)
453     {
454         surf.pMemDesc = pMemory->pMemDesc;
455         surf.offset = Index * sizeof(NvNotification);
456 
457         pDebugNotifier =
458             (NvNotification *) memmgrMemBeginTransfer(pMemoryManager, &surf,
459                                                       sizeof(NvNotification),
460                                                       TRANSFER_FLAGS_SHADOW_ALLOC);
461         NV_ASSERT_OR_RETURN(pDebugNotifier != NULL, NV_ERR_INVALID_STATE);
462     }
463     else
464     {
465         //
466         // If a CPU pointer has been passed by caller ensure that the notifier
467         // is in sysmem or in case it in vidmem, BAR access to the same is not
468         // blocked (for HCC)
469         //
470         NV_ASSERT_OR_RETURN(
471             memdescGetAddressSpace(pMemory->pMemDesc) == ADDR_SYSMEM ||
472             !kbusIsBarAccessBlocked(pKernelBus), NV_ERR_INVALID_ARGUMENT);
473         pDebugNotifier = &pDebugNotifier[Index];
474     }
475 
476     notifyFillNvNotification(pGpu, pDebugNotifier, Info32, Info16,
477                              CompletionStatus, NV_TRUE, Time);
478 
479     if (pMemory->KernelVAddr == NvP64_NULL)
480     {
481         memmgrMemEndTransfer(pMemoryManager, &surf, sizeof(NvNotification), 0);
482     }
483 
484     return NV_OK;
485 }
486 
487 /*
488  * @brief fills notifiers by given memory info and index with current time,
489  * info and completion status.
490  *
491  * Use this function to fill notifier through BAR2 when you have memory info.
492  *
493  * Current time wrapper around notifyFillNotifierMemoryTimestamp.
494  *
495  * @param[in] pGpu              OBJGPU pointer
496  * @param[in] hClient           NvU32 client handle
497  * @param[in] NotifyGPUVABase   64b GPU VA base address of semaphore
498  * @param[in] Info32            32b info part
499  * @param[in] Info16            16b info part
500  * @param[in] CompletionStatus  NV_STATUS value to write to notifier status
501  * @param[in] Index             index of notifier in notifier array
502  *
503  * @return status of notifyFillNotifierMemoryTimestamp
504  */
notifyFillNotifierMemory(OBJGPU * pGpu,Memory * pMemory,NvV32 Info32,NvV16 Info16,NV_STATUS CompletionStatus,NvU32 Index)505 NV_STATUS notifyFillNotifierMemory
506 (
507     OBJGPU    *pGpu,
508     Memory    *pMemory,
509     NvV32      Info32,
510     NvV16      Info16,
511     NV_STATUS  CompletionStatus,
512     NvU32      Index
513 )
514 {
515     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
516     NvU64   Time;
517 
518     tmrGetCurrentTime(pTmr, &Time);
519 
520     return notifyFillNotifierMemoryTimestamp(pGpu,
521                                              pMemory,
522                                              Info32,
523                                              Info16,
524                                              CompletionStatus,
525                                              Index,
526                                              Time);
527 
528 }
529 
530 /*
531  * @brief fill semaphore structure at GPU VA base given time and release value
532  *
533  * Looks up dma memory mapping with given GPU VA and performs writes.
534  * Semaphore write is skipped when CPU kernel mapping is missing.
535  *
536  * @param[in] pGpu                  OBJGPU pointer
537  * @param[in] pDevice               Device pointer
538  * @param[in] SemaphoreGPUVABase    64b GPU VA base address of semaphore
539  * @param[in] ReleaseValue          NvU32 value to write to semaphore upon release
540  * @param[in] Index                 index of semaphore in semaphore array
541  * @param[in] Time                  64b time stamp
542  *
543  * @return NV_ERR_INVALID_ADDRESS on wrong GPU VA address or out of bound index,
544  *         NV_OK on success
545  *
546  */
semaphoreFillGPUVATimestamp(OBJGPU * pGpu,Device * pDevice,NvHandle hMemCtx,NvU64 SemaphoreGPUVABase,NvV32 ReleaseValue,NvU32 Index,NvBool bBroadcast,NvU64 Time)547 NV_STATUS semaphoreFillGPUVATimestamp
548 (
549     OBJGPU    *pGpu,
550     Device    *pDevice,
551     NvHandle   hMemCtx,
552     NvU64      SemaphoreGPUVABase,
553     NvV32      ReleaseValue,
554     NvU32      Index,
555     NvBool     bBroadcast,
556     NvU64      Time
557 )
558 {
559     NvU64                 semaphoreGPUVA;
560     NvU64                 semaphoreGPUVAOffset;
561     CLI_DMA_MAPPING_INFO *pDmaMappingInfo;
562     NvU64                 offset;
563     NvU32                 timeHi, timeLo;
564     NvU32                 subdeviceInstance;
565     NvGpuSemaphore       *pSemaphore;
566     NvBool                bBcState = gpumgrGetBcEnabledStatus(pGpu);
567     NvBool                bFound;
568 
569     if (!portSafeMulU64((NvU64) Index,
570                         (NvU64) sizeof(NvGpuSemaphore),
571                         &semaphoreGPUVAOffset) ||
572         !portSafeAddU64(SemaphoreGPUVABase,
573                         semaphoreGPUVAOffset,
574                         &semaphoreGPUVA))
575     {
576         return NV_ERR_INVALID_ARGUMENT;
577     }
578 
579     bFound = CliGetDmaMappingInfo(RES_GET_CLIENT(pDevice),
580                                   RES_GET_HANDLE(pDevice),
581                                   hMemCtx,
582                                   semaphoreGPUVA,
583                                   gpumgrGetDeviceGpuMask(pGpu->deviceInstance),
584                                   &pDmaMappingInfo);
585     if (!bFound)
586     {
587         NV_PRINTF(LEVEL_ERROR, "Can't find mapping; semaphore not released\n");
588         return NV_ERR_INVALID_ADDRESS;
589     }
590 
591     offset = semaphoreGPUVA - pDmaMappingInfo->DmaOffset;
592     if ((offset + sizeof(NvGpuSemaphore)) > pDmaMappingInfo->pMemDesc->Size)
593     {
594         NV_PRINTF(LEVEL_ERROR,
595                   "offset+size doesn't fit into mapping; semaphore not released\n");
596         return NV_ERR_INVALID_ADDRESS;
597     }
598 
599     timeLo = NvU64_LO32(Time);
600     timeHi = NvU64_HI32(Time);
601 
602     //
603     // Set idx to default position in the dma mapped address array
604     //
605     subdeviceInstance = gpumgrGetSubDeviceInstanceFromGpu(gpumgrGetParentGPU(pGpu));
606 
607     osFlushCpuWriteCombineBuffer();
608 
609     gpumgrSetBcEnabledStatus(pGpu, bBroadcast);
610     SLI_LOOP_START(SLI_LOOP_FLAGS_BC_ONLY)
611 
612     if (IsSLIEnabled(pGpu) &&
613         (memdescGetAddressSpace(pDmaMappingInfo->pMemDesc) == ADDR_FBMEM))
614     {
615         //
616         // If SLI and it is vidmem, replace idx with appropriate SLI index
617         // otherwise, this just stays the default value.
618         //
619         subdeviceInstance = gpumgrGetSubDeviceInstanceFromGpu(pGpu);
620     }
621 
622     if (!pDmaMappingInfo->KernelVAddr[subdeviceInstance])
623     {
624         NV_PRINTF(LEVEL_ERROR, "KernelVAddr==NULL; semaphore not released\n");
625     }
626     else
627     {
628         pSemaphore = (NvGpuSemaphore*)((NvU8*)pDmaMappingInfo->KernelVAddr[subdeviceInstance] + offset);
629 
630         MEM_WR32(&(pSemaphore->timeStamp.nanoseconds[0]), timeLo);
631         MEM_WR32(&(pSemaphore->timeStamp.nanoseconds[1]), timeHi);
632         MEM_WR32(&(pSemaphore->data[0]), ReleaseValue);
633     }
634 
635     SLI_LOOP_END
636 
637     gpumgrSetBcEnabledStatus(pGpu, bBcState);
638     osFlushCpuWriteCombineBuffer();
639 
640     return NV_OK;
641 }
642 
643 /*
644  * @brief fill semaphore at GPU VA with given release value and current time stamp
645  *
646  * Use this function to fill Semaphore through BAR1 when you have GPU VA.
647  *
648  * Wrapper for semaphore handling. Gets current time and routes data to
649  * semaphoreFillGPUVATimestamp.
650  *
651  * @param[in] pGpu                  OBJGPU pointer
652  * @param[in] pDevice               Device pointer
653  * @param[in] SemaphoreGPUVABase    64b GPU VA base address of semaphore
654  * @param[in] ReleaseValue          NvU32 value to write to semaphore upon release
655  * @param[in] Index                 index of semaphore in semaphore array
656  *
657  * @return status of semaphoreFillGPUVATimestamp
658  */
semaphoreFillGPUVA(OBJGPU * pGpu,Device * pDevice,NvHandle hMemCtx,NvU64 SemaphoreGPUVABase,NvV32 ReleaseValue,NvU32 Index,NvBool bBroadcast)659 NV_STATUS semaphoreFillGPUVA
660 (
661     OBJGPU    *pGpu,
662     Device    *pDevice,
663     NvHandle   hMemCtx,
664     NvU64      SemaphoreGPUVABase,
665     NvV32      ReleaseValue,
666     NvU32      Index,
667     NvBool     bBroadcast
668 )
669 {
670     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
671     NvU64   Time;
672 
673     tmrGetCurrentTime(pTmr, &Time);
674 
675     return semaphoreFillGPUVATimestamp(pGpu,
676                                        pDevice,
677                                        hMemCtx,
678                                        SemaphoreGPUVABase,
679                                        ReleaseValue,
680                                        Index,
681                                        bBroadcast,
682                                        Time);
683 }
684