Skip to main content

sbi/
collaborative_processor_performance_control.rs

1// SPDX-License-Identifier: MPL-2.0
2// SPDX-FileCopyrightText: 2023 repnop
3//
4// This Source Code Form is subject to the terms of the Mozilla Public License,
5// v. 2.0. If a copy of the MPL was not distributed with this file, You can
6// obtain one at https://mozilla.org/MPL/2.0/.
7
8use crate::{ecall1, SbiError};
9
10/// Collaborative Processor Performance Control extension ID
11pub const EXTENSION_ID: usize = 0x43505043;
12
13#[doc(hidden)]
14pub trait CastRegisterValue: Sized + Copy {
15    fn cast(from: usize) -> Self;
16    fn reverse_cast(self) -> usize;
17    fn hi_lo(self) -> (usize, usize);
18}
19
20impl CastRegisterValue for u64 {
21    fn cast(from: usize) -> Self {
22        from as u64
23    }
24
25    fn reverse_cast(self) -> usize {
26        self as usize
27    }
28
29    fn hi_lo(self) -> (usize, usize) {
30        ((self >> 32) as usize, (self & 0xFFFF_FFFF) as usize)
31    }
32}
33
34impl CastRegisterValue for u32 {
35    fn cast(from: usize) -> Self {
36        from as u32
37    }
38
39    fn reverse_cast(self) -> usize {
40        self as usize
41    }
42
43    fn hi_lo(self) -> (usize, usize) {
44        (0, self as usize)
45    }
46}
47
48/// A CPPC register
49pub trait Register {
50    /// Register ID
51    const ID: u32;
52    /// Register value width
53    type Width: CastRegisterValue;
54}
55
56/// A register that can be read from
57pub trait Readable: Register {}
58/// A register that can be written to
59pub trait Writable: Register {}
60
61/// CPPC registers defined by the SBI specification
62pub mod registers {
63    use super::{Readable, Register, Writable};
64
65    /// ACPI Specification 6.5; 8.4.6.1.1 Highest Performance
66    ///
67    /// Highest performance is the absolute maximum performance an individual
68    /// processor may reach, assuming ideal conditions. This performance level
69    /// may not be sustainable for long durations, and may only be achievable if
70    /// other platform components are in a specific state; for example, it may
71    /// require other processors be in an idle state.
72    ///
73    /// Notify events of type 0x85 to the processor device object cause OSPM to
74    /// re-evaluate the Highest Performance Register, but only when it is
75    /// encoded as a buffer. Note: OSPM will not re-evaluate the _CPC object as
76    /// a result of the notification.
77    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
78    pub struct HighestPerformance;
79
80    impl Readable for HighestPerformance {}
81    impl Register for HighestPerformance {
82        const ID: u32 = 0x00000000;
83        type Width = u32;
84    }
85
86    /// ACPI Specification 6.5; 8.4.6.1.1.2 Nominal Performance
87    ///
88    /// Nominal Performance is the maximum sustained performance level of the
89    /// processor, assuming ideal operating conditions. In absence of an
90    /// external constraint (power, thermal, etc.) this is the performance level
91    /// the platform is expected to be able to maintain continuously. All
92    /// processors are expected to be able to sustain their nominal performance
93    /// state simultaneously.
94    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
95    pub struct NominalPerformance;
96
97    impl Readable for NominalPerformance {}
98    impl Register for NominalPerformance {
99        const ID: u32 = 0x00000001;
100        type Width = u32;
101    }
102
103    /// ACPI Specification 6.5; 8.4.6.1.1.4 Lowest Nonlinear Performance
104    ///
105    /// Lowest Nonlinear Performance is the lowest performance level at which
106    /// nonlinear power savings are achieved, for example, due to the combined
107    /// effects of voltage and frequency scaling. Above this threshold, lower
108    /// performance levels should be generally more energy efficient than higher
109    /// performance levels. In traditional terms, this represents the P-state
110    /// range of performance levels.
111    ///
112    /// This register effectively conveys the most efficient performance level
113    /// to OSPM.
114    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
115    pub struct LowestNonlinearPerformance;
116
117    impl Readable for LowestNonlinearPerformance {}
118    impl Register for LowestNonlinearPerformance {
119        const ID: u32 = 0x00000002;
120        type Width = u32;
121    }
122
123    /// ACPI Specification 6.5; 8.4.6.1.1.5 Lowest Performance
124    ///
125    /// Lowest Performance is the absolute lowest performance level of the
126    /// platform. Selecting a performance level lower than the lowest nonlinear
127    /// performance level may actually cause an efficiency penalty, but should
128    /// reduce the instantaneous power consumption of the processor. In
129    /// traditional terms, this represents the T-state range of performance
130    /// levels.
131    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
132    pub struct LowestPerformance;
133
134    impl Readable for LowestPerformance {}
135    impl Register for LowestPerformance {
136        const ID: u32 = 0x00000003;
137        type Width = u32;
138    }
139
140    /// ACPI Specification 6.5; 8.4.6.1.1.6 Guaranteed Performance
141    ///
142    /// Guaranteed Performance Register conveys to OSPM a Guaranteed Performance
143    /// level, which is the current maximum sustained performance level of a
144    /// processor, taking into account all known external constraints (power
145    /// budgeting, thermal constraints, AC vs DC power source, etc.). All
146    /// processors are expected to be able to sustain their guaranteed
147    /// performance levels simultaneously. The guaranteed performance level is
148    /// required to fall in the range \[Lowest Performance, Nominal
149    /// performance], inclusive.
150    ///
151    /// If this register is not implemented, OSPM assumes guaranteed performance
152    /// is always equal to nominal performance.
153    ///
154    /// Notify events of type 0x83 to the processor device object will cause
155    /// OSPM to re-evaluate the Guaranteed Performance Register. Changes to
156    /// guaranteed performance should not be more frequent than once per second.
157    /// If the platform is not able to guarantee a given performance level for a
158    /// sustained period of time (greater than one second), it should guarantee
159    /// a lower performance level and opportunistically enter the higher
160    /// performance level as requested by OSPM and allowed by current operating
161    /// conditions.
162    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
163    pub struct GuaranteedPerformance;
164
165    impl Readable for GuaranteedPerformance {}
166    impl Register for GuaranteedPerformance {
167        const ID: u32 = 0x00000004;
168        type Width = u32;
169    }
170
171    /// ACPI Specification 6.5; 8.4.6.1.2.3 Desired Performance
172    ///
173    /// When Autonomous Selection is disabled, the Desired Performance Register
174    /// is required and conveys the performance level OSPM is requesting from
175    /// the platform. Desired performance may be set to any performance value in
176    /// the range \[Minimum Performance, Maximum Performance], inclusive.
177    /// Desired performance may take one of two meanings, depending on whether
178    /// the desired performance is above or below the guaranteed performance
179    /// level.
180    ///
181    /// - Below the guaranteed performance level, desired performance expresses
182    ///   the average performance level the platform must provide subject to the
183    ///   Performance Reduction Tolerance.
184    /// - Above the guaranteed performance level, the platform must provide the
185    ///   guaranteed performance level. The platform should attempt to provide up
186    ///   to the desired performance level, if current operating conditions allow
187    ///   for it, but it is not required to do so
188    ///
189    /// When Autonomous Selection is enabled, it is not necessary for OSPM to
190    /// assess processor workload performance demand and convey a corresponding
191    /// performance delivery request to the platform via the Desired Register.
192    /// If the Desired Performance Register exists, OSPM may provide an explicit
193    /// performance requirement hint to the platform by writing a non-zero
194    /// value. In this case, the delivered performance is not bounded by the
195    /// Performance Reduction Tolerance Register, however, OSPM can influence
196    /// the delivered performance by writing appropriate values to the Energy
197    /// Performance Preference Register. Writing a zero value to the Desired
198    /// Performance Register or the non-existence of the Desired Performance
199    /// Register causes the platform to autonomously select a performance level
200    /// appropriate to the current workload.
201    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
202    pub struct DesiredPerformance;
203
204    impl Readable for DesiredPerformance {}
205    impl Writable for DesiredPerformance {}
206    impl Register for DesiredPerformance {
207        const ID: u32 = 0x00000005;
208        type Width = u32;
209    }
210
211    /// ACPI Specification 6.5; 8.4.6.1.2.2 Minimum Performance
212    ///
213    /// The Minimum Performance Register allows OSPM to convey the minimum
214    /// performance level at which the platform may run. Minimum performance may
215    /// be set to any performance value in the range \[Lowest Performance,
216    /// Highest Performance], inclusive but must be set to a value that is less
217    /// than or equal to that specified by the Maximum Performance Register.
218    ///
219    /// In the presence of a physical constraint, for example a thermal
220    /// excursion, the platform may not be able to successfully maintain minimum
221    /// performance in accordance with that set via the Minimum Performance
222    /// Register. In this case, the platform issues a Notify event of type 0x84
223    /// to the processor device object and sets the Minimum_Excursion bit within
224    /// the Performance Limited Register.
225    ///
226    /// The platform must implement either both the Minimum Performance and
227    /// Maximum Performance registers or neither register. If neither register
228    /// is implemented and Autonomous Selection is disabled, the platform must
229    /// always deliver the desired performance.
230    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
231    pub struct MinimumPerformance;
232
233    impl Readable for MinimumPerformance {}
234    impl Writable for MinimumPerformance {}
235    impl Register for MinimumPerformance {
236        const ID: u32 = 0x00000006;
237        type Width = u32;
238    }
239
240    /// ACPI Specification 6.5; 8.4.6.1.2.1 Maximum Performance
241    ///
242    /// Maximum Performance Register conveys the maximum performance level at
243    /// which the platform may run. Maximum performance may be set to any
244    /// performance value in the range \[Lowest Performance, Highest
245    /// Performance], inclusive.
246    ///
247    /// The value written to the Maximum Performance Register conveys a request
248    /// to limit maximum performance for the purpose of energy efficiency or
249    /// thermal control and the platform limits its performance accordingly as
250    /// possible. However, the platform may exceed the requested limit in the
251    /// event it is necessitated by internal package optimization. For example,
252    /// hardware coordination among multiple logical processors with
253    /// interdependencies.
254    ///
255    /// OSPM’s use of this register to limit performance for the purpose of
256    /// thermal control must comprehend multiple logical processors with
257    /// interdependencies. i.e. the same value must be written to all processors
258    /// within a domain to achieve the desired result.
259    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
260    pub struct MaximumPerformance;
261
262    impl Readable for MaximumPerformance {}
263    impl Writable for MaximumPerformance {}
264    impl Register for MaximumPerformance {
265        const ID: u32 = 0x00000007;
266        type Width = u32;
267    }
268
269    /// ACPI Specification 6.5; 8.4.6.1.2.4 Performance Reduction Tolerance
270    ///
271    /// The Performance Reduction Tolerance Register is used by OSPM to convey
272    /// the deviation below the Desired Performance that is tolerable. It is
273    /// expressed by OSPM as an absolute value on the performance scale.
274    /// Performance Tolerance must be less than or equal to the Desired
275    /// Performance. If the platform supports the Time Window Register, the
276    /// Performance Reduction Tolerance conveys the minimal performance value
277    /// that may be delivered on average over the Time Window. If this register
278    /// is not implemented, the platform must assume Performance Reduction
279    /// Tolerance = Desired Performance.
280    ///
281    /// When Autonomous Selection is enabled, values written to the Performance
282    /// Reduction Tolerance Register are ignored.
283    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
284    pub struct PerformanceReductionTolerance;
285
286    impl Readable for PerformanceReductionTolerance {}
287    impl Writable for PerformanceReductionTolerance {}
288    impl Register for PerformanceReductionTolerance {
289        const ID: u32 = 0x00000008;
290        type Width = u32;
291    }
292
293    /// ACPI Specification 6.5; 8.4.6.1.2.5 Time Window
294    ///
295    /// When Autonomous Selection is not enabled, OSPM may write a value to the
296    /// Time Window Register to indicate a time window over which the platform
297    /// must provide the desired performance level (subject to the Performance
298    /// Reduction Tolerance). OSPM sets the time window when electing a new
299    /// desired performance The time window represents the minimum time duration
300    /// for OSPM’s evaluation of the platform’s delivered performance (see
301    /// Performance Counters “Performance Counters” for details on how OSPM
302    /// computes delivered performance). If OSPM evaluates delivered performance
303    /// over an interval smaller than the specified time window, it has no
304    /// expectations of the performance delivered by the platform. For any
305    /// evaluation interval equal to or greater than the time window, the
306    /// platform must deliver the OSPM desired performance within the specified
307    /// tolerance bound.
308    ///
309    /// If OSPM specifies a time window of zero or if the platform does not
310    /// support the time window register, the platform must deliver performance
311    /// within the bounds of Performance Reduction Tolerance irrespective of the
312    /// duration of the evaluation interval.
313    ///
314    /// When Autonomous Selection is enabled, values written to the Time Window
315    /// Register are ignored. Reads of the Time Window register indicate minimum
316    /// length of time (in ms) between successive reads of the platform’s
317    /// performance counters. If the Time Window register is not supported then
318    /// there is no minimum time requirement between successive reads of the
319    /// platform’s performance counters.
320    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
321    pub struct TimeWindow;
322
323    impl Readable for TimeWindow {}
324    impl Writable for TimeWindow {}
325    impl Register for TimeWindow {
326        const ID: u32 = 0x00000009;
327        type Width = u32;
328    }
329
330    /// ACPI Specification 6.5; 8.4.6.1.3.1 Performance Counters; Counter Wraparound Time
331    ///
332    /// Counter Wraparound Time provides a means for the platform to specify a
333    /// rollover time for the Reference/Delivered performance counters. If
334    /// greater than this time period elapses between OSPM querying the feedback
335    /// counters, the counters may wrap without OSPM being able to detect that
336    /// they have done so. If not implemented (or zero), the performance
337    /// counters are assumed to never wrap during the lifetime of the platform.
338    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
339    pub struct CounterWraparoundTime;
340
341    impl Readable for CounterWraparoundTime {}
342    impl Register for CounterWraparoundTime {
343        const ID: u32 = 0x0000000A;
344        type Width = u64;
345    }
346
347    /// ACPI Specification 6.5; 8.4.6.1.3.1 Performance Counters; Reference Performance Counter
348    ///
349    /// The Reference Performance Counter Register counts at a fixed rate any
350    /// time the processor is active. It is not affected by changes to Desired
351    /// Performance, processor throttling, etc. If Reference Performance is
352    /// supported, the Reference Performance Counter accumulates at a rate
353    /// corresponding to the Reference Performance level. Otherwise, the
354    /// Reference Performance Counter accumulates at the Nominal performance
355    /// level.
356    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
357    pub struct ReferencePerformanceCounter;
358
359    impl Readable for ReferencePerformanceCounter {}
360    impl Register for ReferencePerformanceCounter {
361        const ID: u32 = 0x0000000B;
362        type Width = u64;
363    }
364
365    /// ACPI Specification 6.5; 8.4.6.1.3.1 Performance Counters; Delivered Performance Counter
366    ///
367    /// The Delivered Performance Counter Register increments any time the
368    /// processor is active, at a rate proportional to the current performance
369    /// level, taking into account changes to Desired Performance. When the
370    /// processor is operating at its reference performance level, the delivered
371    /// performance counter must increment at the same rate as the reference
372    /// performance counter.
373    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
374    pub struct DeliveredPerformanceCounter;
375
376    impl Readable for DeliveredPerformanceCounter {}
377    impl Register for DeliveredPerformanceCounter {
378        const ID: u32 = 0x0000000C;
379        type Width = u64;
380    }
381
382    /// ACPI Specification 6.5; 8.4.6.1.3.2 Performance Limited Register
383    ///
384    /// In the event that the platform constrains the delivered performance to
385    /// less than the minimum performance or the desired performance (or, less
386    /// than the guaranteed performance, if desired performance is greater than
387    /// guaranteed performance) due to an unpredictable event, the platform sets
388    /// the performance limited indicator to a non-zero value. This indicates to
389    /// OSPM that an unpredictable event has limited processor performance, and
390    /// the delivered performance may be less than desired / minimum
391    /// performance. If the platform does not support signaling performance
392    /// limited events, this register is permitted to always return zero when
393    /// read.
394    ///
395    /// | Bit | Name              | Description                                                                                                                                                                                                                                                      |
396    /// |-----|-------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
397    /// | 0   | Desired_Excursion | Set when Delivered Performance has been constrained to less than Desired Performance (or, less than the guaranteed performance, if desired performance is greater than guaranteed performance). This bit is not utilized when Autonomous Selection is enabled. |
398    /// | 1   | Minimum_Excursion | Set when Delivered Performance has been constrained to less than Minimum Performance                                                                                                                                                                             |
399    /// | 2-n | Reserved          | Reserved                                                                                                                                                                                                                                                         |
400    ///
401    /// Bits within the Performance Limited Register are sticky, and will remain
402    /// non-zero until OSPM clears the bit. The platform should only issue a
403    /// Notify when Minimum Excursion transitions from 0 to 1 to avoid repeated
404    /// events when there is sustained or recurring limiting but OSPM has not
405    /// cleared the previous indication.
406    ///
407    /// The performance limited register should only be used to report short
408    /// term, unpredictable events (e.g., PROCHOT being asserted). If the
409    /// platform is capable of identifying longer term, predictable events that
410    /// limit processor performance, it should use the guaranteed performance
411    /// register to notify OSPM of this limitation. Changes to guaranteed
412    /// performance should not be more frequent than once per second. If the
413    /// platform is not able to guarantee a given performance level for a
414    /// sustained period of time (greater than one second), it should guarantee
415    /// a lower performance level and opportunistically enter the higher
416    /// performance level as requested by OSPM and allowed by current operating
417    /// conditions.
418    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
419    pub struct PerformanceLimited;
420
421    impl Readable for PerformanceLimited {}
422    impl Writable for PerformanceLimited {}
423    impl Register for PerformanceLimited {
424        const ID: u32 = 0x0000000D;
425        type Width = u32;
426    }
427
428    /// ACPI Specification 6.5; 8.4.6.1.4 CPPC Enable Register
429    ///
430    /// If supported by the platform, OSPM writes a one to this register to
431    /// enable CPPC on this processor.
432    ///
433    /// If not implemented, OSPM assumes the platform always has CPPC enabled.
434    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
435    pub struct CppcEnable;
436
437    impl Readable for CppcEnable {}
438    impl Writable for CppcEnable {}
439    impl Register for CppcEnable {
440        const ID: u32 = 0x0000000E;
441        type Width = u32;
442    }
443
444    /// ACPI Specification 6.5; 8.4.6.1.5 Autonomous Selection Enable Register
445    ///
446    /// If supported by the platform, OSPM writes a one to this register to
447    /// enable Autonomous Performance Level Selection on this processor. CPPC
448    /// must be enabled via the CPPC Enable Register to enable Autonomous
449    /// Performance Level Selection. Platforms that exclusively support
450    /// Autonomous Selection must populate this field as an Integer with a value
451    /// of 1.
452    ///
453    /// When Autonomous Selection is enabled, the platform is responsible for
454    /// selecting performance states. OSPM is not required to assess processor
455    /// workload performance demand and convey a corresponding performance
456    /// delivery request to the platform via the Desired Performance Register.
457    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
458    pub struct AutonomousSelectionEnable;
459
460    impl Readable for AutonomousSelectionEnable {}
461    impl Writable for AutonomousSelectionEnable {}
462    impl Register for AutonomousSelectionEnable {
463        const ID: u32 = 0x0000000F;
464        type Width = u32;
465    }
466
467    /// ACPI Specification 6.5; 8.4.6.1.6 Autonomous Activity Window Register
468    ///
469    /// If supported by the platform, OSPM may write a time value (10^3-bit exp
470    /// * 7-bit mantissa in 1μsec units: 1us to 1270 sec) to this field to
471    ///   indicate a moving utilization sensitivity window to the platform’s
472    ///   autonomous selection policy. Combined with the Energy Performance
473    ///   Preference Register value, the Activity Window influences the rate of
474    ///   performance increase / decrease of the platform’s autonomous selection
475    ///   policy. OSPM writes a zero value to this register to enable the platform
476    ///   to determine an appropriate Activity Window depending on the workload.
477    ///
478    /// Writes to this register only have meaning when Autonomous Selection is
479    /// enabled.
480    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
481    pub struct AutonomousAcivityWindow;
482
483    impl Readable for AutonomousAcivityWindow {}
484    impl Writable for AutonomousAcivityWindow {}
485    impl Register for AutonomousAcivityWindow {
486        const ID: u32 = 0x00000010;
487        type Width = u32;
488    }
489
490    /// ACPI Specification 6.5; 8.4.6.1.7 Energy Performance Preference Register
491    ///
492    /// If supported by the platform, OSPM may write a range of values from 0
493    /// (performance preference) to 0xFF (energy efficiency preference) that
494    /// influences the rate of performance increase /decrease and the result of
495    /// the hardware’s energy efficiency and performance optimization
496    /// policies.This provides a means for OSPM to limit the energy efficiency
497    /// impact of the platform’s performance-related optimizations / control
498    /// policy and the performance impact of the platform’s energy
499    /// efficiency-related optimizations / control policy.
500    ///
501    /// Writes to this register only have meaning when Autonomous Selection is
502    /// enabled.
503    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
504    pub struct EnergyPerformancePreference;
505
506    impl Readable for EnergyPerformancePreference {}
507    impl Writable for EnergyPerformancePreference {}
508    impl Register for EnergyPerformancePreference {
509        const ID: u32 = 0x00000011;
510        type Width = u32;
511    }
512
513    /// ACPI Specification 6.5; 8.4.6.1.1.3 Reference Performance
514    ///
515    /// If supported by the platform, Reference Performance is the rate at which
516    /// the Reference Performance Counter increments. If not implemented (or
517    /// zero), the Reference Performance Counter increments at a rate
518    /// corresponding to the Nominal Performance level.
519    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
520    pub struct ReferencePerformance;
521
522    impl Readable for ReferencePerformance {}
523    impl Register for ReferencePerformance {
524        const ID: u32 = 0x00000012;
525        type Width = u32;
526    }
527
528    /// ACPI Specification 6.5; 8.4.6.1.1.5 Lowest Performance
529    ///
530    /// Lowest Performance is the absolute lowest performance level of the
531    /// platform. Selecting a performance level lower than the lowest nonlinear
532    /// performance level may actually cause an efficiency penalty, but should
533    /// reduce the instantaneous power consumption of the processor. In
534    /// traditional terms, this represents the T-state range of performance
535    /// levels.
536    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
537    pub struct LowestFrequency;
538
539    impl Readable for LowestFrequency {}
540    impl Register for LowestFrequency {
541        const ID: u32 = 0x00000013;
542        type Width = u32;
543    }
544
545    /// ACPI Specification 6.5; 8.4.6.1.1.2 Nominal Performance
546    ///
547    /// Nominal Performance is the maximum sustained performance level of the
548    /// processor, assuming ideal operating conditions. In absence of an
549    /// external constraint (power, thermal, etc.) this is the performance level
550    /// the platform is expected to be able to maintain continuously. All
551    /// processors are expected to be able to sustain their nominal performance
552    /// state simultaneously.
553    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
554    pub struct NominalFrequency;
555
556    impl Readable for NominalFrequency {}
557    impl Register for NominalFrequency {
558        const ID: u32 = 0x00000014;
559        type Width = u32;
560    }
561
562    /// Provides the maximum (worst-case) performance state transition latency
563    /// in nanoseconds.
564    #[derive(Debug, Clone, Copy, PartialEq, Eq)]
565    pub struct TransitionLatency;
566
567    impl Readable for TransitionLatency {}
568    impl Register for TransitionLatency {
569        const ID: u32 = 0x80000000;
570        type Width = u32;
571    }
572}
573
574/// Probe whether the given CPPC register is supported. On success, this
575/// function returns the width of the register in bits, if the register is
576/// implemented.
577///
578/// ### Possible errors
579///
580/// [`SbiError::INVALID_PARAMETER`]: The register ID is a reserved ID.
581///
582/// [`SbiError::FAILED`]: The probe request failed for unspecified or unknown
583///     reasons.
584#[doc(alias = "sbi_cppc_probe")]
585pub fn probe_register<R: Register>(
586    #[allow(unused_variables)] register: R,
587) -> Result<Option<usize>, SbiError> {
588    let ret = unsafe { ecall1(R::ID as usize, EXTENSION_ID, 0) }?;
589
590    match ret {
591        0 => Ok(None),
592        _ => Ok(Some(ret)),
593    }
594}
595
596/// Read the value of a CPPC register. When `XLEN` is 32, this value only
597/// contains the lower 32 bits of the full register value, and a subsequent call
598/// to [`read_register_hi`] is required to read the full value if the register
599/// size is >32 bits. When `XLEN` is >= 64, no further calls are required.
600///
601/// ### Possible errors
602///
603/// [`SbiError::INVALID_PARAMETER`]: The register ID is a reserved ID.
604///
605/// [`SbiError::NOT_SUPPORTED`]: The register is not implemented by the platform.
606///
607/// [`SbiError::DENIED`]: The register is write-only.
608///
609/// [`SbiError::FAILED`]: The read request failed for unspecified or unknown
610///     reasons.
611#[doc(alias = "sbi_cppc_read")]
612pub fn read_register<R: Readable>(
613    #[allow(unused_variables)] register: R,
614) -> Result<R::Width, SbiError> {
615    unsafe { ecall1(R::ID as usize, EXTENSION_ID, 1) }.map(<R::Width as CastRegisterValue>::cast)
616}
617
618/// Read the upper 32 bits of the register value. When `XLEN` >= 64, this
619/// function will always return `0` for valid register IDs.
620///
621/// ### Possible errors
622///
623/// [`SbiError::INVALID_PARAMETER`]: The register ID is a reserved ID.
624///
625/// [`SbiError::NOT_SUPPORTED`]: The register is not implemented by the platform.
626///
627/// [`SbiError::DENIED`]: The register is write-only.
628///
629/// [`SbiError::FAILED`]: The read request failed for unspecified or unknown
630///     reasons.
631#[doc(alias = "sbi_cppc_read_hi")]
632pub fn read_register_hi<R: Readable>(
633    #[allow(unused_variables)] register: R,
634) -> Result<R::Width, SbiError> {
635    unsafe { ecall1(R::ID as usize, EXTENSION_ID, 2) }.map(<R::Width as CastRegisterValue>::cast)
636}
637
638/// Write a value to the specified CPPC register.
639///
640/// ### Possible errors
641///
642/// [`SbiError::INVALID_PARAMETER`]: The register ID is a reserved ID.
643///
644/// [`SbiError::NOT_SUPPORTED`]: The register is not implemented by the platform.
645///
646/// [`SbiError::DENIED`]: The register is read-only.
647///
648/// [`SbiError::FAILED`]: The write request failed for unspecified or unknown
649///     reasons.
650#[doc(alias = "sbi_cppc_write")]
651pub fn write_register<R: Readable>(
652    #[allow(unused_variables)] register: R,
653    value: R::Width,
654) -> Result<(), SbiError> {
655    #[cfg(target_arch = "riscv64")]
656    unsafe {
657        crate::ecall2(
658            R::ID as usize,
659            <R::Width as CastRegisterValue>::reverse_cast(value),
660            EXTENSION_ID,
661            3,
662        )?;
663    };
664
665    #[cfg(target_arch = "riscv32")]
666    unsafe {
667        let (high, low) = <R::Width as CastRegisterValue>::hi_lo(value);
668        crate::ecall3(R::ID as usize, low, high, EXTENSION_ID, 3)?;
669    };
670
671    Ok(())
672}