1 // Copyright 2021 The ChromiumOS Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::fs::File; 6 use std::fs::OpenOptions; 7 use std::io; 8 use std::mem::size_of; 9 10 use base::ioctl_with_ref; 11 use base::AsRawDescriptor; 12 use base::Event; 13 use base::RawDescriptor; 14 use data_model::vec_with_array_field; 15 use remain::sorted; 16 use thiserror::Error; 17 use vfio_sys::*; 18 19 use crate::ACPIPMFixedEvent; 20 use crate::IrqEdgeEvent; 21 use crate::IrqLevelEvent; 22 23 #[sorted] 24 #[derive(Error, Debug)] 25 pub enum DirectIrqError { 26 #[error("failed to clone trigger event: {0}")] 27 CloneEvent(base::Error), 28 #[error("failed to clone resample event: {0}")] 29 CloneResampleEvent(base::Error), 30 #[error("failed to enable direct irq")] 31 Enable, 32 #[error("failed to enable fixed event irq")] 33 EnableFixedEvent, 34 #[error("failed to enable gpe irq")] 35 EnableGpe, 36 #[error("failed to enable direct sci irq")] 37 EnableSci, 38 #[error("failed to open /dev/plat-irq-forward: {0}")] 39 Open(io::Error), 40 } 41 42 pub struct DirectIrq { 43 dev: File, 44 trigger: Event, 45 resample: Option<Event>, 46 sci_irq_prepared: bool, 47 } 48 49 impl DirectIrq { new(trigger_evt: &Event, resample_evt: Option<&Event>) -> Result<Self, DirectIrqError>50 fn new(trigger_evt: &Event, resample_evt: Option<&Event>) -> Result<Self, DirectIrqError> { 51 let trigger = trigger_evt 52 .try_clone() 53 .map_err(DirectIrqError::CloneEvent)?; 54 let resample = if let Some(event) = resample_evt { 55 Some( 56 event 57 .try_clone() 58 .map_err(DirectIrqError::CloneResampleEvent)?, 59 ) 60 } else { 61 None 62 }; 63 let dev = OpenOptions::new() 64 .read(true) 65 .write(true) 66 .open("/dev/plat-irq-forward") 67 .map_err(DirectIrqError::Open)?; 68 Ok(DirectIrq { 69 dev, 70 trigger, 71 resample, 72 sci_irq_prepared: false, 73 }) 74 } 75 76 /// Create DirectIrq object to access hardware edge triggered interrupts. new_edge(irq_evt: &IrqEdgeEvent) -> Result<Self, DirectIrqError>77 pub fn new_edge(irq_evt: &IrqEdgeEvent) -> Result<Self, DirectIrqError> { 78 DirectIrq::new(irq_evt.get_trigger(), None) 79 } 80 81 /// Create DirectIrq object to access hardware level triggered interrupts. new_level(irq_evt: &IrqLevelEvent) -> Result<Self, DirectIrqError>82 pub fn new_level(irq_evt: &IrqLevelEvent) -> Result<Self, DirectIrqError> { 83 DirectIrq::new(irq_evt.get_trigger(), Some(irq_evt.get_resample())) 84 } 85 86 /// Enable hardware triggered interrupt handling. 87 /// 88 /// Note: this feature is not part of VFIO, but provides 89 /// missing IRQ forwarding functionality. 90 /// 91 /// # Arguments 92 /// 93 /// * `irq_num` - host interrupt number (GSI). 94 /// irq_enable(&self, irq_num: u32) -> Result<(), DirectIrqError>95 pub fn irq_enable(&self, irq_num: u32) -> Result<(), DirectIrqError> { 96 if let Some(resample) = &self.resample { 97 self.plat_irq_ioctl( 98 irq_num, 99 PLAT_IRQ_FORWARD_SET_LEVEL_TRIGGER_EVENTFD, 100 self.trigger.as_raw_descriptor(), 101 )?; 102 self.plat_irq_ioctl( 103 irq_num, 104 PLAT_IRQ_FORWARD_SET_LEVEL_UNMASK_EVENTFD, 105 resample.as_raw_descriptor(), 106 )?; 107 } else { 108 self.plat_irq_ioctl( 109 irq_num, 110 PLAT_IRQ_FORWARD_SET_EDGE_TRIGGER, 111 self.trigger.as_raw_descriptor(), 112 )?; 113 }; 114 115 Ok(()) 116 } 117 118 /// Enable hardware triggered SCI interrupt handling for GPE or fixed events. 119 /// 120 /// Note: sci_irq_prepare() itself does not enable SCI forwarding yet 121 /// but configures it so it can be enabled for selected GPEs or fixed events 122 /// using gpe_enable_forwarding() or fixed_event_enable_forwarding(). sci_irq_prepare(&mut self) -> Result<(), DirectIrqError>123 pub fn sci_irq_prepare(&mut self) -> Result<(), DirectIrqError> { 124 if let Some(resample) = &self.resample { 125 self.plat_irq_ioctl( 126 0, 127 PLAT_IRQ_FORWARD_SET_LEVEL_ACPI_SCI_TRIGGER_EVENTFD, 128 self.trigger.as_raw_descriptor(), 129 )?; 130 self.plat_irq_ioctl( 131 0, 132 PLAT_IRQ_FORWARD_SET_LEVEL_ACPI_SCI_UNMASK_EVENTFD, 133 resample.as_raw_descriptor(), 134 )?; 135 } else { 136 return Err(DirectIrqError::EnableSci); 137 } 138 139 self.sci_irq_prepared = true; 140 141 Ok(()) 142 } 143 plat_irq_ioctl( &self, irq_num: u32, action: u32, fd: RawDescriptor, ) -> Result<(), DirectIrqError>144 fn plat_irq_ioctl( 145 &self, 146 irq_num: u32, 147 action: u32, 148 fd: RawDescriptor, 149 ) -> Result<(), DirectIrqError> { 150 let count = 1; 151 let u32_size = size_of::<u32>(); 152 let mut irq_set = vec_with_array_field::<plat_irq_forward_set, u32>(count); 153 irq_set[0].argsz = (size_of::<plat_irq_forward_set>() + count * u32_size) as u32; 154 irq_set[0].action_flags = action; 155 irq_set[0].count = count as u32; 156 irq_set[0].irq_number_host = irq_num; 157 // Safe as we are the owner of irq_set and allocation provides enough space for 158 // eventfd array. 159 let data = unsafe { irq_set[0].eventfd.as_mut_slice(count * u32_size) }; 160 let (left, _right) = data.split_at_mut(u32_size); 161 left.copy_from_slice(&fd.to_ne_bytes()[..]); 162 163 // Safe as we are the owner of plat_irq_forward and irq_set which are valid value 164 let ret = unsafe { ioctl_with_ref(self, PLAT_IRQ_FORWARD_SET(), &irq_set[0]) }; 165 if ret < 0 { 166 Err(DirectIrqError::Enable) 167 } else { 168 Ok(()) 169 } 170 } 171 172 /// Enable hardware triggered GPE handling via SCI interrupt forwarding. 173 /// Note: requires sci_irq_prepare() to be called beforehand. 174 /// 175 /// # Arguments 176 /// 177 /// * `gpe_num` - host GPE number. 178 /// gpe_enable_forwarding(&mut self, gpe_num: u32) -> Result<(), DirectIrqError>179 pub fn gpe_enable_forwarding(&mut self, gpe_num: u32) -> Result<(), DirectIrqError> { 180 if self.resample.is_none() || !self.sci_irq_prepared { 181 return Err(DirectIrqError::EnableGpe); 182 } 183 184 self.gpe_forward_ioctl(gpe_num)?; 185 186 Ok(()) 187 } 188 gpe_forward_ioctl(&self, gpe_num: u32) -> Result<(), DirectIrqError>189 fn gpe_forward_ioctl(&self, gpe_num: u32) -> Result<(), DirectIrqError> { 190 let mut evt_set = vec_with_array_field::<acpi_evt_forward_set, u32>(0); 191 evt_set[0].argsz = (size_of::<acpi_evt_forward_set>()) as u32; 192 evt_set[0].action_flags = ACPI_EVT_FORWARD_SET_GPE_TRIGGER; 193 evt_set[0].__bindgen_anon_1.gpe_host_nr = gpe_num; 194 195 // Safe as we are the owner of self and evt_set which are valid value 196 let ret = unsafe { ioctl_with_ref(self, ACPI_EVT_FORWARD_SET(), &evt_set[0]) }; 197 if ret < 0 { 198 Err(DirectIrqError::EnableGpe) 199 } else { 200 Ok(()) 201 } 202 } 203 204 /// Enable hardware triggered ACPI fixed event handling via SCI interrupt forwarding. 205 /// Note: requires sci_irq_prepare() to be called beforehand. 206 /// 207 /// # Arguments 208 /// 209 /// * `event` - ACPI fixed event. 210 /// fixed_event_enable_forwarding( &mut self, event: ACPIPMFixedEvent, ) -> Result<(), DirectIrqError>211 pub fn fixed_event_enable_forwarding( 212 &mut self, 213 event: ACPIPMFixedEvent, 214 ) -> Result<(), DirectIrqError> { 215 if self.resample.is_none() || !self.sci_irq_prepared { 216 return Err(DirectIrqError::EnableFixedEvent); 217 } 218 219 self.fixed_event_forward_ioctl( 220 // Numeric values from ACPI_EVENT_xxx in include/acpi/actypes.h in kernel. 221 match event { 222 ACPIPMFixedEvent::GlobalLock => 1, 223 ACPIPMFixedEvent::PowerButton => 2, 224 ACPIPMFixedEvent::SleepButton => 3, 225 ACPIPMFixedEvent::RTC => 4, 226 }, 227 )?; 228 229 Ok(()) 230 } 231 fixed_event_forward_ioctl(&self, event_num: u32) -> Result<(), DirectIrqError>232 fn fixed_event_forward_ioctl(&self, event_num: u32) -> Result<(), DirectIrqError> { 233 let mut evt_set = vec_with_array_field::<acpi_evt_forward_set, u32>(0); 234 evt_set[0].argsz = (size_of::<acpi_evt_forward_set>()) as u32; 235 evt_set[0].action_flags = ACPI_EVT_FORWARD_SET_FIXED_EVENT_TRIGGER; 236 evt_set[0].__bindgen_anon_1.fixed_evt_nr = event_num; 237 238 // Safe as we are the owner of self and evt_set which are valid value 239 let ret = unsafe { ioctl_with_ref(self, ACPI_EVT_FORWARD_SET(), &evt_set[0]) }; 240 if ret < 0 { 241 Err(DirectIrqError::EnableFixedEvent) 242 } else { 243 Ok(()) 244 } 245 } 246 } 247 248 impl AsRawDescriptor for DirectIrq { as_raw_descriptor(&self) -> i32249 fn as_raw_descriptor(&self) -> i32 { 250 self.dev.as_raw_descriptor() 251 } 252 } 253