1 /*
2  * Copyright (C) 2020-2021 Intel Corporation
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  */
7 
8 #pragma once
9 #include "level_zero/core/test/unit_tests/mock.h"
10 #include "level_zero/tools/source/sysman/windows/kmd_sys_manager.h"
11 #include "level_zero/tools/source/sysman/windows/os_sysman_imp.h"
12 
13 #include "gmock/gmock.h"
14 
15 namespace L0 {
16 namespace ult {
17 
18 constexpr uint32_t mockKmdVersionMajor = 1;
19 constexpr uint32_t mockKmdVersionMinor = 0;
20 constexpr uint32_t mockKmdPatchNumber = 0;
21 constexpr uint32_t mockKmdMaxHandlesPerEvent = 20;
22 
23 struct MockEventHandle {
24     HANDLE eventHandle;
25     bool inited = false;
26 };
27 
28 uint64_t convertTStoMicroSec(uint64_t TS, uint32_t freq);
29 
30 class MockKmdSysManager : public KmdSysManager {};
31 
32 template <>
33 struct Mock<MockKmdSysManager> : public MockKmdSysManager {
34 
35     ze_bool_t allowSetCalls = false;
36     ze_bool_t fanSupported = false;
37     uint32_t mockPowerLimit1 = 2500;
38 
39     MockEventHandle handles[KmdSysman::Events::MaxEvents][mockKmdMaxHandlesPerEvent];
40 
41     MOCK_METHOD(bool, escape, (uint32_t escapeOp, uint64_t pDataIn, uint32_t dataInSize, uint64_t pDataOut, uint32_t dataOutSize));
42 
43     MOCKABLE_VIRTUAL void getInterfaceProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
44         pResponse->outDataSize = 0;
45         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
46     }
47 
48     MOCKABLE_VIRTUAL void setInterfaceProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
49         pResponse->outDataSize = 0;
50         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
51     }
52 
53     MOCKABLE_VIRTUAL void getPowerProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
54         uint8_t *pBuffer = reinterpret_cast<uint8_t *>(pResponse);
55         pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderOut);
56 
57         if (pRequest->inRequestId == KmdSysman::Requests::Power::CurrentPowerLimit1) {
58             uint32_t *pPl1 = reinterpret_cast<uint32_t *>(pBuffer);
59             *pPl1 = mockPowerLimit1;
60             pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess;
61             pResponse->outDataSize = sizeof(uint32_t);
62         } else {
63             pResponse->outDataSize = 0;
64             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
65         }
66     }
67 
68     MOCKABLE_VIRTUAL void setPowerProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
69         uint8_t *pBuffer = reinterpret_cast<uint8_t *>(pRequest);
70         pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderIn);
71 
72         if (pRequest->inRequestId == KmdSysman::Requests::Power::CurrentPowerLimit1) {
73             uint32_t *pPl1 = reinterpret_cast<uint32_t *>(pBuffer);
74             mockPowerLimit1 = *pPl1;
75             pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess;
76         } else {
77             pResponse->outDataSize = 0;
78             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
79         }
80     }
81 
82     MOCKABLE_VIRTUAL void getFrequencyProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
83         pResponse->outDataSize = 0;
84         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
85     }
86 
87     MOCKABLE_VIRTUAL void setFrequencyProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
88         pResponse->outDataSize = 0;
89         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
90     }
91 
92     MOCKABLE_VIRTUAL void getActivityProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
93         pResponse->outDataSize = 0;
94         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
95     }
96 
97     MOCKABLE_VIRTUAL void setActivityProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
98         pResponse->outDataSize = 0;
99         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
100     }
101 
102     MOCKABLE_VIRTUAL void getFanProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
103         pResponse->outDataSize = 0;
104         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
105     }
106 
107     MOCKABLE_VIRTUAL void setFanProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
108         pResponse->outDataSize = 0;
109         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
110     }
111 
112     MOCKABLE_VIRTUAL void getTemperatureProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
113         pResponse->outDataSize = 0;
114         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
115     }
116 
117     MOCKABLE_VIRTUAL void setTemperatureProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
118         pResponse->outDataSize = 0;
119         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
120     }
121 
122     MOCKABLE_VIRTUAL void getFpsProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
123         pResponse->outDataSize = 0;
124         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
125     }
126 
127     MOCKABLE_VIRTUAL void setFpsProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
128         pResponse->outDataSize = 0;
129         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
130     }
131 
132     MOCKABLE_VIRTUAL void getSchedulerProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
133         pResponse->outDataSize = 0;
134         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
135     }
136 
137     MOCKABLE_VIRTUAL void setSchedulerProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
138         pResponse->outDataSize = 0;
139         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
140     }
141 
142     MOCKABLE_VIRTUAL void getMemoryProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
143         pResponse->outDataSize = 0;
144         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
145     }
146 
147     MOCKABLE_VIRTUAL void setMemoryProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
148         pResponse->outDataSize = 0;
149         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
150     }
151 
152     MOCKABLE_VIRTUAL void getPciProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
153         pResponse->outDataSize = 0;
154         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
155     }
156 
157     MOCKABLE_VIRTUAL void setPciProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
158         pResponse->outDataSize = 0;
159         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
160     }
161 
162     MOCKABLE_VIRTUAL void getGlobalOperationsProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
163         pResponse->outDataSize = 0;
164         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
165     }
166 
167     MOCKABLE_VIRTUAL void setGlobalOperationsProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
168         pResponse->outDataSize = 0;
169         pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
170     }
171 
172     void retrieveCorrectVersion(KmdSysman::GfxSysmanMainHeaderOut *pHeaderOut) {
173         pHeaderOut->outNumElements = 1;
174         pHeaderOut->outTotalSize = 0;
175 
176         KmdSysman::GfxSysmanReqHeaderOut *pResponse = reinterpret_cast<KmdSysman::GfxSysmanReqHeaderOut *>(pHeaderOut->outBuffer);
177         uint8_t *pBuffer = nullptr;
178 
179         pResponse->outReturnCode = KmdSysman::KmdSysmanSuccess;
180         pResponse->outDataSize = sizeof(KmdSysman::KmdSysmanVersion);
181         pBuffer = reinterpret_cast<uint8_t *>(pResponse);
182         pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderOut);
183         pHeaderOut->outTotalSize += sizeof(KmdSysman::GfxSysmanReqHeaderOut);
184 
185         KmdSysman::KmdSysmanVersion *pCurrentVersion = reinterpret_cast<KmdSysman::KmdSysmanVersion *>(pBuffer);
186         pCurrentVersion->majorVersion = mockKmdVersionMajor;
187         pCurrentVersion->minorVersion = mockKmdVersionMinor;
188         pCurrentVersion->patchNumber = mockKmdPatchNumber;
189 
190         pHeaderOut->outTotalSize += sizeof(KmdSysman::KmdSysmanVersion);
191     }
192 
193     bool validateInputBuffer(KmdSysman::GfxSysmanMainHeaderIn *pHeaderIn) {
194         uint32_t sizeCheck = pHeaderIn->inTotalsize;
195         uint8_t *pBufferPtr = pHeaderIn->inBuffer;
196 
197         for (uint32_t i = 0; i < pHeaderIn->inNumElements; i++) {
198             KmdSysman::GfxSysmanReqHeaderIn *pRequest = reinterpret_cast<KmdSysman::GfxSysmanReqHeaderIn *>(pBufferPtr);
199             if (pRequest->inCommand == KmdSysman::Command::Get ||
200                 pRequest->inCommand == KmdSysman::Command::Set ||
201                 pRequest->inCommand == KmdSysman::Command::RegisterEvent) {
202                 if (pRequest->inComponent >= KmdSysman::Component::InterfaceProperties && pRequest->inComponent < KmdSysman::Component::MaxComponents) {
203                     pBufferPtr += sizeof(KmdSysman::GfxSysmanReqHeaderIn);
204                     sizeCheck -= sizeof(KmdSysman::GfxSysmanReqHeaderIn);
205 
206                     if (pRequest->inCommand == KmdSysman::Command::Set ||
207                         pRequest->inCommand == KmdSysman::Command::RegisterEvent) {
208                         if (pRequest->inDataSize == 0) {
209                             return false;
210                         }
211                         pBufferPtr += pRequest->inDataSize;
212                         sizeCheck -= pRequest->inDataSize;
213                     }
214                 } else {
215                     return false;
216                 }
217             } else {
218                 return false;
219             }
220         }
221 
222         if (sizeCheck != 0) {
223             return false;
224         }
225 
226         return true;
227     }
228 
229     void registerEvent(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
230         if (!allowSetCalls) {
231             pResponse->outDataSize = 0;
232             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
233             return;
234         }
235 
236         uint8_t *pBuffer = reinterpret_cast<uint8_t *>(pRequest);
237         pBuffer += sizeof(KmdSysman::GfxSysmanReqHeaderIn);
238 
239         pResponse->outDataSize = 0;
240 
241         switch (pRequest->inRequestId) {
242         case KmdSysman::Events::EnterD0:
243         case KmdSysman::Events::EnterD3:
244         case KmdSysman::Events::EnterTDR:
245         case KmdSysman::Events::ExitTDR:
246         case KmdSysman::Events::EnergyThresholdCrossed: {
247             bool found = false;
248             for (uint32_t i = 0; i < mockKmdMaxHandlesPerEvent; i++) {
249                 if (!handles[pRequest->inRequestId][i].inited) {
250                     handles[pRequest->inRequestId][i].inited = true;
251                     unsigned long long eventID = *(unsigned long long *)pBuffer;
252                     handles[pRequest->inRequestId][i].eventHandle = reinterpret_cast<HANDLE>(eventID);
253                     found = true;
254                     break;
255                 }
256             }
257             pResponse->outReturnCode = found ? KmdSysman::KmdSysmanSuccess : KmdSysman::KmdSysmanFail;
258         } break;
259         default:
260             pResponse->outDataSize = 0;
261             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
262             break;
263         }
264     }
265 
266     void signalEvent(uint32_t idEvent) {
267 
268         uint32_t arrayID = 0;
269         if (idEvent & ZES_EVENT_TYPE_FLAG_ENERGY_THRESHOLD_CROSSED) {
270             arrayID = KmdSysman::Events::EnergyThresholdCrossed;
271         }
272 
273         if (idEvent & ZES_EVENT_TYPE_FLAG_DEVICE_SLEEP_STATE_ENTER) {
274             arrayID = KmdSysman::Events::EnterD3;
275         }
276 
277         if (idEvent & ZES_EVENT_TYPE_FLAG_DEVICE_SLEEP_STATE_EXIT) {
278             arrayID = KmdSysman::Events::EnterD0;
279         }
280 
281         if (idEvent & ZES_EVENT_TYPE_FLAG_DEVICE_DETACH) {
282             arrayID = KmdSysman::Events::EnterTDR;
283         }
284 
285         if (idEvent & ZES_EVENT_TYPE_FLAG_DEVICE_ATTACH) {
286             arrayID = KmdSysman::Events::ExitTDR;
287         }
288 
289         for (uint32_t i = 0; i < mockKmdMaxHandlesPerEvent; i++) {
290             if (handles[arrayID][i].inited) {
291                 SetEvent(handles[arrayID][i].eventHandle);
292             }
293         }
294     }
295 
296     void setProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
297         if (!allowSetCalls) {
298             pResponse->outDataSize = 0;
299             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
300             return;
301         }
302 
303         switch (pRequest->inComponent) {
304         case KmdSysman::Component::InterfaceProperties: {
305             setInterfaceProperty(pRequest, pResponse);
306         } break;
307         case KmdSysman::Component::PowerComponent: {
308             setPowerProperty(pRequest, pResponse);
309         } break;
310         case KmdSysman::Component::FrequencyComponent: {
311             setFrequencyProperty(pRequest, pResponse);
312         } break;
313         case KmdSysman::Component::ActivityComponent: {
314             setActivityProperty(pRequest, pResponse);
315         } break;
316         case KmdSysman::Component::FanComponent: {
317             setFanProperty(pRequest, pResponse);
318         } break;
319         case KmdSysman::Component::TemperatureComponent: {
320             setTemperatureProperty(pRequest, pResponse);
321         } break;
322         case KmdSysman::Component::FpsComponent: {
323             setFpsProperty(pRequest, pResponse);
324         } break;
325         case KmdSysman::Component::SchedulerComponent: {
326             setSchedulerProperty(pRequest, pResponse);
327         } break;
328         case KmdSysman::Component::MemoryComponent: {
329             setMemoryProperty(pRequest, pResponse);
330         } break;
331         case KmdSysman::Component::PciComponent: {
332             setPciProperty(pRequest, pResponse);
333         } break;
334         case KmdSysman::Component::GlobalOperationsComponent: {
335             setGlobalOperationsProperty(pRequest, pResponse);
336         } break;
337         default: {
338             pResponse->outDataSize = 0;
339             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
340         } break;
341         }
342     }
343 
344     void getProperty(KmdSysman::GfxSysmanReqHeaderIn *pRequest, KmdSysman::GfxSysmanReqHeaderOut *pResponse) {
345         switch (pRequest->inComponent) {
346         case KmdSysman::Component::InterfaceProperties: {
347             getInterfaceProperty(pRequest, pResponse);
348         } break;
349         case KmdSysman::Component::PowerComponent: {
350             getPowerProperty(pRequest, pResponse);
351         } break;
352         case KmdSysman::Component::FrequencyComponent: {
353             getFrequencyProperty(pRequest, pResponse);
354         } break;
355         case KmdSysman::Component::ActivityComponent: {
356             getActivityProperty(pRequest, pResponse);
357         } break;
358         case KmdSysman::Component::FanComponent: {
359             getFanProperty(pRequest, pResponse);
360         } break;
361         case KmdSysman::Component::TemperatureComponent: {
362             getTemperatureProperty(pRequest, pResponse);
363         } break;
364         case KmdSysman::Component::FpsComponent: {
365             getFpsProperty(pRequest, pResponse);
366         } break;
367         case KmdSysman::Component::SchedulerComponent: {
368             getSchedulerProperty(pRequest, pResponse);
369         } break;
370         case KmdSysman::Component::MemoryComponent: {
371             getMemoryProperty(pRequest, pResponse);
372         } break;
373         case KmdSysman::Component::PciComponent: {
374             getPciProperty(pRequest, pResponse);
375         } break;
376         case KmdSysman::Component::GlobalOperationsComponent: {
377             getGlobalOperationsProperty(pRequest, pResponse);
378         } break;
379         default: {
380             pResponse->outDataSize = 0;
381             pResponse->outReturnCode = KmdSysman::KmdSysmanFail;
382         } break;
383         }
384     }
385 
386     bool mock_escape(uint32_t escapeOp, uint64_t pInPtr, uint32_t dataInSize, uint64_t pOutPtr, uint32_t dataOutSize) {
387         void *pDataIn = reinterpret_cast<void *>(pInPtr);
388         void *pDataOut = reinterpret_cast<void *>(pOutPtr);
389 
390         if (pDataIn == nullptr || pDataOut == nullptr) {
391             return false;
392         }
393 
394         if (dataInSize != sizeof(KmdSysman::GfxSysmanMainHeaderIn) || dataOutSize != sizeof(KmdSysman::GfxSysmanMainHeaderOut)) {
395             return false;
396         }
397 
398         if (escapeOp != KmdSysman::PcEscapeOperation) {
399             return false;
400         }
401 
402         KmdSysman::GfxSysmanMainHeaderIn *pSysmanMainHeaderIn = reinterpret_cast<KmdSysman::GfxSysmanMainHeaderIn *>(pDataIn);
403         KmdSysman::GfxSysmanMainHeaderOut *pSysmanMainHeaderOut = reinterpret_cast<KmdSysman::GfxSysmanMainHeaderOut *>(pDataOut);
404 
405         KmdSysman::KmdSysmanVersion versionSysman;
406         versionSysman.data = pSysmanMainHeaderIn->inVersion;
407 
408         if (versionSysman.majorVersion != KmdSysman::KmdMajorVersion) {
409             if (versionSysman.majorVersion == 0) {
410                 retrieveCorrectVersion(pSysmanMainHeaderOut);
411                 return true;
412             }
413             return false;
414         }
415 
416         if (pSysmanMainHeaderIn->inTotalsize == 0) {
417             return false;
418         }
419 
420         if (pSysmanMainHeaderIn->inNumElements == 0) {
421             return false;
422         }
423 
424         if (!validateInputBuffer(pSysmanMainHeaderIn)) {
425             return false;
426         }
427 
428         uint8_t *pBufferIn = pSysmanMainHeaderIn->inBuffer;
429         uint8_t *pBufferOut = pSysmanMainHeaderOut->outBuffer;
430         uint32_t requestOffset = 0;
431         uint32_t responseOffset = 0;
432         pSysmanMainHeaderOut->outTotalSize = 0;
433 
434         for (uint32_t i = 0; i < pSysmanMainHeaderIn->inNumElements; i++) {
435             KmdSysman::GfxSysmanReqHeaderIn *pRequest = reinterpret_cast<KmdSysman::GfxSysmanReqHeaderIn *>(pBufferIn);
436             KmdSysman::GfxSysmanReqHeaderOut *pResponse = reinterpret_cast<KmdSysman::GfxSysmanReqHeaderOut *>(pBufferOut);
437 
438             switch (pRequest->inCommand) {
439             case KmdSysman::Command::Get: {
440                 getProperty(pRequest, pResponse);
441                 requestOffset = sizeof(KmdSysman::GfxSysmanReqHeaderIn);
442                 responseOffset = sizeof(KmdSysman::GfxSysmanReqHeaderOut);
443                 responseOffset += pResponse->outDataSize;
444             } break;
445             case KmdSysman::Command::Set: {
446                 setProperty(pRequest, pResponse);
447                 requestOffset = sizeof(KmdSysman::GfxSysmanReqHeaderIn);
448                 requestOffset += pRequest->inDataSize;
449                 responseOffset = sizeof(KmdSysman::GfxSysmanReqHeaderOut);
450             } break;
451             case KmdSysman::Command::RegisterEvent: {
452                 registerEvent(pRequest, pResponse);
453                 requestOffset = sizeof(KmdSysman::GfxSysmanReqHeaderIn);
454                 requestOffset += pRequest->inDataSize;
455                 responseOffset = sizeof(KmdSysman::GfxSysmanReqHeaderOut);
456             } break;
457             default: {
458                 return false;
459             } break;
460             }
461 
462             pResponse->outRequestId = pRequest->inRequestId;
463             pResponse->outComponent = pRequest->inComponent;
464             pBufferIn += requestOffset;
465             pBufferOut += responseOffset;
466             pSysmanMainHeaderOut->outTotalSize += responseOffset;
467         }
468 
469         pSysmanMainHeaderOut->outNumElements = pSysmanMainHeaderIn->inNumElements;
470         pSysmanMainHeaderOut->outStatus = KmdSysman::KmdSysmanSuccess;
471 
472         return true;
473     }
474 
475     Mock() = default;
476     ~Mock() = default;
477 };
478 
479 } // namespace ult
480 } // namespace L0