1 /** @file
2 
3   Copyright (c) 2017-2018, Arm Limited. All rights reserved.
4 
5   SPDX-License-Identifier: BSD-2-Clause-Patent
6 
7   System Control and Management Interface V1.0
8     http://infocenter.arm.com/help/topic/com.arm.doc.den0056a/
9     DEN0056A_System_Control_and_Management_Interface.pdf
10 **/
11 
12 #include <Library/BaseMemoryLib.h>
13 #include <Library/UefiBootServicesTableLib.h>
14 #include <Protocol/ArmScmiPerformanceProtocol.h>
15 
16 #include "ArmScmiPerformanceProtocolPrivate.h"
17 #include "ScmiPrivate.h"
18 
19 /** Return version of the performance management protocol supported by SCP.
20    firmware.
21 
22   @param[in]  This      A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
23 
24   @param[out] Version   Version of the supported SCMI performance management
25                         protocol.
26 
27   @retval EFI_SUCCESS       The version is returned.
28   @retval EFI_DEVICE_ERROR  SCP returns an SCMI error.
29   @retval !(EFI_SUCCESS)    Other errors.
30 **/
31 STATIC
32 EFI_STATUS
PerformanceGetVersion(IN SCMI_PERFORMANCE_PROTOCOL * This,OUT UINT32 * Version)33 PerformanceGetVersion (
34   IN  SCMI_PERFORMANCE_PROTOCOL  *This,
35   OUT UINT32                     *Version
36   )
37 {
38   return ScmiGetProtocolVersion (SCMI_PROTOCOL_ID_PERFORMANCE, Version);
39 }
40 
41 /** Return protocol attributes of the performance management protocol.
42 
43   @param[in] This         A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
44 
45   @param[out] Attributes  Protocol attributes.
46 
47   @retval EFI_SUCCESS       Protocol attributes are returned.
48   @retval EFI_DEVICE_ERROR  SCP returns an SCMI error.
49   @retval !(EFI_SUCCESS)    Other errors.
50 **/
51 STATIC
52 EFI_STATUS
PerformanceGetAttributes(IN SCMI_PERFORMANCE_PROTOCOL * This,OUT SCMI_PERFORMANCE_PROTOCOL_ATTRIBUTES * Attributes)53 PerformanceGetAttributes (
54   IN  SCMI_PERFORMANCE_PROTOCOL              *This,
55   OUT SCMI_PERFORMANCE_PROTOCOL_ATTRIBUTES   *Attributes
56   )
57 {
58   EFI_STATUS  Status;
59   UINT32* ReturnValues;
60 
61   Status = ScmiGetProtocolAttributes (
62              SCMI_PROTOCOL_ID_PERFORMANCE,
63              &ReturnValues
64              );
65   if (EFI_ERROR (Status)) {
66     return Status;
67   }
68 
69   CopyMem (
70     Attributes,
71     ReturnValues,
72     sizeof (SCMI_PERFORMANCE_PROTOCOL_ATTRIBUTES)
73     );
74 
75   return EFI_SUCCESS;
76 }
77 
78 /** Return performance domain attributes.
79 
80   @param[in]  This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
81   @param[in]  DomainId    Identifier for the performance domain.
82 
83   @param[out] Attributes  Performance domain attributes.
84 
85   @retval EFI_SUCCESS       Domain attributes are returned.
86   @retval EFI_DEVICE_ERROR  SCP returns an SCMI error.
87   @retval !(EFI_SUCCESS)    Other errors.
88 **/
89 STATIC
90 EFI_STATUS
PerformanceDomainAttributes(IN SCMI_PERFORMANCE_PROTOCOL * This,IN UINT32 DomainId,OUT SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES * DomainAttributes)91 PerformanceDomainAttributes (
92   IN  SCMI_PERFORMANCE_PROTOCOL           *This,
93   IN  UINT32                               DomainId,
94   OUT SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES  *DomainAttributes
95   )
96 {
97   EFI_STATUS    Status;
98   UINT32        *MessageParams;
99   UINT32        *ReturnValues;
100   UINT32        PayloadLength;
101   SCMI_COMMAND  Cmd;
102 
103   Status = ScmiCommandGetPayload (&MessageParams);
104   if (EFI_ERROR (Status)) {
105     return Status;
106   }
107 
108   *MessageParams = DomainId;
109 
110   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
111   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_DOMAIN_ATTRIBUTES;
112 
113   PayloadLength = sizeof (DomainId);
114 
115   Status = ScmiCommandExecute (
116              &Cmd,
117              &PayloadLength,
118              &ReturnValues
119              );
120   if (EFI_ERROR (Status)) {
121     return Status;
122   }
123 
124   CopyMem (
125     DomainAttributes,
126     ReturnValues,
127     sizeof (SCMI_PERFORMANCE_DOMAIN_ATTRIBUTES)
128     );
129 
130   return EFI_SUCCESS;
131 }
132 
133 /** Return list of performance domain levels of a given domain.
134 
135   @param[in] This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
136   @param[in] DomainId    Identifier for the performance domain.
137 
138   @param[out] NumLevels   Total number of levels a domain can support.
139 
140   @param[in,out]  LevelArraySize Size of the performance level array.
141 
142   @param[out] LevelArray   Array of the performance levels.
143 
144   @retval EFI_SUCCESS          Domain levels are returned.
145   @retval EFI_DEVICE_ERROR     SCP returns an SCMI error.
146   @retval EFI_BUFFER_TOO_SMALL LevelArraySize is too small for the result.
147                                It has been updated to the size needed.
148   @retval !(EFI_SUCCESS)       Other errors.
149 **/
150 STATIC
151 EFI_STATUS
PerformanceDescribeLevels(IN SCMI_PERFORMANCE_PROTOCOL * This,IN UINT32 DomainId,OUT UINT32 * NumLevels,IN OUT UINT32 * LevelArraySize,OUT SCMI_PERFORMANCE_LEVEL * LevelArray)152 PerformanceDescribeLevels (
153   IN     SCMI_PERFORMANCE_PROTOCOL  *This,
154   IN     UINT32                     DomainId,
155   OUT    UINT32                     *NumLevels,
156   IN OUT UINT32                     *LevelArraySize,
157   OUT    SCMI_PERFORMANCE_LEVEL     *LevelArray
158   )
159 {
160   EFI_STATUS    Status;
161   UINT32        PayloadLength;
162   SCMI_COMMAND  Cmd;
163   UINT32*       MessageParams;
164   UINT32        LevelIndex;
165   UINT32        RequiredSize;
166   UINT32        LevelNo;
167   UINT32        ReturnNumLevels;
168   UINT32        ReturnRemainNumLevels;
169 
170   PERF_DESCRIBE_LEVELS *Levels;
171 
172   Status = ScmiCommandGetPayload (&MessageParams);
173   if (EFI_ERROR (Status)) {
174     return Status;
175   }
176 
177   LevelIndex = 0;
178   RequiredSize = 0;
179 
180   *MessageParams++ = DomainId;
181 
182   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
183   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_DESCRIBE_LEVELS;
184 
185   do {
186 
187     *MessageParams = LevelIndex;
188 
189     // Note, PayloadLength is an IN/OUT parameter.
190     PayloadLength = sizeof (DomainId) + sizeof (LevelIndex);
191 
192     Status = ScmiCommandExecute (
193                &Cmd,
194                &PayloadLength,
195                (UINT32**)&Levels
196                );
197     if (EFI_ERROR (Status)) {
198       return Status;
199     }
200 
201     ReturnNumLevels = NUM_PERF_LEVELS (Levels->NumLevels);
202     ReturnRemainNumLevels = NUM_REMAIN_PERF_LEVELS (Levels->NumLevels);
203 
204     if (RequiredSize == 0) {
205       *NumLevels = ReturnNumLevels + ReturnRemainNumLevels;
206 
207       RequiredSize =  (*NumLevels) * sizeof (SCMI_PERFORMANCE_LEVEL);
208       if (RequiredSize > (*LevelArraySize)) {
209         // Update LevelArraySize with required size.
210         *LevelArraySize = RequiredSize;
211         return EFI_BUFFER_TOO_SMALL;
212       }
213     }
214 
215     for (LevelNo = 0; LevelNo < ReturnNumLevels; LevelNo++) {
216        CopyMem (
217          &LevelArray[LevelIndex++],
218          &Levels->PerfLevel[LevelNo],
219          sizeof (SCMI_PERFORMANCE_LEVEL)
220          );
221     }
222 
223   } while (ReturnRemainNumLevels != 0);
224 
225   *LevelArraySize = RequiredSize;
226 
227   return EFI_SUCCESS;
228 }
229 
230 /** Set performance limits of a domain.
231 
232   @param[in] This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
233   @param[in] DomainId    Identifier for the performance domain.
234   @param[in] Limit       Performance limit to set.
235 
236   @retval EFI_SUCCESS          Performance limits set successfully.
237   @retval EFI_DEVICE_ERROR     SCP returns an SCMI error.
238   @retval !(EFI_SUCCESS)       Other errors.
239 **/
240 EFI_STATUS
PerformanceLimitsSet(IN SCMI_PERFORMANCE_PROTOCOL * This,IN UINT32 DomainId,IN SCMI_PERFORMANCE_LIMITS * Limits)241 PerformanceLimitsSet (
242   IN SCMI_PERFORMANCE_PROTOCOL *This,
243   IN UINT32                    DomainId,
244   IN SCMI_PERFORMANCE_LIMITS   *Limits
245   )
246 {
247   EFI_STATUS    Status;
248   UINT32        PayloadLength;
249   SCMI_COMMAND  Cmd;
250   UINT32        *MessageParams;
251 
252   Status = ScmiCommandGetPayload (&MessageParams);
253   if (EFI_ERROR (Status)) {
254     return Status;
255   }
256 
257   *MessageParams++ = DomainId;
258   *MessageParams++ = Limits->RangeMax;
259   *MessageParams   = Limits->RangeMin;
260 
261   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
262   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_LIMITS_SET;
263 
264   PayloadLength = sizeof (DomainId) + sizeof (SCMI_PERFORMANCE_LIMITS);
265 
266   Status = ScmiCommandExecute (
267              &Cmd,
268              &PayloadLength,
269              NULL
270              );
271 
272   return Status;
273 }
274 
275 /** Get performance limits of a domain.
276 
277   @param[in]  This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
278   @param[in]  DomainId    Identifier for the performance domain.
279 
280   @param[out] Limit       Performance Limits of the domain.
281 
282   @retval EFI_SUCCESS          Performance limits are returned.
283   @retval EFI_DEVICE_ERROR     SCP returns an SCMI error.
284   @retval !(EFI_SUCCESS)       Other errors.
285 **/
286 EFI_STATUS
PerformanceLimitsGet(SCMI_PERFORMANCE_PROTOCOL * This,UINT32 DomainId,SCMI_PERFORMANCE_LIMITS * Limits)287 PerformanceLimitsGet (
288   SCMI_PERFORMANCE_PROTOCOL *This,
289   UINT32                    DomainId,
290   SCMI_PERFORMANCE_LIMITS   *Limits
291   )
292 {
293   EFI_STATUS    Status;
294   UINT32        PayloadLength;
295   SCMI_COMMAND  Cmd;
296   UINT32        *MessageParams;
297 
298   SCMI_PERFORMANCE_LIMITS  *ReturnValues;
299 
300   Status = ScmiCommandGetPayload (&MessageParams);
301   if (EFI_ERROR (Status)) {
302     return Status;
303   }
304 
305   *MessageParams = DomainId;
306 
307   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
308   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_LIMITS_GET;
309 
310   PayloadLength = sizeof (DomainId);
311 
312   Status = ScmiCommandExecute (
313              &Cmd,
314              &PayloadLength,
315              (UINT32**)&ReturnValues
316              );
317   if (EFI_ERROR (Status)) {
318     return Status;
319   }
320 
321   Limits->RangeMax = ReturnValues->RangeMax;
322   Limits->RangeMin = ReturnValues->RangeMin;
323 
324   return EFI_SUCCESS;
325 }
326 
327 /** Set performance level of a domain.
328 
329   @param[in]  This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
330   @param[in]  DomainId    Identifier for the performance domain.
331   @param[in]  Level       Performance level of the domain.
332 
333   @retval EFI_SUCCESS          Performance level set successfully.
334   @retval EFI_DEVICE_ERROR     SCP returns an SCMI error.
335   @retval !(EFI_SUCCESS)       Other errors.
336 **/
337 EFI_STATUS
PerformanceLevelSet(IN SCMI_PERFORMANCE_PROTOCOL * This,IN UINT32 DomainId,IN UINT32 Level)338 PerformanceLevelSet (
339   IN SCMI_PERFORMANCE_PROTOCOL *This,
340   IN UINT32                    DomainId,
341   IN UINT32                    Level
342   )
343 {
344   EFI_STATUS    Status;
345   UINT32        PayloadLength;
346   SCMI_COMMAND  Cmd;
347   UINT32        *MessageParams;
348 
349   Status = ScmiCommandGetPayload (&MessageParams);
350   if (EFI_ERROR (Status)) {
351     return Status;
352   }
353 
354   *MessageParams++ = DomainId;
355   *MessageParams   = Level;
356 
357   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
358   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_LEVEL_SET;
359 
360   PayloadLength = sizeof (DomainId) + sizeof (Level);
361 
362   Status = ScmiCommandExecute (
363              &Cmd,
364              &PayloadLength,
365              NULL
366              );
367 
368   return Status;
369 }
370 
371 /** Get performance level of a domain.
372 
373   @param[in]  This        A Pointer to SCMI_PERFORMANCE_PROTOCOL Instance.
374   @param[in]  DomainId    Identifier for the performance domain.
375 
376   @param[out] Level       Performance level of the domain.
377 
378   @retval EFI_SUCCESS          Performance level got successfully.
379   @retval EFI_DEVICE_ERROR     SCP returns an SCMI error.
380   @retval !(EFI_SUCCESS)       Other errors.
381 **/
382 EFI_STATUS
PerformanceLevelGet(IN SCMI_PERFORMANCE_PROTOCOL * This,IN UINT32 DomainId,OUT UINT32 * Level)383 PerformanceLevelGet (
384   IN  SCMI_PERFORMANCE_PROTOCOL *This,
385   IN  UINT32                    DomainId,
386   OUT UINT32                    *Level
387   )
388 {
389   EFI_STATUS    Status;
390   UINT32        PayloadLength;
391   SCMI_COMMAND  Cmd;
392   UINT32        *ReturnValues;
393   UINT32        *MessageParams;
394 
395   Status = ScmiCommandGetPayload (&MessageParams);
396   if (EFI_ERROR (Status)) {
397     return Status;
398   }
399 
400   *MessageParams = DomainId;
401 
402   Cmd.ProtocolId = SCMI_PROTOCOL_ID_PERFORMANCE;
403   Cmd.MessageId  = SCMI_MESSAGE_ID_PERFORMANCE_LEVEL_GET;
404 
405   PayloadLength = sizeof (DomainId);
406 
407   Status = ScmiCommandExecute (
408              &Cmd,
409              &PayloadLength,
410              &ReturnValues
411              );
412   if (EFI_ERROR (Status)) {
413     return Status;
414   }
415 
416   *Level = *ReturnValues;
417 
418   return EFI_SUCCESS;
419 }
420 
421 // Instance of the SCMI performance management protocol.
422 STATIC CONST SCMI_PERFORMANCE_PROTOCOL PerformanceProtocol = {
423   PerformanceGetVersion,
424   PerformanceGetAttributes,
425   PerformanceDomainAttributes,
426   PerformanceDescribeLevels,
427   PerformanceLimitsSet,
428   PerformanceLimitsGet,
429   PerformanceLevelSet,
430   PerformanceLevelGet
431 };
432 
433 /** Initialize performance management protocol and install on a given Handle.
434 
435   @param[in] Handle              Handle to install performance management
436                                  protocol.
437 
438   @retval EFI_SUCCESS            Performance protocol installed successfully.
439 **/
440 EFI_STATUS
ScmiPerformanceProtocolInit(IN EFI_HANDLE * Handle)441 ScmiPerformanceProtocolInit (
442   IN EFI_HANDLE* Handle
443   )
444 {
445   return gBS->InstallMultipleProtocolInterfaces (
446                 Handle,
447                 &gArmScmiPerformanceProtocolGuid,
448                 &PerformanceProtocol,
449                 NULL
450                 );
451 }
452