xref: /aosp_15_r20/external/crosvm/devices/src/pci/pm.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
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