mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-25 05:03:05 +00:00
acpi: support vGPE
- Add vGPE registers to ACPIPMResource and inject vSCI when a GPE is enabled and its event is received. - Add a new interface, gpe_evt(), to trait PmResource. - Always use vGPE, regardless of FADT forwarding. - Always advertise support for 256 GPEs [1] to reduce code complexity. [1] "Up to 256 GPEx_STS bits and matching GPEx_EN bits can be implemented." 5.6.1, ACPI Spec Version 6.4 BUG=b:199383670 TEST=boot Linux kernel and inspect /sys/firmware/acpi/interrupts/ Change-Id: I97687326e9313c26b84dfacade5c8741719e7841 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3350493 Reviewed-by: Daniel Verkamp <dverkamp@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Tomasz Nowicki <tnowicki@google.com>
This commit is contained in:
parent
6ca0323c87
commit
eb16dd5118
3 changed files with 133 additions and 1 deletions
|
@ -16,6 +16,8 @@ pub struct ACPIPMResource {
|
|||
pm1_status: u16,
|
||||
pm1_enable: u16,
|
||||
pm1_control: u16,
|
||||
gpe0_status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
|
||||
gpe0_enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
|
||||
}
|
||||
|
||||
impl ACPIPMResource {
|
||||
|
@ -29,6 +31,8 @@ impl ACPIPMResource {
|
|||
pm1_status: 0,
|
||||
pm1_enable: 0,
|
||||
pm1_control: 0,
|
||||
gpe0_status: Default::default(),
|
||||
gpe0_enable: Default::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -46,12 +50,24 @@ impl ACPIPMResource {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn gpe_sci(&self) {
|
||||
for i in 0..self.gpe0_status.len() {
|
||||
if self.gpe0_status[i] & self.gpe0_enable[i] != 0 {
|
||||
if let Err(e) = self.sci_evt.write(1) {
|
||||
error!("ACPIPM: failed to trigger sci event: {}", e);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// the ACPI PM register length.
|
||||
pub const ACPIPM_RESOURCE_LEN: u8 = 8;
|
||||
pub const ACPIPM_RESOURCE_EVENTBLK_LEN: u8 = 4;
|
||||
pub const ACPIPM_RESOURCE_CONTROLBLK_LEN: u8 = 2;
|
||||
pub const ACPIPM_RESOURCE_GPE0_BLK_LEN: u8 = 64;
|
||||
pub const ACPIPM_RESOURCE_LEN: u8 = ACPIPM_RESOURCE_EVENTBLK_LEN + 4 + ACPIPM_RESOURCE_GPE0_BLK_LEN;
|
||||
|
||||
/// ACPI PM register value definitions
|
||||
|
||||
|
@ -71,6 +87,26 @@ const PM1_ENABLE: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2);
|
|||
/// Size: PM1_CNT_LEN (defined in FADT)
|
||||
const PM1_CONTROL: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16;
|
||||
|
||||
/// 4.8.5.1 General-Purpose Event Register Blocks, ACPI Spec Version 6.4
|
||||
/// - Each register block contains two registers: an enable and a status register.
|
||||
/// - Each register block is 32-bit aligned.
|
||||
/// - Each register in the block is accessed as a byte.
|
||||
|
||||
/// 4.8.5.1.1 General-Purpose Event 0 Register Block, ACPI Spec Version 6.4
|
||||
/// This register block consists of two registers: The GPE0_STS and the GPE0_EN registers. Each
|
||||
/// register’s length is defined to be half the length of the GPE0 register block, and is described
|
||||
/// in the ACPI FADT’s GPE0_BLK and GPE0_BLK_LEN operators.
|
||||
|
||||
/// 4.8.5.1.1.1 General-Purpose Event 0 Status Register, ACPI Spec Version 6.4
|
||||
/// Register Location: <GPE0_STS> System I/O or System Memory Space (defined in FADT)
|
||||
/// Size: GPE0_BLK_LEN/2 (defined in FADT)
|
||||
const GPE0_STATUS: u16 = PM1_STATUS + ACPIPM_RESOURCE_EVENTBLK_LEN as u16 + 4; // ensure alignment
|
||||
|
||||
/// 4.8.5.1.1.2 General-Purpose Event 0 Enable Register, ACPI Spec Version 6.4
|
||||
/// Register Location: <GPE0_EN> System I/O or System Memory Space (defined in FADT)
|
||||
/// Size: GPE0_BLK_LEN/2 (defined in FADT)
|
||||
const GPE0_ENABLE: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2);
|
||||
|
||||
const BITMASK_PM1STS_PWRBTN_STS: u16 = 1 << 8;
|
||||
const BITMASK_PM1EN_GBL_EN: u16 = 1 << 5;
|
||||
const BITMASK_PM1EN_PWRBTN_EN: u16 = 1 << 8;
|
||||
|
@ -91,11 +127,23 @@ impl PmResource for ACPIPMResource {
|
|||
self.pm1_status |= BITMASK_PM1STS_PWRBTN_STS;
|
||||
self.pm_sci();
|
||||
}
|
||||
|
||||
fn gpe_evt(&mut self, gpe: u32) {
|
||||
let byte = gpe as usize / 8;
|
||||
if byte >= self.gpe0_status.len() {
|
||||
error!("gpe_evt: GPE register {} does not exist", byte);
|
||||
return;
|
||||
}
|
||||
self.gpe0_status[byte] |= 1 << (gpe % 8);
|
||||
self.gpe_sci();
|
||||
}
|
||||
}
|
||||
|
||||
const PM1_STATUS_LAST: u16 = PM1_STATUS + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
|
||||
const PM1_ENABLE_LAST: u16 = PM1_ENABLE + (ACPIPM_RESOURCE_EVENTBLK_LEN as u16 / 2) - 1;
|
||||
const PM1_CONTROL_LAST: u16 = PM1_CONTROL + ACPIPM_RESOURCE_CONTROLBLK_LEN as u16 - 1;
|
||||
const GPE0_STATUS_LAST: u16 = GPE0_STATUS + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
|
||||
const GPE0_ENABLE_LAST: u16 = GPE0_ENABLE + (ACPIPM_RESOURCE_GPE0_BLK_LEN as u16 / 2) - 1;
|
||||
|
||||
impl BusDevice for ACPIPMResource {
|
||||
fn debug_label(&self) -> String {
|
||||
|
@ -135,6 +183,25 @@ impl BusDevice for ACPIPMResource {
|
|||
let offset = (info.offset - PM1_CONTROL as u64) as usize;
|
||||
data.copy_from_slice(&self.pm1_control.to_ne_bytes()[offset..offset + data.len()]);
|
||||
}
|
||||
// OSPM accesses GPE registers through byte accesses (regardless of their length)
|
||||
GPE0_STATUS..=GPE0_STATUS_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|| info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
|
||||
{
|
||||
warn!("ACPIPM: bad read size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
data[0] = self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize];
|
||||
}
|
||||
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|| info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
|
||||
{
|
||||
warn!("ACPIPM: bad read size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
data[0] = self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize];
|
||||
}
|
||||
_ => {
|
||||
warn!("ACPIPM: Bad read from {}", info);
|
||||
}
|
||||
|
@ -214,6 +281,26 @@ impl BusDevice for ACPIPMResource {
|
|||
}
|
||||
self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
|
||||
}
|
||||
// OSPM accesses GPE registers through byte accesses (regardless of their length)
|
||||
GPE0_STATUS..=GPE0_STATUS_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|| info.offset + data.len() as u64 > (GPE0_STATUS_LAST + 1).into()
|
||||
{
|
||||
warn!("ACPIPM: bad write size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize] &= !data[0];
|
||||
}
|
||||
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|| info.offset + data.len() as u64 > (GPE0_ENABLE_LAST + 1).into()
|
||||
{
|
||||
warn!("ACPIPM: bad write size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize] = data[0];
|
||||
self.gpe_sci();
|
||||
}
|
||||
_ => {
|
||||
warn!("ACPIPM: Bad write to {}", info);
|
||||
}
|
||||
|
|
|
@ -109,6 +109,7 @@ impl Default for VmRunMode {
|
|||
|
||||
pub trait PmResource {
|
||||
fn pwrbtn_evt(&mut self) {}
|
||||
fn gpe_evt(&mut self, _gpe: u32) {}
|
||||
}
|
||||
|
||||
/// The maximum number of devices that can be listed in one `UsbControlCommand`.
|
||||
|
|
|
@ -115,9 +115,14 @@ const FADT_FIELD_PM1B_EVENT_BLK_ADDR: usize = 60;
|
|||
const FADT_FIELD_PM1A_CONTROL_BLK_ADDR: usize = 64;
|
||||
const FADT_FIELD_PM1B_CONTROL_BLK_ADDR: usize = 68;
|
||||
const FADT_FIELD_PM2_CONTROL_BLK_ADDR: usize = 72;
|
||||
const FADT_FIELD_GPE0_BLK_ADDR: usize = 80;
|
||||
const FADT_FIELD_GPE1_BLK_ADDR: usize = 84;
|
||||
const FADT_FIELD_PM1A_EVENT_BLK_LEN: usize = 88;
|
||||
const FADT_FIELD_PM1A_CONTROL_BLK_LEN: usize = 89;
|
||||
const FADT_FIELD_PM2_CONTROL_BLK_LEN: usize = 90;
|
||||
const FADT_FIELD_GPE0_BLK_LEN: usize = 92;
|
||||
const FADT_FIELD_GPE1_BLK_LEN: usize = 93;
|
||||
const FADT_FIELD_GPE1_BASE: usize = 94;
|
||||
const FADT_FIELD_FLAGS: usize = 112;
|
||||
const FADT_FIELD_RESET_REGISTER: usize = 116;
|
||||
const FADT_FIELD_RESET_VALUE: usize = 128;
|
||||
|
@ -129,6 +134,8 @@ const FADT_FIELD_X_PM1B_EVENT_BLK_ADDR: usize = 160;
|
|||
const FADT_FIELD_X_PM1A_CONTROL_BLK_ADDR: usize = 172;
|
||||
const FADT_FIELD_X_PM1B_CONTROL_BLK_ADDR: usize = 184;
|
||||
const FADT_FIELD_X_PM2_CONTROL_BLK_ADDR: usize = 196;
|
||||
const FADT_FIELD_X_GPE0_BLK_ADDR: usize = 220;
|
||||
const FADT_FIELD_X_GPE1_BLK_ADDR: usize = 232;
|
||||
const FADT_FIELD_HYPERVISOR_ID: usize = 268;
|
||||
// MADT
|
||||
const MADT_LEN: u32 = 44;
|
||||
|
@ -253,6 +260,15 @@ fn write_facp_overrides(
|
|||
// PM2 Control Block Address (not supported)
|
||||
facp.write(FADT_FIELD_PM2_CONTROL_BLK_ADDR, 0u32);
|
||||
|
||||
// GPE0 Block Address
|
||||
facp.write(
|
||||
FADT_FIELD_GPE0_BLK_ADDR,
|
||||
pm_iobase + devices::acpi::ACPIPM_RESOURCE_EVENTBLK_LEN as u32 + 4,
|
||||
);
|
||||
|
||||
// GPE1 Block Address (not supported)
|
||||
facp.write(FADT_FIELD_GPE1_BLK_ADDR, 0u32);
|
||||
|
||||
// PM1 Event Block Length
|
||||
facp.write(
|
||||
FADT_FIELD_PM1A_EVENT_BLK_LEN,
|
||||
|
@ -268,6 +284,18 @@ fn write_facp_overrides(
|
|||
// PM2 Control Block Length (not supported)
|
||||
facp.write(FADT_FIELD_PM2_CONTROL_BLK_LEN, 0u8);
|
||||
|
||||
// GPE0 Block Length
|
||||
facp.write(
|
||||
FADT_FIELD_GPE0_BLK_LEN,
|
||||
devices::acpi::ACPIPM_RESOURCE_GPE0_BLK_LEN,
|
||||
);
|
||||
|
||||
// GPE1 Block Length (not supported)
|
||||
facp.write(FADT_FIELD_GPE1_BLK_LEN, 0u8);
|
||||
|
||||
// GPE1 Base (not supported)
|
||||
facp.write(FADT_FIELD_GPE1_BASE, 0u8);
|
||||
|
||||
// PM1A Extended Event Block Address (not supported)
|
||||
facp.write(
|
||||
FADT_FIELD_X_PM1A_EVENT_BLK_ADDR,
|
||||
|
@ -307,6 +335,22 @@ fn write_facp_overrides(
|
|||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
// GPE0 Extended Address (not supported)
|
||||
facp.write(
|
||||
FADT_FIELD_X_GPE0_BLK_ADDR,
|
||||
GenericAddress {
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
|
||||
// GPE1 Extended Address (not supported)
|
||||
facp.write(
|
||||
FADT_FIELD_X_GPE1_BLK_ADDR,
|
||||
GenericAddress {
|
||||
..Default::default()
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn next_offset(offset: GuestAddress, len: u64) -> Option<GuestAddress> {
|
||||
|
|
Loading…
Reference in a new issue