• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2022 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 #![cfg_attr(windows, allow(dead_code))]
6 
7 use base::error;
8 use base::AsRawDescriptor;
9 use base::Event;
10 use base::RawDescriptor;
11 use base::Tube;
12 use bit_field::*;
13 use vm_control::VmIrqRequest;
14 use vm_control::VmIrqResponse;
15 use zerocopy::AsBytes;
16 use zerocopy::FromBytes;
17 
18 use crate::pci::PciCapability;
19 use crate::pci::PciCapabilityID;
20 // MSI registers
21 pub const PCI_MSI_NEXT_POINTER: u32 = 0x1; // Next cap pointer
22 pub const PCI_MSI_FLAGS: u32 = 0x2; // Message Control
23 const PCI_MSI_FLAGS_ENABLE: u16 = 0x0001; // MSI feature enabled
24 pub const PCI_MSI_FLAGS_64BIT: u16 = 0x0080; // 64-bit addresses allowed
25 pub const PCI_MSI_FLAGS_MASKBIT: u16 = 0x0100; // Per-vector masking capable
26 const PCI_MSI_ADDRESS_LO: u32 = 0x4; // MSI address lower 32 bits
27 const PCI_MSI_ADDRESS_HI: u32 = 0x8; // MSI address upper 32 bits (if 64 bit allowed)
28 const PCI_MSI_DATA_32: u32 = 0x8; // 16 bits of data for 32-bit message address
29 const PCI_MSI_DATA_64: u32 = 0xC; // 16 bits of date for 64-bit message address
30 
31 // MSI length
32 const MSI_LENGTH_32BIT_WITHOUT_MASK: u32 = 0xA;
33 const MSI_LENGTH_32BIT_WITH_MASK: u32 = 0x14;
34 const MSI_LENGTH_64BIT_WITHOUT_MASK: u32 = 0xE;
35 const MSI_LENGTH_64BIT_WITH_MASK: u32 = 0x18;
36 
37 pub enum MsiStatus {
38     Enabled,
39     Disabled,
40     NothingToDo,
41 }
42 
43 /// Wrapper over MSI Capability Structure
44 pub struct MsiConfig {
45     is_64bit: bool,
46     mask_cap: bool,
47     ctrl: u16,
48     address: u64,
49     data: u16,
50     vm_socket_irq: Tube,
51     irqfd: Option<Event>,
52     gsi: Option<u32>,
53     device_id: u32,
54     device_name: String,
55 }
56 
57 impl MsiConfig {
new( is_64bit: bool, mask_cap: bool, vm_socket_irq: Tube, device_id: u32, device_name: String, ) -> Self58     pub fn new(
59         is_64bit: bool,
60         mask_cap: bool,
61         vm_socket_irq: Tube,
62         device_id: u32,
63         device_name: String,
64     ) -> Self {
65         let mut ctrl: u16 = 0;
66         if is_64bit {
67             ctrl |= PCI_MSI_FLAGS_64BIT;
68         }
69         if mask_cap {
70             ctrl |= PCI_MSI_FLAGS_MASKBIT;
71         }
72         MsiConfig {
73             is_64bit,
74             mask_cap,
75             ctrl,
76             address: 0,
77             data: 0,
78             vm_socket_irq,
79             irqfd: None,
80             gsi: None,
81             device_id,
82             device_name,
83         }
84     }
85 
is_msi_reg(&self, offset: u32, index: u64, len: usize) -> bool86     pub fn is_msi_reg(&self, offset: u32, index: u64, len: usize) -> bool {
87         let msi_len = match (self.is_64bit, self.mask_cap) {
88             (true, true) => MSI_LENGTH_64BIT_WITH_MASK,
89             (true, false) => MSI_LENGTH_64BIT_WITHOUT_MASK,
90             (false, true) => MSI_LENGTH_32BIT_WITH_MASK,
91             (false, false) => MSI_LENGTH_32BIT_WITHOUT_MASK,
92         };
93 
94         index >= offset as u64
95             && index + len as u64 <= (offset + msi_len) as u64
96             && len as u32 <= msi_len
97     }
98 
read_msi_capability(&self, offset: u32, data: u32) -> u3299     pub fn read_msi_capability(&self, offset: u32, data: u32) -> u32 {
100         if offset == 0 {
101             (self.ctrl as u32) << 16 | (data & u16::max_value() as u32)
102         } else {
103             data
104         }
105     }
106 
write_msi_capability(&mut self, offset: u32, data: &[u8]) -> MsiStatus107     pub fn write_msi_capability(&mut self, offset: u32, data: &[u8]) -> MsiStatus {
108         let len = data.len();
109         let mut ret = MsiStatus::NothingToDo;
110         let old_address = self.address;
111         let old_data = self.data;
112 
113         // write msi ctl
114         if len == 2 && offset == PCI_MSI_FLAGS {
115             let was_enabled = self.is_msi_enabled();
116             let value: [u8; 2] = [data[0], data[1]];
117             self.ctrl = u16::from_le_bytes(value);
118             let is_enabled = self.is_msi_enabled();
119             if !was_enabled && is_enabled {
120                 self.enable();
121                 ret = MsiStatus::Enabled;
122             } else if was_enabled && !is_enabled {
123                 ret = MsiStatus::Disabled;
124             }
125         } else if len == 4 && offset == PCI_MSI_ADDRESS_LO && !self.is_64bit {
126             //write 32 bit message address
127             let value: [u8; 8] = [data[0], data[1], data[2], data[3], 0, 0, 0, 0];
128             self.address = u64::from_le_bytes(value);
129         } else if len == 4 && offset == PCI_MSI_ADDRESS_LO && self.is_64bit {
130             // write 64 bit message address low part
131             let value: [u8; 8] = [data[0], data[1], data[2], data[3], 0, 0, 0, 0];
132             self.address &= !0xffffffff;
133             self.address |= u64::from_le_bytes(value);
134         } else if len == 4 && offset == PCI_MSI_ADDRESS_HI && self.is_64bit {
135             //write 64 bit message address high part
136             let value: [u8; 8] = [0, 0, 0, 0, data[0], data[1], data[2], data[3]];
137             self.address &= 0xffffffff;
138             self.address |= u64::from_le_bytes(value);
139         } else if len == 8 && offset == PCI_MSI_ADDRESS_LO && self.is_64bit {
140             // write 64 bit message address
141             let value: [u8; 8] = [
142                 data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7],
143             ];
144             self.address = u64::from_le_bytes(value);
145         } else if len == 2
146             && ((offset == PCI_MSI_DATA_32 && !self.is_64bit)
147                 || (offset == PCI_MSI_DATA_64 && self.is_64bit))
148         {
149             // write message data
150             let value: [u8; 2] = [data[0], data[1]];
151             self.data = u16::from_le_bytes(value);
152         }
153 
154         if self.is_msi_enabled() && (old_address != self.address || old_data != self.data) {
155             self.add_msi_route();
156         }
157 
158         ret
159     }
160 
is_msi_enabled(&self) -> bool161     pub fn is_msi_enabled(&self) -> bool {
162         self.ctrl & PCI_MSI_FLAGS_ENABLE == PCI_MSI_FLAGS_ENABLE
163     }
164 
add_msi_route(&self)165     fn add_msi_route(&self) {
166         let gsi = match self.gsi {
167             Some(g) => g,
168             None => {
169                 error!("Add msi route but gsi is none");
170                 return;
171             }
172         };
173         if let Err(e) = self.vm_socket_irq.send(&VmIrqRequest::AddMsiRoute {
174             gsi,
175             msi_address: self.address,
176             msi_data: self.data.into(),
177         }) {
178             error!("failed to send AddMsiRoute request at {:?}", e);
179             return;
180         }
181         match self.vm_socket_irq.recv() {
182             Ok(VmIrqResponse::Err(e)) => error!("failed to call AddMsiRoute request {:?}", e),
183             Ok(_) => {}
184             Err(e) => error!("failed to receive AddMsiRoute response {:?}", e),
185         }
186     }
187 
allocate_one_msi(&mut self)188     fn allocate_one_msi(&mut self) {
189         let irqfd = match self.irqfd.take() {
190             Some(e) => e,
191             None => match Event::new() {
192                 Ok(e) => e,
193                 Err(e) => {
194                     error!("failed to create event: {:?}", e);
195                     return;
196                 }
197             },
198         };
199 
200         let request = VmIrqRequest::AllocateOneMsi {
201             irqfd,
202             device_id: self.device_id,
203             queue_id: 0,
204             device_name: self.device_name.clone(),
205         };
206         let request_result = self.vm_socket_irq.send(&request);
207 
208         // Stash the irqfd in self immediately because we used take above.
209         self.irqfd = match request {
210             VmIrqRequest::AllocateOneMsi { irqfd, .. } => Some(irqfd),
211             _ => unreachable!(),
212         };
213 
214         if let Err(e) = request_result {
215             error!("failed to send AllocateOneMsi request: {:?}", e);
216             return;
217         }
218 
219         match self.vm_socket_irq.recv() {
220             Ok(VmIrqResponse::AllocateOneMsi { gsi }) => self.gsi = Some(gsi),
221             _ => error!("failed to receive AllocateOneMsi Response"),
222         }
223     }
224 
enable(&mut self)225     fn enable(&mut self) {
226         if self.gsi.is_none() || self.irqfd.is_none() {
227             self.allocate_one_msi();
228         }
229 
230         self.add_msi_route();
231     }
232 
get_irqfd(&self) -> Option<&Event>233     pub fn get_irqfd(&self) -> Option<&Event> {
234         self.irqfd.as_ref()
235     }
236 
destroy(&mut self)237     pub fn destroy(&mut self) {
238         if let Some(gsi) = self.gsi {
239             if let Some(irqfd) = self.irqfd.take() {
240                 let request = VmIrqRequest::ReleaseOneIrq { gsi, irqfd };
241                 if self.vm_socket_irq.send(&request).is_ok() {
242                     let _ = self.vm_socket_irq.recv::<VmIrqResponse>();
243                 }
244             }
245         }
246     }
247 
248     /// Return the raw descriptor of the MSI device socket
get_msi_socket(&self) -> RawDescriptor249     pub fn get_msi_socket(&self) -> RawDescriptor {
250         self.vm_socket_irq.as_raw_descriptor()
251     }
252 
trigger(&self)253     pub fn trigger(&self) {
254         if let Some(irqfd) = self.irqfd.as_ref() {
255             irqfd.signal().unwrap();
256         }
257     }
258 }
259 
260 #[bitfield]
261 #[derive(Copy, Clone, AsBytes, FromBytes)]
262 pub struct MsiCtrl {
263     enable: B1,
264     multi_msg_capable: B3,
265     multi_msg_enable: B3,
266     is_64bit: B1,
267     per_vector_masking: B1,
268     extended_msg_data_capable: B1,
269     extended_msg_data_enable: B1,
270     reserved: B5,
271 }
272 
273 #[allow(dead_code)]
274 #[repr(C, align(4))]
275 #[derive(Clone, Copy, Default, AsBytes, FromBytes)]
276 struct Msi32BitWithoutMask {
277     msg_data: u16,
278     msg_extended_data: u16,
279     _padding: [u8; 12],
280 }
281 
282 #[allow(dead_code)]
283 #[repr(C, align(4))]
284 #[derive(Clone, Copy, Default, AsBytes, FromBytes)]
285 struct Msi32BitWithMask {
286     msg_data: u16,
287     msg_extended_data: u16,
288     mask_bits: u32,
289     pending_bits: u32,
290     _padding: [u8; 4],
291 }
292 
293 #[allow(dead_code)]
294 #[repr(C, align(4))]
295 #[derive(Clone, Copy, Default, AsBytes, FromBytes)]
296 struct Msi64BitWithoutMask {
297     msg_upper: u32,
298     msg_data: u16,
299     msg_extended_data: u16,
300     _padding: [u8; 8],
301 }
302 
303 #[allow(dead_code)]
304 #[repr(C)]
305 #[derive(Clone, Copy, Default, AsBytes, FromBytes)]
306 struct Msi64BitWithMask {
307     msg_upper: u32,
308     msg_data: u16,
309     msg_extended_data: u16,
310     mask_bits: u32,
311     pending_bits: u32,
312 }
313 
314 #[allow(dead_code)]
315 #[repr(C)]
316 #[derive(Clone, Copy, AsBytes, FromBytes)]
317 union MsiVary {
318     msi_32bit_without_mask: Msi32BitWithoutMask,
319     msi_32bit_with_mask: Msi32BitWithMask,
320     msi_64bit_without_mask: Msi64BitWithoutMask,
321     msi_64bit_with_mask: Msi64BitWithMask,
322 }
323 
324 #[allow(dead_code)]
325 #[repr(C)]
326 #[derive(Clone, Copy, AsBytes, FromBytes)]
327 /// MSI Capability Structure
328 pub struct MsiCap {
329     // To make add_capability() happy
330     _cap_vndr: u8,
331     _cap_next: u8,
332     // Message Control Register
333     msg_ctl: MsiCtrl,
334     // Message Address
335     msg_addr: u32,
336     // Msi Vary structure
337     msi_vary: MsiVary,
338 }
339 
340 impl PciCapability for MsiCap {
bytes(&self) -> &[u8]341     fn bytes(&self) -> &[u8] {
342         self.as_bytes()
343     }
344 
id(&self) -> PciCapabilityID345     fn id(&self) -> PciCapabilityID {
346         PciCapabilityID::MessageSignalledInterrupts
347     }
348 
writable_bits(&self) -> Vec<u32>349     fn writable_bits(&self) -> Vec<u32> {
350         // Check spec for detail
351         match (
352             self.msg_ctl.get_is_64bit(),
353             self.msg_ctl.get_per_vector_masking(),
354         ) {
355             (0, 0) => vec![0x0471_0000, 0xffff_fffc, 0xffff_ffff],
356             (0, 1) => vec![0x0471_0000, 0xffff_fffc, 0xffff_ffff, 0xffff_ffff],
357             (1, 0) => vec![
358                 0x0471_0000,
359                 0xffff_fffc,
360                 0xffff_ffff,
361                 0xffff_ffff,
362                 0x0000_0000,
363             ],
364             (1, 1) => vec![
365                 0x0471_0000,
366                 0xffff_fffc,
367                 0xffff_ffff,
368                 0xffff_ffff,
369                 0xffff_ffff,
370                 0x0000_0000,
371             ],
372             (_, _) => Vec::new(),
373         }
374     }
375 }
376 
377 impl MsiCap {
new(is_64bit: bool, mask_cap: bool) -> Self378     pub fn new(is_64bit: bool, mask_cap: bool) -> Self {
379         let mut msg_ctl = MsiCtrl::new();
380         if is_64bit {
381             msg_ctl.set_is_64bit(1);
382         }
383         if mask_cap {
384             msg_ctl.set_per_vector_masking(1);
385         }
386         let msi_vary = match (is_64bit, mask_cap) {
387             (false, false) => MsiVary {
388                 msi_32bit_without_mask: Msi32BitWithoutMask::default(),
389             },
390             (false, true) => MsiVary {
391                 msi_32bit_with_mask: Msi32BitWithMask::default(),
392             },
393             (true, false) => MsiVary {
394                 msi_64bit_without_mask: Msi64BitWithoutMask::default(),
395             },
396             (true, true) => MsiVary {
397                 msi_64bit_with_mask: Msi64BitWithMask::default(),
398             },
399         };
400         MsiCap {
401             _cap_vndr: 0,
402             _cap_next: 0,
403             msg_ctl,
404             msg_addr: 0,
405             msi_vary,
406         }
407     }
408 }
409