mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2024-11-24 20:48:55 +00:00
devices: acpi: add Pm1Resource and GpeResource
In preparation for implementing SCI resample handling which will work in a separate worker thread, implement Pm1Resource and GpeResource to access virtual PM1 and GPE regs concurrently using Arc<Mutex<...>>. BUG=b:205072342 TEST=inject GPE or power button event from command line and inspect /sys/firmware/acpi/interrupts/ Change-Id: Icf7e845cf21fd9d1edcb91db26632e202b7b8434 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/3492218 Reviewed-by: Dmitry Torokhov <dtor@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Tomasz Nowicki <tnowicki@google.com>
This commit is contained in:
parent
d7db39550e
commit
c3d2364e42
1 changed files with 80 additions and 43 deletions
|
@ -5,8 +5,21 @@
|
|||
use crate::{BusAccessInfo, BusDevice, BusResumeDevice};
|
||||
use acpi_tables::{aml, aml::Aml};
|
||||
use base::{error, warn, Event};
|
||||
use std::sync::Arc;
|
||||
use sync::Mutex;
|
||||
use vm_control::PmResource;
|
||||
|
||||
struct Pm1Resource {
|
||||
status: u16,
|
||||
enable: u16,
|
||||
control: u16,
|
||||
}
|
||||
|
||||
struct GpeResource {
|
||||
status: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
|
||||
enable: [u8; ACPIPM_RESOURCE_GPE0_BLK_LEN as usize / 2],
|
||||
}
|
||||
|
||||
/// ACPI PM resource for handling OS suspend/resume request
|
||||
#[allow(dead_code)]
|
||||
pub struct ACPIPMResource {
|
||||
|
@ -14,11 +27,8 @@ pub struct ACPIPMResource {
|
|||
sci_evt_resample: Event,
|
||||
suspend_evt: Event,
|
||||
exit_evt: Event,
|
||||
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],
|
||||
pm1: Arc<Mutex<Pm1Resource>>,
|
||||
gpe0: Arc<Mutex<GpeResource>>,
|
||||
}
|
||||
|
||||
impl ACPIPMResource {
|
||||
|
@ -30,41 +40,49 @@ impl ACPIPMResource {
|
|||
suspend_evt: Event,
|
||||
exit_evt: Event,
|
||||
) -> ACPIPMResource {
|
||||
let pm1 = Pm1Resource {
|
||||
status: 0,
|
||||
enable: 0,
|
||||
control: 0,
|
||||
};
|
||||
let gpe0 = GpeResource {
|
||||
status: Default::default(),
|
||||
enable: Default::default(),
|
||||
};
|
||||
|
||||
ACPIPMResource {
|
||||
sci_evt,
|
||||
sci_evt_resample,
|
||||
suspend_evt,
|
||||
exit_evt,
|
||||
pm1_status: 0,
|
||||
pm1_enable: 0,
|
||||
pm1_control: 0,
|
||||
gpe0_status: Default::default(),
|
||||
gpe0_enable: Default::default(),
|
||||
pm1: Arc::new(Mutex::new(pm1)),
|
||||
gpe0: Arc::new(Mutex::new(gpe0)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn pm_sci(&self) {
|
||||
if self.pm1_status
|
||||
& self.pm1_enable
|
||||
impl Pm1Resource {
|
||||
fn trigger_sci(&self, sci_evt: &Event) {
|
||||
if self.status
|
||||
& self.enable
|
||||
& (BITMASK_PM1EN_GBL_EN
|
||||
| BITMASK_PM1EN_PWRBTN_EN
|
||||
| BITMASK_PM1EN_SLPBTN_EN
|
||||
| BITMASK_PM1EN_RTC_EN)
|
||||
!= 0
|
||||
{
|
||||
if let Err(e) = self.sci_evt.write(1) {
|
||||
error!("ACPIPM: failed to trigger sci event: {}", e);
|
||||
if let Err(e) = sci_evt.write(1) {
|
||||
error!("ACPIPM: failed to trigger sci event for pm1: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
impl GpeResource {
|
||||
fn trigger_sci(&self, sci_evt: &Event) {
|
||||
if (0..self.status.len()).any(|i| self.status[i] & self.enable[i] != 0) {
|
||||
if let Err(e) = sci_evt.write(1) {
|
||||
error!("ACPIPM: failed to trigger sci event for gpe: {}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -131,18 +149,22 @@ const SLEEP_TYPE_S5: u16 = 0 << 10;
|
|||
|
||||
impl PmResource for ACPIPMResource {
|
||||
fn pwrbtn_evt(&mut self) {
|
||||
self.pm1_status |= BITMASK_PM1STS_PWRBTN_STS;
|
||||
self.pm_sci();
|
||||
let mut pm1 = self.pm1.lock();
|
||||
|
||||
pm1.status |= BITMASK_PM1STS_PWRBTN_STS;
|
||||
pm1.trigger_sci(&self.sci_evt);
|
||||
}
|
||||
|
||||
fn gpe_evt(&mut self, gpe: u32) {
|
||||
let mut gpe0 = self.gpe0.lock();
|
||||
|
||||
let byte = gpe as usize / 8;
|
||||
if byte >= self.gpe0_status.len() {
|
||||
if byte >= gpe0.status.len() {
|
||||
error!("gpe_evt: GPE register {} does not exist", byte);
|
||||
return;
|
||||
}
|
||||
self.gpe0_status[byte] |= 1 << (gpe % 8);
|
||||
self.gpe_sci();
|
||||
gpe0.status[byte] |= 1 << (gpe % 8);
|
||||
gpe0.trigger_sci(&self.sci_evt);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -168,7 +190,9 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_STATUS as u64) as usize;
|
||||
data.copy_from_slice(&self.pm1_status.to_ne_bytes()[offset..offset + data.len()]);
|
||||
data.copy_from_slice(
|
||||
&self.pm1.lock().status.to_ne_bytes()[offset..offset + data.len()],
|
||||
);
|
||||
}
|
||||
PM1_ENABLE..=PM1_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u16>()
|
||||
|
@ -178,7 +202,9 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_ENABLE as u64) as usize;
|
||||
data.copy_from_slice(&self.pm1_enable.to_ne_bytes()[offset..offset + data.len()]);
|
||||
data.copy_from_slice(
|
||||
&self.pm1.lock().enable.to_ne_bytes()[offset..offset + data.len()],
|
||||
);
|
||||
}
|
||||
PM1_CONTROL..=PM1_CONTROL_LAST => {
|
||||
if data.len() > std::mem::size_of::<u16>()
|
||||
|
@ -188,7 +214,9 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_CONTROL as u64) as usize;
|
||||
data.copy_from_slice(&self.pm1_control.to_ne_bytes()[offset..offset + data.len()]);
|
||||
data.copy_from_slice(
|
||||
&self.pm1.lock().control.to_ne_bytes()[offset..offset + data.len()],
|
||||
);
|
||||
}
|
||||
// OSPM accesses GPE registers through byte accesses (regardless of their length)
|
||||
GPE0_STATUS..=GPE0_STATUS_LAST => {
|
||||
|
@ -198,7 +226,7 @@ impl BusDevice for ACPIPMResource {
|
|||
warn!("ACPIPM: bad read size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
data[0] = self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize];
|
||||
data[0] = self.gpe0.lock().status[(info.offset - GPE0_STATUS as u64) as usize];
|
||||
}
|
||||
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|
@ -207,7 +235,7 @@ impl BusDevice for ACPIPMResource {
|
|||
warn!("ACPIPM: bad read size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
data[0] = self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize];
|
||||
data[0] = self.gpe0.lock().enable[(info.offset - GPE0_ENABLE as u64) as usize];
|
||||
}
|
||||
_ => {
|
||||
warn!("ACPIPM: Bad read from {}", info);
|
||||
|
@ -226,11 +254,13 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_STATUS as u64) as usize;
|
||||
let mut v = self.pm1_status.to_ne_bytes();
|
||||
|
||||
let mut pm1 = self.pm1.lock();
|
||||
let mut v = pm1.status.to_ne_bytes();
|
||||
for (i, j) in (offset..offset + data.len()).enumerate() {
|
||||
v[j] &= !data[i];
|
||||
}
|
||||
self.pm1_status = u16::from_ne_bytes(v);
|
||||
pm1.status = u16::from_ne_bytes(v);
|
||||
}
|
||||
PM1_ENABLE..=PM1_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u16>()
|
||||
|
@ -240,12 +270,14 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_ENABLE as u64) as usize;
|
||||
let mut v = self.pm1_enable.to_ne_bytes();
|
||||
|
||||
let mut pm1 = self.pm1.lock();
|
||||
let mut v = pm1.enable.to_ne_bytes();
|
||||
for (i, j) in (offset..offset + data.len()).enumerate() {
|
||||
v[j] = data[i];
|
||||
}
|
||||
self.pm1_enable = u16::from_ne_bytes(v);
|
||||
self.pm_sci(); // TODO take care of spurious interrupts
|
||||
pm1.enable = u16::from_ne_bytes(v);
|
||||
pm1.trigger_sci(&self.sci_evt);
|
||||
}
|
||||
PM1_CONTROL..=PM1_CONTROL_LAST => {
|
||||
if data.len() > std::mem::size_of::<u16>()
|
||||
|
@ -255,7 +287,10 @@ impl BusDevice for ACPIPMResource {
|
|||
return;
|
||||
}
|
||||
let offset = (info.offset - PM1_CONTROL as u64) as usize;
|
||||
let mut v = self.pm1_control.to_ne_bytes();
|
||||
|
||||
let mut pm1 = self.pm1.lock();
|
||||
|
||||
let mut v = pm1.control.to_ne_bytes();
|
||||
for (i, j) in (offset..offset + data.len()).enumerate() {
|
||||
v[j] = data[i];
|
||||
}
|
||||
|
@ -286,7 +321,7 @@ impl BusDevice for ACPIPMResource {
|
|||
),
|
||||
}
|
||||
}
|
||||
self.pm1_control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
|
||||
pm1.control = val & !BITMASK_PM1CNT_SLEEP_ENABLE;
|
||||
}
|
||||
// OSPM accesses GPE registers through byte accesses (regardless of their length)
|
||||
GPE0_STATUS..=GPE0_STATUS_LAST => {
|
||||
|
@ -296,7 +331,7 @@ impl BusDevice for ACPIPMResource {
|
|||
warn!("ACPIPM: bad write size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
self.gpe0_status[(info.offset - GPE0_STATUS as u64) as usize] &= !data[0];
|
||||
self.gpe0.lock().status[(info.offset - GPE0_STATUS as u64) as usize] &= !data[0];
|
||||
}
|
||||
GPE0_ENABLE..=GPE0_ENABLE_LAST => {
|
||||
if data.len() > std::mem::size_of::<u8>()
|
||||
|
@ -305,8 +340,10 @@ impl BusDevice for ACPIPMResource {
|
|||
warn!("ACPIPM: bad write size: {}", data.len());
|
||||
return;
|
||||
}
|
||||
self.gpe0_enable[(info.offset - GPE0_ENABLE as u64) as usize] = data[0];
|
||||
self.gpe_sci();
|
||||
|
||||
let mut gpe = self.gpe0.lock();
|
||||
gpe.enable[(info.offset - GPE0_ENABLE as u64) as usize] = data[0];
|
||||
gpe.trigger_sci(&self.sci_evt);
|
||||
}
|
||||
_ => {
|
||||
warn!("ACPIPM: Bad write to {}", info);
|
||||
|
@ -317,7 +354,7 @@ impl BusDevice for ACPIPMResource {
|
|||
|
||||
impl BusResumeDevice for ACPIPMResource {
|
||||
fn resume_imminent(&mut self) {
|
||||
self.pm1_status |= BITMASK_PM1CNT_WAKE_STATUS;
|
||||
self.pm1.lock().status |= BITMASK_PM1CNT_WAKE_STATUS;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue