1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors 2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be 3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file. 4*bb4ee6a4SAndroid Build Coastguard Worker 5*bb4ee6a4SAndroid Build Coastguard Worker #![cfg_attr(windows, allow(dead_code))] 6*bb4ee6a4SAndroid Build Coastguard Worker 7*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::AsBytes; 8*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromBytes; 9*bb4ee6a4SAndroid Build Coastguard Worker use zerocopy::FromZeroes; 10*bb4ee6a4SAndroid Build Coastguard Worker 11*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciCapConfig; 12*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciCapConfigWriteResult; 13*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::pci_configuration::PciCapMapping; 14*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciCapability; 15*bb4ee6a4SAndroid Build Coastguard Worker use crate::pci::PciCapabilityID; 16*bb4ee6a4SAndroid Build Coastguard Worker 17*bb4ee6a4SAndroid Build Coastguard Worker const PM_CAP_CONTROL_STATE_OFFSET: usize = 1; 18*bb4ee6a4SAndroid Build Coastguard Worker pub const PM_CAP_LENGTH: usize = 8; 19*bb4ee6a4SAndroid Build Coastguard Worker const PM_CAP_PME_SUPPORT_D0: u16 = 0x0800; 20*bb4ee6a4SAndroid Build Coastguard Worker const PM_CAP_PME_SUPPORT_D3_HOT: u16 = 0x4000; 21*bb4ee6a4SAndroid Build Coastguard Worker const PM_CAP_PME_SUPPORT_D3_COLD: u16 = 0x8000; 22*bb4ee6a4SAndroid Build Coastguard Worker const PM_CAP_VERSION: u16 = 0x2; 23*bb4ee6a4SAndroid Build Coastguard Worker const PM_PME_STATUS: u16 = 0x8000; 24*bb4ee6a4SAndroid Build Coastguard Worker const PM_PME_ENABLE: u16 = 0x100; 25*bb4ee6a4SAndroid Build Coastguard Worker const PM_NO_SOFT_RESET: u16 = 0x8; 26*bb4ee6a4SAndroid Build Coastguard Worker const PM_POWER_STATE_MASK: u16 = 0x3; 27*bb4ee6a4SAndroid Build Coastguard Worker const PM_POWER_STATE_D0: u16 = 0; 28*bb4ee6a4SAndroid Build Coastguard Worker const PM_POWER_STATE_D3: u16 = 0x3; 29*bb4ee6a4SAndroid Build Coastguard Worker 30*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Eq, PartialEq)] 31*bb4ee6a4SAndroid Build Coastguard Worker pub enum PciDevicePower { 32*bb4ee6a4SAndroid Build Coastguard Worker D0 = 0, 33*bb4ee6a4SAndroid Build Coastguard Worker D3 = 3, 34*bb4ee6a4SAndroid Build Coastguard Worker Unsupported = 0xFF, 35*bb4ee6a4SAndroid Build Coastguard Worker } 36*bb4ee6a4SAndroid Build Coastguard Worker 37*bb4ee6a4SAndroid Build Coastguard Worker #[repr(C)] 38*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Clone, Copy, AsBytes, FromZeroes, FromBytes)] 39*bb4ee6a4SAndroid Build Coastguard Worker pub struct PciPmCap { 40*bb4ee6a4SAndroid Build Coastguard Worker _cap_vndr: u8, 41*bb4ee6a4SAndroid Build Coastguard Worker _cap_next: u8, 42*bb4ee6a4SAndroid Build Coastguard Worker pm_cap: u16, 43*bb4ee6a4SAndroid Build Coastguard Worker pm_control_status: u16, 44*bb4ee6a4SAndroid Build Coastguard Worker padding: u16, 45*bb4ee6a4SAndroid Build Coastguard Worker } 46*bb4ee6a4SAndroid Build Coastguard Worker 47*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapability for PciPmCap { bytes(&self) -> &[u8]48*bb4ee6a4SAndroid Build Coastguard Worker fn bytes(&self) -> &[u8] { 49*bb4ee6a4SAndroid Build Coastguard Worker self.as_bytes() 50*bb4ee6a4SAndroid Build Coastguard Worker } 51*bb4ee6a4SAndroid Build Coastguard Worker id(&self) -> PciCapabilityID52*bb4ee6a4SAndroid Build Coastguard Worker fn id(&self) -> PciCapabilityID { 53*bb4ee6a4SAndroid Build Coastguard Worker PciCapabilityID::PowerManagement 54*bb4ee6a4SAndroid Build Coastguard Worker } 55*bb4ee6a4SAndroid Build Coastguard Worker writable_bits(&self) -> Vec<u32>56*bb4ee6a4SAndroid Build Coastguard Worker fn writable_bits(&self) -> Vec<u32> { 57*bb4ee6a4SAndroid Build Coastguard Worker vec![0u32, 0x8103] 58*bb4ee6a4SAndroid Build Coastguard Worker } 59*bb4ee6a4SAndroid Build Coastguard Worker } 60*bb4ee6a4SAndroid Build Coastguard Worker 61*bb4ee6a4SAndroid Build Coastguard Worker impl PciPmCap { new() -> Self62*bb4ee6a4SAndroid Build Coastguard Worker pub fn new() -> Self { 63*bb4ee6a4SAndroid Build Coastguard Worker PciPmCap { 64*bb4ee6a4SAndroid Build Coastguard Worker _cap_vndr: 0, 65*bb4ee6a4SAndroid Build Coastguard Worker _cap_next: 0, 66*bb4ee6a4SAndroid Build Coastguard Worker pm_cap: Self::default_cap(), 67*bb4ee6a4SAndroid Build Coastguard Worker pm_control_status: 0, 68*bb4ee6a4SAndroid Build Coastguard Worker padding: 0, 69*bb4ee6a4SAndroid Build Coastguard Worker } 70*bb4ee6a4SAndroid Build Coastguard Worker } default_cap() -> u1671*bb4ee6a4SAndroid Build Coastguard Worker pub fn default_cap() -> u16 { 72*bb4ee6a4SAndroid Build Coastguard Worker let mut cap = PM_CAP_VERSION; 73*bb4ee6a4SAndroid Build Coastguard Worker // We use ACPI GPEs for PMEs, which are x86_64 only. We should 74*bb4ee6a4SAndroid Build Coastguard Worker // implement support for native PCIe PMEs to support non-ACPI platforms. 75*bb4ee6a4SAndroid Build Coastguard Worker if cfg!(target_arch = "x86_64") { 76*bb4ee6a4SAndroid Build Coastguard Worker cap |= PM_CAP_PME_SUPPORT_D0 | PM_CAP_PME_SUPPORT_D3_HOT | PM_CAP_PME_SUPPORT_D3_COLD 77*bb4ee6a4SAndroid Build Coastguard Worker } 78*bb4ee6a4SAndroid Build Coastguard Worker cap 79*bb4ee6a4SAndroid Build Coastguard Worker } 80*bb4ee6a4SAndroid Build Coastguard Worker } 81*bb4ee6a4SAndroid Build Coastguard Worker 82*bb4ee6a4SAndroid Build Coastguard Worker pub struct PmConfig { 83*bb4ee6a4SAndroid Build Coastguard Worker power_control_status: u16, 84*bb4ee6a4SAndroid Build Coastguard Worker cap_mapping: Option<PciCapMapping>, 85*bb4ee6a4SAndroid Build Coastguard Worker } 86*bb4ee6a4SAndroid Build Coastguard Worker 87*bb4ee6a4SAndroid Build Coastguard Worker impl PmConfig { new(no_soft_reset: bool) -> Self88*bb4ee6a4SAndroid Build Coastguard Worker pub fn new(no_soft_reset: bool) -> Self { 89*bb4ee6a4SAndroid Build Coastguard Worker PmConfig { 90*bb4ee6a4SAndroid Build Coastguard Worker power_control_status: if no_soft_reset { PM_NO_SOFT_RESET } else { 0 }, 91*bb4ee6a4SAndroid Build Coastguard Worker cap_mapping: None, 92*bb4ee6a4SAndroid Build Coastguard Worker } 93*bb4ee6a4SAndroid Build Coastguard Worker } 94*bb4ee6a4SAndroid Build Coastguard Worker read(&self, data: &mut u32)95*bb4ee6a4SAndroid Build Coastguard Worker pub fn read(&self, data: &mut u32) { 96*bb4ee6a4SAndroid Build Coastguard Worker *data = self.power_control_status as u32; 97*bb4ee6a4SAndroid Build Coastguard Worker } 98*bb4ee6a4SAndroid Build Coastguard Worker write(&mut self, offset: u64, data: &[u8])99*bb4ee6a4SAndroid Build Coastguard Worker pub fn write(&mut self, offset: u64, data: &[u8]) { 100*bb4ee6a4SAndroid Build Coastguard Worker if offset > 1 { 101*bb4ee6a4SAndroid Build Coastguard Worker return; 102*bb4ee6a4SAndroid Build Coastguard Worker } 103*bb4ee6a4SAndroid Build Coastguard Worker 104*bb4ee6a4SAndroid Build Coastguard Worker if offset == 0 { 105*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status &= !PM_POWER_STATE_MASK; 106*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status |= data[0] as u16 & PM_POWER_STATE_MASK; 107*bb4ee6a4SAndroid Build Coastguard Worker } 108*bb4ee6a4SAndroid Build Coastguard Worker 109*bb4ee6a4SAndroid Build Coastguard Worker let write_data = if offset == 0 && (data.len() == 2 || data.len() == 4) { 110*bb4ee6a4SAndroid Build Coastguard Worker Some((data[1] as u16) << 8) 111*bb4ee6a4SAndroid Build Coastguard Worker } else if offset == 1 && data.len() == 1 { 112*bb4ee6a4SAndroid Build Coastguard Worker Some((data[0] as u16) << 8) 113*bb4ee6a4SAndroid Build Coastguard Worker } else { 114*bb4ee6a4SAndroid Build Coastguard Worker None 115*bb4ee6a4SAndroid Build Coastguard Worker }; 116*bb4ee6a4SAndroid Build Coastguard Worker 117*bb4ee6a4SAndroid Build Coastguard Worker if let Some(write_data) = write_data { 118*bb4ee6a4SAndroid Build Coastguard Worker if write_data & PM_PME_STATUS != 0 { 119*bb4ee6a4SAndroid Build Coastguard Worker // clear PME_STATUS 120*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status &= !PM_PME_STATUS; 121*bb4ee6a4SAndroid Build Coastguard Worker } 122*bb4ee6a4SAndroid Build Coastguard Worker 123*bb4ee6a4SAndroid Build Coastguard Worker if write_data & PM_PME_ENABLE != 0 { 124*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status |= PM_PME_ENABLE; 125*bb4ee6a4SAndroid Build Coastguard Worker } else { 126*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status &= !PM_PME_ENABLE; 127*bb4ee6a4SAndroid Build Coastguard Worker } 128*bb4ee6a4SAndroid Build Coastguard Worker } 129*bb4ee6a4SAndroid Build Coastguard Worker } 130*bb4ee6a4SAndroid Build Coastguard Worker 131*bb4ee6a4SAndroid Build Coastguard Worker /// If device is in D3 and PME is enabled, set PME status, then device could 132*bb4ee6a4SAndroid Build Coastguard Worker /// inject a pme interrupt into guest should_trigger_pme(&mut self) -> bool133*bb4ee6a4SAndroid Build Coastguard Worker pub fn should_trigger_pme(&mut self) -> bool { 134*bb4ee6a4SAndroid Build Coastguard Worker if self.power_control_status & PM_POWER_STATE_MASK == PM_POWER_STATE_D3 135*bb4ee6a4SAndroid Build Coastguard Worker && self.power_control_status & PM_PME_ENABLE != 0 136*bb4ee6a4SAndroid Build Coastguard Worker { 137*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status |= PM_PME_STATUS; 138*bb4ee6a4SAndroid Build Coastguard Worker if let Some(cap_mapping) = &mut self.cap_mapping { 139*bb4ee6a4SAndroid Build Coastguard Worker cap_mapping.set_reg( 140*bb4ee6a4SAndroid Build Coastguard Worker PM_CAP_CONTROL_STATE_OFFSET, 141*bb4ee6a4SAndroid Build Coastguard Worker self.power_control_status as u32, 142*bb4ee6a4SAndroid Build Coastguard Worker 0xffff, 143*bb4ee6a4SAndroid Build Coastguard Worker ); 144*bb4ee6a4SAndroid Build Coastguard Worker } 145*bb4ee6a4SAndroid Build Coastguard Worker return true; 146*bb4ee6a4SAndroid Build Coastguard Worker } 147*bb4ee6a4SAndroid Build Coastguard Worker 148*bb4ee6a4SAndroid Build Coastguard Worker false 149*bb4ee6a4SAndroid Build Coastguard Worker } 150*bb4ee6a4SAndroid Build Coastguard Worker 151*bb4ee6a4SAndroid Build Coastguard Worker /// Get device power status get_power_status(&self) -> PciDevicePower152*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_power_status(&self) -> PciDevicePower { 153*bb4ee6a4SAndroid Build Coastguard Worker match self.power_control_status & PM_POWER_STATE_MASK { 154*bb4ee6a4SAndroid Build Coastguard Worker PM_POWER_STATE_D0 => PciDevicePower::D0, 155*bb4ee6a4SAndroid Build Coastguard Worker PM_POWER_STATE_D3 => PciDevicePower::D3, 156*bb4ee6a4SAndroid Build Coastguard Worker _ => PciDevicePower::Unsupported, 157*bb4ee6a4SAndroid Build Coastguard Worker } 158*bb4ee6a4SAndroid Build Coastguard Worker } 159*bb4ee6a4SAndroid Build Coastguard Worker } 160*bb4ee6a4SAndroid Build Coastguard Worker 161*bb4ee6a4SAndroid Build Coastguard Worker pub struct PmStatusChange { 162*bb4ee6a4SAndroid Build Coastguard Worker pub from: PciDevicePower, 163*bb4ee6a4SAndroid Build Coastguard Worker pub to: PciDevicePower, 164*bb4ee6a4SAndroid Build Coastguard Worker } 165*bb4ee6a4SAndroid Build Coastguard Worker 166*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapConfigWriteResult for PmStatusChange {} 167*bb4ee6a4SAndroid Build Coastguard Worker 168*bb4ee6a4SAndroid Build Coastguard Worker const PM_CONFIG_READ_MASK: [u32; 2] = [0, 0xffff]; 169*bb4ee6a4SAndroid Build Coastguard Worker 170*bb4ee6a4SAndroid Build Coastguard Worker impl PciCapConfig for PmConfig { read_mask(&self) -> &'static [u32]171*bb4ee6a4SAndroid Build Coastguard Worker fn read_mask(&self) -> &'static [u32] { 172*bb4ee6a4SAndroid Build Coastguard Worker &PM_CONFIG_READ_MASK 173*bb4ee6a4SAndroid Build Coastguard Worker } 174*bb4ee6a4SAndroid Build Coastguard Worker read_reg(&self, reg_idx: usize) -> u32175*bb4ee6a4SAndroid Build Coastguard Worker fn read_reg(&self, reg_idx: usize) -> u32 { 176*bb4ee6a4SAndroid Build Coastguard Worker let mut data = 0; 177*bb4ee6a4SAndroid Build Coastguard Worker if reg_idx == PM_CAP_CONTROL_STATE_OFFSET { 178*bb4ee6a4SAndroid Build Coastguard Worker self.read(&mut data); 179*bb4ee6a4SAndroid Build Coastguard Worker } 180*bb4ee6a4SAndroid Build Coastguard Worker data 181*bb4ee6a4SAndroid Build Coastguard Worker } 182*bb4ee6a4SAndroid Build Coastguard Worker write_reg( &mut self, reg_idx: usize, offset: u64, data: &[u8], ) -> Option<Box<dyn PciCapConfigWriteResult>>183*bb4ee6a4SAndroid Build Coastguard Worker fn write_reg( 184*bb4ee6a4SAndroid Build Coastguard Worker &mut self, 185*bb4ee6a4SAndroid Build Coastguard Worker reg_idx: usize, 186*bb4ee6a4SAndroid Build Coastguard Worker offset: u64, 187*bb4ee6a4SAndroid Build Coastguard Worker data: &[u8], 188*bb4ee6a4SAndroid Build Coastguard Worker ) -> Option<Box<dyn PciCapConfigWriteResult>> { 189*bb4ee6a4SAndroid Build Coastguard Worker if reg_idx == PM_CAP_CONTROL_STATE_OFFSET { 190*bb4ee6a4SAndroid Build Coastguard Worker let from = self.get_power_status(); 191*bb4ee6a4SAndroid Build Coastguard Worker self.write(offset, data); 192*bb4ee6a4SAndroid Build Coastguard Worker let to = self.get_power_status(); 193*bb4ee6a4SAndroid Build Coastguard Worker if from != to { 194*bb4ee6a4SAndroid Build Coastguard Worker return Some(Box::new(PmStatusChange { from, to })); 195*bb4ee6a4SAndroid Build Coastguard Worker } 196*bb4ee6a4SAndroid Build Coastguard Worker } 197*bb4ee6a4SAndroid Build Coastguard Worker None 198*bb4ee6a4SAndroid Build Coastguard Worker } 199*bb4ee6a4SAndroid Build Coastguard Worker set_cap_mapping(&mut self, mapping: PciCapMapping)200*bb4ee6a4SAndroid Build Coastguard Worker fn set_cap_mapping(&mut self, mapping: PciCapMapping) { 201*bb4ee6a4SAndroid Build Coastguard Worker self.cap_mapping = Some(mapping); 202*bb4ee6a4SAndroid Build Coastguard Worker } 203*bb4ee6a4SAndroid Build Coastguard Worker } 204