1 /*
2  * SPDX-FileCopyrightText: Copyright (c) 1993-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 #include "objtmr.h"
25 #include "gpu/external_device/gsync.h"
26 
27 #include "gpu/external_device/external_device.h"
28 #include "gpu_mgr/gpu_mgr.h"
29 #include "kernel/gpu/i2c/i2c_api.h"
30 #include "gpu/disp/kern_disp_max.h"
31 
32 static
extdevGetExtDev(OBJGPU * pGpu)33 PDACEXTERNALDEVICE extdevGetExtDev
34 (
35     OBJGPU *pGpu
36 )
37 {
38     if (RMCFG_FEATURE_EXTDEV_GSYNC)
39     {
40         OBJGSYNC *pGsync = gsyncmgrGetGsync(pGpu);
41         if (pGsync)
42         {
43             return pGsync->pExtDev;
44         }
45     }
46 
47     return NULL;
48 }
49 
50 //
51 // RMCONFIG: when the EXTDEV feature is disabled there are #defines in
52 // extdev.h that stub this routine out.
53 //
extdevDestroy_Base(OBJGPU * pGpu,PDACEXTERNALDEVICE pExternalDevice)54 void extdevDestroy_Base(OBJGPU *pGpu, PDACEXTERNALDEVICE pExternalDevice)
55 {
56     portMemFree(pExternalDevice->pI);
57 }
58 
dacAttachExternalDevice_Base(OBJGPU * pGpu,PDACEXTERNALDEVICE * ppExtdevs)59 static NvBool dacAttachExternalDevice_Base(OBJGPU *pGpu, PDACEXTERNALDEVICE *ppExtdevs)
60 {
61     return NV_FALSE;
62 }
63 
64 PDACEXTERNALDEVICE
extdevConstruct_Base(OBJGPU * pGpu,PDACEXTERNALDEVICE pThis)65 extdevConstruct_Base
66 (
67     OBJGPU             *pGpu,
68     PDACEXTERNALDEVICE  pThis
69 )
70 {
71     //
72     // Alloc or find interface.
73     // Not being able to do so is fatal.
74     //
75     {
76         pThis->pI = portMemAllocNonPaged(sizeof(DACEXTERNALDEVICEIFACE));
77         if (pThis->pI == NULL)
78         {
79             return 0;
80         }
81         portMemSet(pThis->pI, 0, sizeof(DACEXTERNALDEVICEIFACE));
82     }
83 
84     // No parent constructor to call, we're the base class!
85 
86     // Setup interface(s)
87     {
88         pThis->pI->Destroy = extdevDestroy_Base;
89         pThis->pI->Attach  = dacAttachExternalDevice_Base;
90 
91         pThis->pI->GetDevice = 0;
92         pThis->pI->Init = 0;
93 
94         pThis->pI->Validate   = extdevValidate_Default;
95     }
96 
97     // Init data members
98     {
99         pThis->MaxGpus                 = 1; // default, only connect to 1 gpu
100 
101         pThis->WatchdogControl.Scheduled = NV_FALSE;
102         pThis->WatchdogControl.TimeOut = 1000000000; // 1 second in ns
103     }
104 
105     return pThis;
106 }
107 
108 void
extdevDestroy(OBJGPU * pGpu)109 extdevDestroy(OBJGPU *pGpu)
110 {
111     OBJGSYNC *pGsync = NULL;
112 
113     if (RMCFG_FEATURE_EXTDEV_GSYNC)
114     {
115         // destroy gsync object if any
116         pGsync = gsyncmgrGetGsync(pGpu);
117         if (pGsync && pGsync->pExtDev)
118         {
119             pGsync->pExtDev->pI->Destroy(pGpu, pGsync->pExtDev);
120             if (pGsync->pExtDev->ReferenceCount == 0)
121             {
122                 portMemFree(pGsync->pExtDev);
123                 pGsync->pExtDev = NULL;
124             }
125         }
126     }
127 }
128 
129 // Schedule Watchdog
extdevScheduleWatchdog(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDevice)130 NV_STATUS extdevScheduleWatchdog
131 (
132     OBJGPU *pGpu,
133     PDACEXTERNALDEVICE pExtDevice
134 )
135 {
136     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
137     NV_STATUS rmStatus = NV_ERR_GENERIC;
138 
139     // make sure it isn't already scheduled
140     if (!pExtDevice->WatchdogControl.Scheduled)
141     {
142         pExtDevice->WatchdogControl.Scheduled = NV_TRUE;
143 
144         rmStatus = tmrScheduleCallbackRel(
145             pTmr,
146             extdevServiceWatchdog,
147             pExtDevice,
148             pExtDevice->WatchdogControl.TimeOut,
149             TMR_FLAG_RECUR,
150             0);
151 
152         if (NV_OK != rmStatus)
153         {
154             pExtDevice->WatchdogControl.Scheduled = NV_FALSE;
155         }
156     }
157 
158     return rmStatus;
159 }
160 
161 // deSchedule Watchdog
extdevCancelWatchdog(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDevice)162 NV_STATUS extdevCancelWatchdog
163 (
164     OBJGPU *pGpu,
165     PDACEXTERNALDEVICE pExtDevice
166 )
167 {
168     OBJTMR *pTmr = GPU_GET_TIMER(pGpu);
169     NV_STATUS rmStatus;
170 
171     // cancel first...
172     rmStatus = tmrCancelCallback(pTmr, pExtDevice);
173 
174     // ... then lower the flag!
175     pExtDevice->WatchdogControl.Scheduled = NV_FALSE;
176 
177     return rmStatus;
178 }
179 
180 // Service the Watchdog
extdevServiceWatchdog(OBJGPU * pGpu,OBJTMR * pTmr,void * _pComponent)181 NV_STATUS extdevServiceWatchdog
182 (
183     OBJGPU *pGpu,
184     OBJTMR *pTmr,
185     void *_pComponent
186 )
187 {
188     PDACEXTERNALDEVICE pExtDevice = NULL;
189     PDACEXTERNALDEVICEIFACE pdsif = NULL;
190 
191     pExtDevice = extdevGetExtDev(pGpu);
192 
193     // No gsync and no gvo, return NV_ERR_GENERIC
194     if (!pExtDevice)
195     {
196         return NV_ERR_GENERIC;
197     }
198 
199     pdsif = pExtDevice->pI;
200 
201     // lower the flag, since it's no longer waiting to run
202     pExtDevice->WatchdogControl.Scheduled = NV_FALSE;
203 
204     return pdsif->Watchdog(pGpu, pTmr, pExtDevice);
205 }
206 
207 // Trivial validation
extdevValidate_Default(OBJGPU * pGpu,PDACEXTERNALDEVICE pExtDevice)208 NvBool extdevValidate_Default
209 (
210     OBJGPU *pGpu,
211     PDACEXTERNALDEVICE pExtDevice
212 )
213 {
214     if (!pExtDevice)
215     {
216         return NV_FALSE;
217     }
218 
219     return NV_TRUE;
220 }
221 
222 NV_STATUS
writeregu008_extdevice(OBJGPU * pGpu,PDACEXTERNALDEVICE pThis,NvU8 SubAdr,NvU8 Data)223 writeregu008_extdevice
224 (
225     OBJGPU            *pGpu,
226     PDACEXTERNALDEVICE pThis,
227     NvU8               SubAdr,
228     NvU8               Data
229 )
230 {
231 
232     NV_STATUS status = NV_ERR_GENERIC;
233 
234     NvU32 i2cPort = (pGpu->i2cPortForExtdev < NV402C_CTRL_NUM_I2C_PORTS) ? pGpu->i2cPortForExtdev : pThis->I2CPort;
235     status = i2c_extdeviceHelper(pGpu, pThis, i2cPort, SubAdr, &Data, NV_TRUE);
236 
237     return status;
238 }
239 
240 //
241 // This is a wrapper function for writeregu008_extdevice to be used when a
242 // specific GPU is to be targeted (rather than an SLI abstraction). For
243 // example, a P294 framelock board has two connectors to gpus, one for a
244 // primary gpu and one for a secondary gpu. It is only valid to read and
245 // write registers over i2c connected to the primary gpu. If the MC_PARENT
246 // is not the same gpu as the primary, the ThisGpuFromHal macro at the
247 // beginning of writeregu008_extdevice will return the secondary gpu unless
248 // the primary gpu is specifically loaded beforehand.
249 // This wrapper does that loading.
250 //
251 NV_STATUS
writeregu008_extdeviceTargeted(OBJGPU * pGpu,PDACEXTERNALDEVICE pThis,NvU8 SubAdr,NvU8 Data)252 writeregu008_extdeviceTargeted
253 (
254     OBJGPU             *pGpu,
255     PDACEXTERNALDEVICE  pThis,
256     NvU8                SubAdr,
257     NvU8                Data
258 )
259 {
260     NV_STATUS status = NV_ERR_GENERIC;
261     NvBool bcState;
262 
263     if (!pGpu)
264     {
265        return status;
266     }
267 
268     bcState = gpumgrGetBcEnabledStatus(pGpu);
269 
270     gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
271     status = writeregu008_extdevice(pGpu, pThis, SubAdr, Data);
272     gpumgrSetBcEnabledStatus(pGpu, bcState);
273 
274     return status;
275 }
276 
277 NV_STATUS
readregu008_extdevice(OBJGPU * pGpu,PDACEXTERNALDEVICE pThis,NvU8 SubAdr,NvU8 * pData)278 readregu008_extdevice
279 (
280     OBJGPU             *pGpu,
281     PDACEXTERNALDEVICE  pThis,
282     NvU8                SubAdr,
283     NvU8               *pData
284 )
285 {
286 
287     NV_STATUS status = NV_ERR_GENERIC;
288 
289     NvU32 i2cPort = (pGpu->i2cPortForExtdev < NV402C_CTRL_NUM_I2C_PORTS) ? pGpu->i2cPortForExtdev : pThis->I2CPort;
290     status = i2c_extdeviceHelper(pGpu, pThis, i2cPort, SubAdr, pData, NV_FALSE);
291 
292     return status;
293 }
294 
295 //
296 // This is a wrapper function for readregu008_extdevice to be used when a
297 // specific GPU is to be targeted (rather than an SLI abstraction). For
298 // example, a P294 framelock board has two connectors to gpus, one for a
299 // primary gpu and one for a secondary gpu. It is only valid to read and
300 // write registers over i2c connected to the primary gpu. If the MC_PARENT
301 // is not the same gpu as the primary, the ThisGpuFromHal macro at the
302 // beginning of readregu008_extdevice will return the secondary gpu unless
303 // the primary gpu is specifically loaded beforehand.
304 // This wrapper does that loading.
305 //
306 NV_STATUS
readregu008_extdeviceTargeted(OBJGPU * pGpu,PDACEXTERNALDEVICE pThis,NvU8 SubAdr,NvU8 * pData)307 readregu008_extdeviceTargeted
308 (
309     OBJGPU             *pGpu,
310     PDACEXTERNALDEVICE  pThis,
311     NvU8                SubAdr,
312     NvU8               *pData
313 )
314 {
315     NV_STATUS status = NV_ERR_GENERIC;
316     NvBool bcState;
317 
318     if (!pGpu)
319     {
320        return status;
321     }
322 
323     bcState = gpumgrGetBcEnabledStatus(pGpu);
324 
325     gpumgrSetBcEnabledStatus(pGpu, NV_FALSE);
326     status = readregu008_extdevice(pGpu, pThis, SubAdr, pData);
327     gpumgrSetBcEnabledStatus(pGpu, bcState);
328 
329     return status;
330 }
331 
332 void
extdevGsyncService(OBJGPU * pGpu,NvU8 lossRegStatus,NvU8 gainRegStatus,NvU8 miscRegStatus,NvBool rmStatus)333 extdevGsyncService
334 (
335     OBJGPU             *pGpu,
336     NvU8                lossRegStatus,
337     NvU8                gainRegStatus,
338     NvU8                miscRegStatus,
339     NvBool              rmStatus
340 )
341 {
342     PDACEXTERNALDEVICE pExtDevice = NULL;
343     PDACEXTERNALDEVICEIFACE pdsif = NULL;
344 
345     pExtDevice = extdevGetExtDev(pGpu);
346     if (!pExtDevice)
347         return;
348 
349     pdsif = pExtDevice->pI;
350 
351     pdsif->Service(pGpu, pExtDevice, lossRegStatus, gainRegStatus, miscRegStatus, rmStatus);
352 }
353 
354 void
extdevGetBoundHeadsAndDisplayIds(OBJGPU * pGpu,NvU32 * pDisplayId)355 extdevGetBoundHeadsAndDisplayIds
356 (
357     OBJGPU      *pGpu,
358     NvU32       *pDisplayId
359 )
360 {
361     RM_API   *pRmApi      = GPU_GET_PHYSICAL_RMAPI(pGpu);
362     NvU32     hClient     = pGpu->hInternalClient;
363     NvU32     hSubdevice  = pGpu->hInternalSubdevice;
364     NV_STATUS status      = NV_OK;
365     NV2080_CTRL_INTERNAL_GSYNC_GET_DISPLAY_IDS_PARAMS ctrlParams = {0};
366 
367     portMemSet(pDisplayId, 0, OBJ_MAX_HEADS * sizeof(NvU32));
368 
369     status = pRmApi->Control(pRmApi, hClient, hSubdevice,
370                              NV2080_CTRL_CMD_INTERNAL_GSYNC_GET_DISPLAY_IDS,
371                              &ctrlParams, sizeof(ctrlParams));
372 
373     if (status != NV_OK)
374     {
375         NV_PRINTF(LEVEL_ERROR, "Extdev getting display IDs have failed!\n");
376     }
377     else
378     {
379         portMemCopy(pDisplayId, OBJ_MAX_HEADS * sizeof(NvU32), ctrlParams.displayIds,
380                     OBJ_MAX_HEADS * sizeof(NvU32));
381     }
382 }
383 
384