devices/pci/
msi.rs

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