From 33ea082f6b61e85ec489fc5267b3cf30cd3f7819 Mon Sep 17 00:00:00 2001 From: Tim Wawrzynczak Date: Mon, 13 Nov 2023 09:53:54 -0700 Subject: [PATCH] acpi_tables: Add support for RQSC RQSC is the RISC-V Quality of Service (QoS) Controllers Table. It is used by RISC-V platforms to describe cache and memory QoS controllers to the operating system. The ECR has been accepted its current draft can be found at: https://docs.google.com/document/d/12PZvtvKTEx6GD_ou8h_sg1hhwGTdA35JJiiWH5YfXHM/edit but note even though the doc says RQCT its accepted name was RQSC. Signed-off-by: Tim Wawrzynczak --- README.md | 3 +- src/lib.rs | 1 + src/rqsc.rs | 190 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 193 insertions(+), 1 deletion(-) create mode 100644 src/rqsc.rs diff --git a/README.md b/README.md index 93fa404..39a8536 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ MCFG, etc) as well as generate AML for filling a DSDT table. ## Usage -There are eighteen modules: +There are nineteen modules: * `aml` provides the ability to generate AML code, see the chapter titled "ACPI Machine Language (AML) Specification" in the ACPI Specification. @@ -24,6 +24,7 @@ There are eighteen modules: * `pptt` contains routines for creating a `PPTT` table * `rhct` contains routines for creating a `RHCT` table * `rimt` contains routines for creating a `RIMT` table +* `rqsc` contains routines for creating a `RQSC` table * `rsdp` contains a helper for creating a `RSDP` table * `sdt` provides the ability to build user defined tables including header and checksum validation diff --git a/src/lib.rs b/src/lib.rs index 57da418..ff2b333 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -22,6 +22,7 @@ pub mod mcfg; pub mod pptt; pub mod rhct; pub mod rimt; +pub mod rqsc; pub mod rsdp; pub mod sdt; pub mod slit; diff --git a/src/rqsc.rs b/src/rqsc.rs new file mode 100644 index 0000000..374176f --- /dev/null +++ b/src/rqsc.rs @@ -0,0 +1,190 @@ +// Copyright 2023 Rivos, Inc. +// +// SPDX-License-Identifier: Apache-2.0 +// + +use zerocopy::{byteorder, byteorder::LE, AsBytes}; + +extern crate alloc; +use alloc::vec::Vec; + +use crate::{aml_as_bytes, assert_same_size, gas, Aml, AmlSink, Checksum, TableHeader}; + +type U16 = byteorder::U16; +type U32 = byteorder::U32; + +#[repr(u8)] +pub enum ControllerType { + Capacity = 0, + Bandwidth = 1, +} + +#[repr(u8)] +pub enum ResourceType { + Cache = 0, + Memory = 1, +} + +pub struct RQSC { + header: TableHeader, + structures: Vec, +} + +impl RQSC { + pub fn new(oem_id: [u8; 6], oem_table_id: [u8; 8], oem_revision: u32) -> Self { + let mut cksum = Checksum::default(); + + let mut header = TableHeader { + signature: *b"RQSC", + length: (TableHeader::len() as u32).into(), + revision: 1, + checksum: 0, + oem_id, + oem_table_id, + oem_revision: oem_revision.into(), + creator_id: crate::CREATOR_ID, + creator_revision: crate::CREATOR_REVISION, + }; + cksum.append(header.as_bytes()); + header.checksum = cksum.value(); + + Self { + header, + structures: Vec::new(), + } + } + + fn update_header(&mut self, data: &[u8]) { + // Fix up the length of the table + let len = data.len() as u32; + let old_len = self.header.length.get(); + let new_len = len + old_len; + self.header.length.set(new_len); + + // Fix up checksum + self.header.checksum = 0; + let mut cksum = Checksum::default(); + self.to_aml_bytes(&mut cksum); + self.header.checksum = cksum.value(); + } + + pub fn add_controller(&mut self, q: QoSController) { + self.structures.push(q); + self.update_header(q.as_bytes()); + } +} + +impl Aml for RQSC { + fn to_aml_bytes(&self, sink: &mut dyn AmlSink) { + for byte in self.header.as_bytes() { + sink.byte(*byte); + } + + sink.dword(self.structures.len() as u32); + for st in &self.structures { + st.to_aml_bytes(sink); + } + } +} + +#[repr(C, packed)] +#[derive(Clone, Copy, Debug, Default, AsBytes)] +pub struct QoSController { + /// Identifies the specific register interface that is supported by this + /// controller + controller_type: u8, + _reserved0: u8, + length: U16, + /// Register Buffer describing the starting address of the QoS register interface + register: gas::GAS, + _reserved1: [u8; 3], + /// Describes the type of resource that this QoS controller has control over + resource_type: u8, + /// Depends on the Resource Type field. If Cache (0), this represents the unique Cache ID + /// from the PPTT table's Cache Type structure (Table 5.159 in ACPI Spec 6.5) that this + /// controller is associated with. If Memory, then this represents the proximity domain from + /// the SRAT table that this specific controller is associated with. If SRAT is not + /// implemented, then this shall be 0, indicating a UMA memory configuration. + resource_id: U32, + /// Non-zero number indicates that the controller supports allocation capability and the + /// number of Resource Control IDs (RCID) supported by the controller. If 0, then no + /// allocation control is available. + rcid_count: U32, + /// Non-zero number indicates that the controller supports usage monitoring capability and + /// the number of Monitoring Control IDs (MCID) supported by the controller. If 0, then no + /// usage monitoring is available. + mcid_count: U32, +} + +impl QoSController { + pub fn new( + controller_type: ControllerType, + register_interface_address: gas::GAS, + resource_type: ResourceType, + resource_id: u32, + rcid_count: u32, + mcid_count: u32, + ) -> Self { + Self { + controller_type: controller_type as u8, + _reserved0: 0, + length: 32u16.into(), + register: register_interface_address, + _reserved1: [0, 0, 0], + resource_type: resource_type as u8, + resource_id: resource_id.into(), + rcid_count: rcid_count.into(), + mcid_count: mcid_count.into(), + } + } +} + +aml_as_bytes!(QoSController); +assert_same_size!(QoSController, [u8; 32]); + +#[cfg(test)] +mod tests { + use super::*; + use crate::gas::*; + + #[test] + fn test_bare_rqsc() { + let rqsc = RQSC::new(*b"RQSSCC", *b"SOMETHIN", 0xcafe_d00d); + let mut bytes = Vec::new(); + rqsc.to_aml_bytes(&mut bytes); + let sum = bytes.iter().fold(0u8, |acc, x| acc.wrapping_add(*x)); + assert_eq!(sum, 0); + assert_eq!(bytes.len(), TableHeader::len() + 4); + assert_eq!(bytes[0..4], *b"RQSC"); + } + + #[test] + fn test_structures() { + let mut rqsc = RQSC::new(*b"RQSSCC", *b"SOMETHIN", 0xcafe_d00d); + rqsc.add_controller(QoSController::new( + ControllerType::Capacity, + gas::GAS::new( + AddressSpace::SystemMemory, + 64, + 0, + AccessSize::QwordAccess, + 0x0123_4567_89ab_cdef, + ), + ResourceType::Memory, + 0x4242_4242, + 0x3737_3737, + 0x5656_5656, + )); + + let mut bytes = Vec::new(); + rqsc.to_aml_bytes(&mut bytes); + let sum = bytes.iter().fold(0u8, |acc, x| acc.wrapping_add(*x)); + + assert_eq!(sum, 0); + assert_eq!( + bytes.len(), + TableHeader::len() + 4 + core::mem::size_of::() + ); + assert_eq!(bytes[0..4], *b"RQSC"); + } +}