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