浏览代码

feat: support CPPC extension

jakezhu9 1 年之前
父节点
当前提交
631966eedf
共有 4 个文件被更改,包括 256 次插入26 次删除
  1. 131 0
      src/cppc.rs
  2. 112 16
      src/instance.rs
  3. 6 3
      src/lib.rs
  4. 7 7
      src/susp.rs

+ 131 - 0
src/cppc.rs

@@ -0,0 +1,131 @@
+use sbi_spec::binary::SbiRet;
+
+/// CPPC Extension
+///
+/// ACPI defines the Collaborative Processor Performance Control (CPPC) mechanism,
+/// which is an abstract and flexible mechanism for the supervisor-mode
+/// power-management software to collaborate with an entity in the platform to
+/// manage the performance of the processors.
+///
+/// The SBI CPPC extension provides an abstraction to access the CPPC registers
+/// through SBI calls. The CPPC registers can be memory locations shared with a
+/// separate platform entity such as a BMC. Even though CPPC is defined in the ACPI
+/// specification, it may be possible to implement a CPPC driver based on
+/// Device Tree.
+///
+/// The table below defines 32-bit identifiers for all CPPC registers
+/// to be used by the SBI CPPC functions. The first half of the 32-bit register
+/// space corresponds to the registers as defined by the ACPI specification.
+/// The second half provides the information not defined in the ACPI specification,
+/// but is additionally required by the supervisor-mode power-management software.
+///
+/// | Register ID             | Register                              | Bit Width | Attribute    | Description               
+/// | ----------------------- | ------------------------------------- | --------- | ------------ | ---------------------------
+/// | 0x00000000              | HighestPerformance                    | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.1  
+/// | 0x00000001              | NominalPerformance                    | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.2   
+/// | 0x00000002              | LowestNonlinearPerformance            | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.4
+/// | 0x00000003              | LowestPerformance                     | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.5
+/// | 0x00000004              | GuaranteedPerformanceRegister         | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.6
+/// | 0x00000005              | DesiredPerformanceRegister            | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.2.3
+/// | 0x00000006              | MinimumPerformanceRegister            | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.2.2
+/// | 0x00000007              | MaximumPerformanceRegister            | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.2.1
+/// | 0x00000008              | PerformanceReductionToleranceRegister | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.2.4
+/// | 0x00000009              | TimeWindowRegister                    | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.2.5
+/// | 0x0000000A              | CounterWraparoundTime                 | 32 / 64   | Read-only    | ACPI Spec 6.5: 8.4.6.1.3.1
+/// | 0x0000000B              | ReferencePerformanceCounterRegister   | 32 / 64   | Read-only    | ACPI Spec 6.5: 8.4.6.1.3.1
+/// | 0x0000000C              | DeliveredPerformanceCounterRegister   | 32 / 64   | Read-only    | ACPI Spec 6.5: 8.4.6.1.3.1
+/// | 0x0000000D              | PerformanceLimitedRegister            | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.3.2
+/// | 0x0000000E              | CPPCEnableRegister                    | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.4
+/// | 0x0000000F              | AutonomousSelectionEnable             | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.5
+/// | 0x00000010              | AutonomousActivityWindowRegister      | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.6
+/// | 0x00000011              | EnergyPerformancePreferenceRegister   | 32        | Read / Write | ACPI Spec 6.5: 8.4.6.1.7  
+/// | 0x00000012              | ReferencePerformance                  | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.3  
+/// | 0x00000013              | LowestFrequency                       | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.7
+/// | 0x00000014              | NominalFrequency                      | 32        | Read-only    | ACPI Spec 6.5: 8.4.6.1.1.7
+/// | 0x00000015 - 0x7FFFFFFF |                                       |           |              | Reserved for future use.     
+/// | 0x80000000              | TransitionLatency                     | 32        | Read-only    | Provides the maximum (worst-case) performance state transition latency in nanoseconds.
+/// | 0x80000001 - 0xFFFFFFFF |                                       |           |              | Reserved for future use.   
+///
+pub trait Cppc: Send + Sync {
+    /// Probe whether the CPPC register as specified by the `reg_id` parameter
+    /// is implemented or not by the platform.
+    ///
+    /// # Return value
+    ///
+    /// If the register is implemented, `SbiRet.value` will contain the register
+    /// width. If the register is not implemented, `SbiRet.value` will be set to 0.
+    ///
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Error code                | Description   
+    /// | ------------------------- | ---------------
+    /// | `SbiRet::success()`       | Probe completed successfully.
+    /// | `SbiRet::invalid_param()` | `reg_id` is reserved.
+    /// | `SbiRet::failed()`        | The probe request failed for unspecified or unknown other reasons.
+    fn probe(&self, reg_id: u32) -> SbiRet;
+    /// Reads the register as specified in the `reg_id` parameter.
+    ///
+    /// # Return value
+    ///
+    /// Returns the value of the register in `SbiRet.value`. When supervisor mode XLEN is 32,
+    /// the `SbiRet.value` will only contain the lower 32 bits of the CPPC register value.
+    ///
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Error code                | Description
+    /// | ------------------------- | -------------------
+    /// | `SbiRet::success()`       | Read completed successfully.
+    /// | `SbiRet::invalid_param()` | `reg_id` is reserved.
+    /// | `SbiRet::not_supported()` | `reg_id` is not implemented by the platform.
+    /// | `SbiRet::denied()`        | `reg_id` is a write-only register.  
+    /// | `SbiRet::failed()`        | The read request failed for unspecified or unknown other reasons.
+    fn read(&self, reg_id: u32) -> SbiRet;
+    /// Reads the upper 32-bit value of the register specified in the `reg_id`
+    /// parameter.
+    ///
+    /// # Return value
+    ///
+    /// Returns the value of the register in `SbiRet.value`. This function always
+    /// returns zero in `SbiRet.value` when supervisor mode XLEN is 64 or higher.
+    ///
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Error code                | Description
+    /// | ------------------------- | -------------------
+    /// | `SbiRet::success()`       | Read completed successfully.
+    /// | `SbiRet::invalid_param()` | `reg_id` is reserved.
+    /// | `SbiRet::not_supported()` | `reg_id` is not implemented by the platform.
+    /// | `SbiRet::denied()`        | `reg_id` is a write-only register.  
+    /// | `SbiRet::failed()`        | The read request failed for unspecified or unknown other reasons.
+    fn read_hi(&self, reg_id: u32) -> SbiRet;
+    /// Writes the value passed in the `val` parameter to the register as
+    /// specified in the `reg_id` parameter.
+    ///
+    /// # Return value
+    ///
+    /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
+    ///
+    /// | Error code                | Description        
+    /// | ------------------------- | -------------------
+    /// | `SbiRet::success()`       | Write completed successfully.  
+    /// | `SbiRet::invalid_param()` | `reg_id` is reserved.       
+    /// | `SbiRet::not_supported()` | `reg_id` is not implemented by the platform.  
+    /// | `SbiRet::denied()`        | `reg_id` is a read-only register.
+    /// | `SbiRet::failed()`        | The write request failed for unspecified or unknown other reasons.
+    fn write(&self, reg_id: u32, val: u64) -> SbiRet;
+}
+
+impl<T: Cppc> Cppc for &T {
+    fn probe(&self, reg_id: u32) -> SbiRet {
+        T::probe(self, reg_id)
+    }
+    fn read(&self, reg_id: u32) -> SbiRet {
+        T::read(self, reg_id)
+    }
+    fn read_hi(&self, reg_id: u32) -> SbiRet {
+        T::read_hi(self, reg_id)
+    }
+    fn write(&self, reg_id: u32, val: u64) -> SbiRet {
+        T::write(self, reg_id, val)
+    }
+}

+ 112 - 16
src/instance.rs

@@ -1,5 +1,5 @@
 use crate::{
-    spec::binary::SbiRet, Console, Fence, HartMask, Hsm, Ipi, Pmu, Reset, Susp, Timer,
+    spec::binary::SbiRet, Console, Cppc, Fence, HartMask, Hsm, Ipi, Pmu, Reset, Susp, Timer,
     IMPL_ID_RUSTSBI, RUSTSBI_VERSION, SBI_SPEC_MAJOR, SBI_SPEC_MINOR,
 };
 use core::convert::Infallible;
@@ -12,7 +12,7 @@ use spec::binary::Physical;
 /// By now RustSBI supports to run instance based interface on systems has environment pointer width
 /// that is the same as supervisor pointer width.
 #[derive(Clone, Debug)]
-pub struct RustSBI<T, I, R, H, S, P, C, SU> {
+pub struct RustSBI<T, I, R, H, S, P, C, SU, CP> {
     timer: Option<T>,
     ipi: Option<I>,
     rfnc: Option<R>,
@@ -21,6 +21,7 @@ pub struct RustSBI<T, I, R, H, S, P, C, SU> {
     pmu: Option<P>,
     dbcn: Option<C>,
     susp: Option<SU>,
+    cppc: Option<CP>,
     #[cfg(not(feature = "machine"))]
     info: MachineInfo,
 }
@@ -39,8 +40,8 @@ pub struct MachineInfo {
     pub mimpid: usize,
 }
 
-impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
-    RustSBI<T, I, R, H, S, P, C, SU>
+impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp, CP: Cppc>
+    RustSBI<T, I, R, H, S, P, C, SU, CP>
 {
     /// Create RustSBI instance on current machine environment for all the SBI extensions
     #[cfg(feature = "machine")]
@@ -54,6 +55,7 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
         pmu: P,
         dbcn: C,
         susp: SU,
+        cppc: CP,
     ) -> Self {
         Self {
             timer: Some(timer),
@@ -64,6 +66,7 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
             pmu: Some(pmu),
             dbcn: Some(dbcn),
             susp: Some(susp),
+            cppc: Some(cppc),
         }
     }
 
@@ -80,6 +83,7 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
         pmu: P,
         dbcn: C,
         susp: SU,
+        cppc: CP,
         info: MachineInfo,
     ) -> Self {
         Self {
@@ -91,6 +95,7 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
             pmu: Some(pmu),
             dbcn: Some(dbcn),
             susp: Some(susp),
+            cppc: Some(cppc),
             info,
         }
     }
@@ -318,6 +323,48 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
                     _ => SbiRet::not_supported(),
                 }
             }
+            spec::cppc::EID_CPPC => match () {
+                #[cfg(target_pointer_width = "64")]
+                () => {
+                    let Some(cppc) = &mut self.cppc else {
+                        return SbiRet::not_supported();
+                    };
+                    let [param0, param1] = [param[0], param[1]];
+                    match function {
+                        spec::cppc::PROBE => match u32::try_from(param0) {
+                            Ok(reg_id) => cppc.probe(reg_id),
+                            _ => SbiRet::invalid_param(),
+                        },
+                        spec::cppc::READ => match u32::try_from(param0) {
+                            Ok(reg_id) => cppc.read(reg_id),
+                            _ => SbiRet::invalid_param(),
+                        },
+                        spec::cppc::READ_HI => match u32::try_from(param0) {
+                            Ok(reg_id) => cppc.read_hi(reg_id),
+                            _ => SbiRet::invalid_param(),
+                        },
+                        spec::cppc::WRITE => match u32::try_from(param0) {
+                            Ok(reg_id) => cppc.write(reg_id, param1 as _),
+                            _ => SbiRet::invalid_param(),
+                        },
+                        _ => SbiRet::not_supported(),
+                    }
+                }
+                #[cfg(target_pointer_width = "32")]
+                () => {
+                    let Some(cppc) = &mut self.cppc else {
+                        return SbiRet::not_supported();
+                    };
+                    let [param0, param1, param2] = [param[0], param[1], param[2]];
+                    match function {
+                        spec::cppc::PROBE => cppc.probe(param0),
+                        spec::cppc::READ => cppc.read(param0),
+                        spec::cppc::READ_HI => cppc.read(param0),
+                        spec::cppc::WRITE => cppc.write(param0, concat_u32(param2, param1)),
+                        _ => SbiRet::not_supported(),
+                    }
+                }
+            },
             _ => SbiRet::not_supported(),
         }
     }
@@ -333,6 +380,8 @@ impl<T: Timer, I: Ipi, R: Fence, H: Hsm, S: Reset, P: Pmu, C: Console, SU: Susp>
             spec::hsm::EID_HSM => self.hsm.is_some(),
             spec::pmu::EID_PMU => self.pmu.is_some(),
             spec::dbcn::EID_DBCN => self.dbcn.is_some(),
+            spec::susp::EID_SUSP => self.susp.is_some(),
+            spec::cppc::EID_CPPC => self.cppc.is_some(),
             _ => false,
         };
         if ans {
@@ -350,8 +399,8 @@ const fn concat_u32(h: usize, l: usize) -> u64 {
 }
 
 /// Structure to build a RustSBI instance
-pub struct Builder<T, I, R, H, S, P, C, SU> {
-    inner: RustSBI<T, I, R, H, S, P, C, SU>,
+pub struct Builder<T, I, R, H, S, P, C, SU, CP> {
+    inner: RustSBI<T, I, R, H, S, P, C, SU, CP>,
 }
 
 impl
@@ -364,6 +413,7 @@ impl
         Infallible,
         Infallible,
         Infallible,
+        Infallible,
     >
 {
     /// Create a new `Builder` from current machine environment
@@ -378,6 +428,7 @@ impl
         Infallible,
         Infallible,
         Infallible,
+        Infallible,
     > {
         Builder {
             inner: RustSBI {
@@ -389,6 +440,7 @@ impl
                 pmu: None,
                 dbcn: None,
                 susp: None,
+                cppc: None,
             },
         }
     }
@@ -407,6 +459,7 @@ impl
         Infallible,
         Infallible,
         Infallible,
+        Infallible,
     > {
         Builder {
             inner: RustSBI {
@@ -418,6 +471,7 @@ impl
                 pmu: None,
                 dbcn: None,
                 susp: None,
+                cppc: None,
                 info,
             },
         }
@@ -430,10 +484,10 @@ impl
 
 // fixme: struct `Infallible` should be replaced to never type once it's stablized
 
-impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
+impl<T, I, R, H, S, P, C, SU, CP> Builder<T, I, R, H, S, P, C, SU, CP> {
     /// Add Timer programmer extension to RustSBI
     #[inline]
-    pub fn with_timer<T2: Timer>(self, timer: T2) -> Builder<T2, I, R, H, S, P, C, SU> {
+    pub fn with_timer<T2: Timer>(self, timer: T2) -> Builder<T2, I, R, H, S, P, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: Some(timer),
@@ -444,6 +498,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -452,7 +507,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Add Inter-processor Interrupt extension to RustSBI
     #[inline]
-    pub fn with_ipi<I2: Ipi>(self, ipi: I2) -> Builder<T, I2, R, H, S, P, C, SU> {
+    pub fn with_ipi<I2: Ipi>(self, ipi: I2) -> Builder<T, I2, R, H, S, P, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -463,6 +518,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -471,7 +527,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Add Remote Fence extension to RustSBI
     #[inline]
-    pub fn with_fence<R2: Fence>(self, fence: R2) -> Builder<T, I, R2, H, S, P, C, SU> {
+    pub fn with_fence<R2: Fence>(self, fence: R2) -> Builder<T, I, R2, H, S, P, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -482,6 +538,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -490,7 +547,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Add Hart State Monitor extension to RustSBI
     #[inline]
-    pub fn with_hsm<H2: Hsm>(self, hsm: H2) -> Builder<T, I, R, H2, S, P, C, SU> {
+    pub fn with_hsm<H2: Hsm>(self, hsm: H2) -> Builder<T, I, R, H2, S, P, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -501,6 +558,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -509,7 +567,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Add System Reset extension to RustSBI
     #[inline]
-    pub fn with_reset<S2: Reset>(self, reset: S2) -> Builder<T, I, R, H, S2, P, C, SU> {
+    pub fn with_reset<S2: Reset>(self, reset: S2) -> Builder<T, I, R, H, S2, P, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -520,6 +578,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -528,7 +587,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Add Performance Monitor Unit extension to RustSBI
     #[inline]
-    pub fn with_pmu<P2: Pmu>(self, pmu: P2) -> Builder<T, I, R, H, S, P2, C, SU> {
+    pub fn with_pmu<P2: Pmu>(self, pmu: P2) -> Builder<T, I, R, H, S, P2, C, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -539,6 +598,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: Some(pmu),
                 dbcn: self.inner.dbcn,
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -546,7 +606,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
     }
     /// Add Debug Console extension to RustSBI
     #[inline]
-    pub fn with_console<C2: Console>(self, console: C2) -> Builder<T, I, R, H, S, P, C2, SU> {
+    pub fn with_console<C2: Console>(self, console: C2) -> Builder<T, I, R, H, S, P, C2, SU, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -557,6 +617,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: Some(console),
                 susp: self.inner.susp,
+                cppc: self.inner.cppc,
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -564,7 +625,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
     }
     /// Add System Suspend extension to RustSBI
     #[inline]
-    pub fn with_susp<SU2: Susp>(self, susp: SU2) -> Builder<T, I, R, H, S, P, C, SU2> {
+    pub fn with_susp<SU2: Susp>(self, susp: SU2) -> Builder<T, I, R, H, S, P, C, SU2, CP> {
         Builder {
             inner: RustSBI {
                 timer: self.inner.timer,
@@ -575,6 +636,26 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
                 pmu: self.inner.pmu,
                 dbcn: self.inner.dbcn,
                 susp: Some(susp),
+                cppc: self.inner.cppc,
+                #[cfg(not(feature = "machine"))]
+                info: self.inner.info,
+            },
+        }
+    }
+    /// Add CPPC extension to RustSBI
+    #[inline]
+    pub fn with_cppc<CP2: Cppc>(self, cppc: CP2) -> Builder<T, I, R, H, S, P, C, SU, CP2> {
+        Builder {
+            inner: RustSBI {
+                timer: self.inner.timer,
+                ipi: self.inner.ipi,
+                rfnc: self.inner.rfnc,
+                hsm: self.inner.hsm,
+                srst: self.inner.srst,
+                pmu: self.inner.pmu,
+                dbcn: self.inner.dbcn,
+                susp: self.inner.susp,
+                cppc: Some(cppc),
                 #[cfg(not(feature = "machine"))]
                 info: self.inner.info,
             },
@@ -583,7 +664,7 @@ impl<T, I, R, H, S, P, C, SU> Builder<T, I, R, H, S, P, C, SU> {
 
     /// Build the target RustSBI instance
     #[inline]
-    pub fn build(self) -> RustSBI<T, I, R, H, S, P, C, SU> {
+    pub fn build(self) -> RustSBI<T, I, R, H, S, P, C, SU, CP> {
         self.inner
     }
 }
@@ -710,3 +791,18 @@ impl Susp for Infallible {
         unreachable!()
     }
 }
+
+impl Cppc for Infallible {
+    fn probe(&self, _: u32) -> SbiRet {
+        unreachable!()
+    }
+    fn read(&self, _: u32) -> SbiRet {
+        unreachable!()
+    }
+    fn read_hi(&self, _: u32) -> SbiRet {
+        unreachable!()
+    }
+    fn write(&self, _: u32, _: u64) -> SbiRet {
+        unreachable!()
+    }
+}

+ 6 - 3
src/lib.rs

@@ -168,6 +168,7 @@
 //! # struct MyPlatPmu;
 //! # struct MyPlatDbcn;
 //! # struct MyPlatSusp;
+//! # struct MyPlatCppc;
 //! use rustsbi::RustSBI;
 //!
 //! # struct SupervisorContext;
@@ -175,7 +176,7 @@
 //! struct Executor {
 //!     ctx: SupervisorContext,
 //!     /* other environment variables ... */
-//!     sbi: RustSBI<Clint, Clint, MyPlatRfnc, MyPlatHsm, MyBoardPower, MyPlatPmu, MyPlatDbcn, MyPlatSusp>,
+//!     sbi: RustSBI<Clint, Clint, MyPlatRfnc, MyPlatHsm, MyBoardPower, MyPlatPmu, MyPlatDbcn, MyPlatSusp, MyPlatCppc>,
 //!     /* custom_1: CustomSBI<...> */
 //! }
 //!
@@ -504,6 +505,7 @@
 #![no_std]
 
 mod console;
+mod cppc;
 mod hart_mask;
 mod hsm;
 mod instance;
@@ -511,8 +513,8 @@ mod ipi;
 mod pmu;
 mod reset;
 mod rfence;
-mod timer;
 mod susp;
+mod timer;
 
 /// The RustSBI logo without blank lines on the beginning
 pub const LOGO: &str = r".______       __    __      _______.___________.  _______..______   __
@@ -542,6 +544,7 @@ pub const VERSION: &str = env!("CARGO_PKG_VERSION");
 
 pub extern crate sbi_spec as spec;
 pub use console::Console;
+pub use cppc::Cppc;
 pub use hart_mask::HartMask;
 pub use hsm::Hsm;
 pub use instance::{Builder, RustSBI};
@@ -549,8 +552,8 @@ pub use ipi::Ipi;
 pub use pmu::Pmu;
 pub use reset::Reset;
 pub use rfence::Rfence as Fence;
-pub use timer::Timer;
 pub use susp::Susp;
+pub use timer::Timer;
 
 #[cfg(not(feature = "machine"))]
 pub use instance::MachineInfo;

+ 7 - 7
src/susp.rs

@@ -70,13 +70,13 @@ pub trait Susp: Send + Sync {
     ///
     /// The possible return error codes returned in `SbiRet.error` are shown in the table below:
     ///
-    /// | Error code              | Description
-    /// | ----------------------- | -----------------------
-    /// | SBI_SUCCESS             | System has suspended and resumed successfully.        
-    /// | SBI_ERR_INVALID_PARAM   | `sleep_type` is reserved or is platform-specific and unimplemented.
-    /// | SBI_ERR_NOT_SUPPORTED   | `sleep_type` is not reserved and is implemented, but the platform does not support it due to one or more missing dependencies.
-    /// | SBI_ERR_INVALID_ADDRESS | `resume_addr` is not valid, possibly due to the following reasons: * It is not a valid physical address. * Executable access to the address is prohibited by a physical memory protection mechanism or H-extension G-stage for supervisor mode.
-    /// | SBI_ERR_FAILED          | The suspend request failed for unspecified or unknown other reasons.
+    /// | Error code                  | Description  
+    /// | --------------------------- | -------------------
+    /// | `SbiRet::success()`         | System has suspended and resumed successfully.
+    /// | `SbiRet::invalid_param()`   | `sleep_type` is reserved or is platform-specific and unimplemented.
+    /// | `SbiRet::not_supported()`   | `sleep_type` is not reserved and is implemented, but the platform does not support it due to one or more missing dependencies.
+    /// | `SbiRet::invalid_address()` | `resume_addr` is not valid, possibly due to the following reasons: * It is not a valid physical address. * Executable access to the address is prohibited by a physical memory protection mechanism or H-extension G-stage for supervisor mode.
+    /// | `SbiRet::failed()`          | The suspend request failed for unspecified or unknown other reasons. 
     fn system_suspend(&self, sleep_type: u32, resume_addr: usize, opaque: usize) -> SbiRet;
 }