xref: /cloud-hypervisor/pci/src/msi.rs (revision f7f2f25a574b1b2dba22c094fc8226d404157d15)
1 // Copyright © 2019 Intel Corporation
2 //
3 // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4 //
5 
6 use byteorder::{ByteOrder, LittleEndian};
7 use std::sync::Arc;
8 use vm_device::interrupt::{
9     InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
10 };
11 
12 // MSI control masks
13 const MSI_CTL_ENABLE: u16 = 0x1;
14 const MSI_CTL_MULTI_MSG_ENABLE: u16 = 0x70;
15 const MSI_CTL_64_BITS: u16 = 0x80;
16 const MSI_CTL_PER_VECTOR: u16 = 0x100;
17 
18 // MSI message offsets
19 const MSI_MSG_CTL_OFFSET: u64 = 0x2;
20 const MSI_MSG_ADDR_LO_OFFSET: u64 = 0x4;
21 
22 // MSI message masks
23 const MSI_MSG_ADDR_LO_MASK: u32 = 0xffff_fffc;
24 
25 pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
26     let field = (msg_ctl >> 4) & 0x7;
27 
28     if field > 5 {
29         return 0;
30     }
31 
32     1 << field
33 }
34 
35 #[derive(Clone, Copy, Default)]
36 pub struct MsiCap {
37     // Message Control Register
38     //   0:     MSI enable.
39     //   3-1;   Multiple message capable.
40     //   6-4:   Multiple message enable.
41     //   7:     64 bits address capable.
42     //   8:     Per-vector masking capable.
43     //   15-9:  Reserved.
44     pub msg_ctl: u16,
45     // Message Address (LSB)
46     //   1-0:  Reserved.
47     //   31-2: Message address.
48     pub msg_addr_lo: u32,
49     // Message Upper Address (MSB)
50     //   31-0: Message address.
51     pub msg_addr_hi: u32,
52     // Message Data
53     //   15-0: Message data.
54     pub msg_data: u16,
55     // Mask Bits
56     //   31-0: Mask bits.
57     pub mask_bits: u32,
58     // Pending Bits
59     //   31-0: Pending bits.
60     pub pending_bits: u32,
61 }
62 
63 impl MsiCap {
64     fn addr_64_bits(&self) -> bool {
65         self.msg_ctl & MSI_CTL_64_BITS == MSI_CTL_64_BITS
66     }
67 
68     fn per_vector_mask(&self) -> bool {
69         self.msg_ctl & MSI_CTL_PER_VECTOR == MSI_CTL_PER_VECTOR
70     }
71 
72     fn enabled(&self) -> bool {
73         self.msg_ctl & MSI_CTL_ENABLE == MSI_CTL_ENABLE
74     }
75 
76     fn num_enabled_vectors(&self) -> usize {
77         msi_num_enabled_vectors(self.msg_ctl)
78     }
79 
80     fn vector_masked(&self, vector: usize) -> bool {
81         if !self.per_vector_mask() {
82             return false;
83         }
84 
85         (self.mask_bits >> vector) & 0x1 == 0x1
86     }
87 
88     fn size(&self) -> u64 {
89         let mut size: u64 = 0xa;
90 
91         if self.addr_64_bits() {
92             size += 0x4;
93         }
94         if self.per_vector_mask() {
95             size += 0xa;
96         }
97 
98         size
99     }
100 
101     fn update(&mut self, offset: u64, data: &[u8]) {
102         // Calculate message data offset depending on the address being 32 or
103         // 64 bits.
104         // Calculate upper address offset if the address is 64 bits.
105         // Calculate mask bits offset based on the address being 32 or 64 bits
106         // and based on the per vector masking being enabled or not.
107         let (msg_data_offset, addr_hi_offset, mask_bits_offset): (u64, Option<u64>, Option<u64>) =
108             if self.addr_64_bits() {
109                 let mask_bits = if self.per_vector_mask() {
110                     Some(0x10)
111                 } else {
112                     None
113                 };
114                 (0xc, Some(0x8), mask_bits)
115             } else {
116                 let mask_bits = if self.per_vector_mask() {
117                     Some(0xc)
118                 } else {
119                     None
120                 };
121                 (0x8, None, mask_bits)
122             };
123 
124         // Update cache without overriding the read-only bits.
125         match data.len() {
126             2 => {
127                 let value = LittleEndian::read_u16(data);
128                 match offset {
129                     MSI_MSG_CTL_OFFSET => {
130                         self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
131                             | (value & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
132                     }
133                     x if x == msg_data_offset => self.msg_data = value,
134                     _ => error!("invalid offset"),
135                 }
136             }
137             4 => {
138                 let value = LittleEndian::read_u32(data);
139                 match offset {
140                     0x0 => {
141                         self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
142                             | ((value >> 16) as u16 & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
143                     }
144                     MSI_MSG_ADDR_LO_OFFSET => self.msg_addr_lo = value & MSI_MSG_ADDR_LO_MASK,
145                     x if x == msg_data_offset => self.msg_data = value as u16,
146                     x if addr_hi_offset.is_some() && x == addr_hi_offset.unwrap() => {
147                         self.msg_addr_hi = value
148                     }
149                     x if mask_bits_offset.is_some() && x == mask_bits_offset.unwrap() => {
150                         self.mask_bits = value
151                     }
152                     _ => error!("invalid offset"),
153                 }
154             }
155             _ => error!("invalid data length"),
156         }
157     }
158 }
159 
160 pub struct MsiConfig {
161     cap: MsiCap,
162     interrupt_source_group: Arc<dyn InterruptSourceGroup>,
163 }
164 
165 impl MsiConfig {
166     pub fn new(msg_ctl: u16, interrupt_source_group: Arc<dyn InterruptSourceGroup>) -> Self {
167         let cap = MsiCap {
168             msg_ctl,
169             ..Default::default()
170         };
171 
172         MsiConfig {
173             cap,
174             interrupt_source_group,
175         }
176     }
177 
178     pub fn enabled(&self) -> bool {
179         self.cap.enabled()
180     }
181 
182     pub fn size(&self) -> u64 {
183         self.cap.size()
184     }
185 
186     pub fn num_enabled_vectors(&self) -> usize {
187         self.cap.num_enabled_vectors()
188     }
189 
190     pub fn update(&mut self, offset: u64, data: &[u8]) {
191         let old_enabled = self.cap.enabled();
192 
193         self.cap.update(offset, data);
194 
195         if self.cap.enabled() {
196             for idx in 0..self.num_enabled_vectors() {
197                 let config = MsiIrqSourceConfig {
198                     high_addr: self.cap.msg_addr_hi,
199                     low_addr: self.cap.msg_addr_lo,
200                     data: self.cap.msg_data as u32,
201                     devid: 0,
202                 };
203 
204                 if let Err(e) = self
205                     .interrupt_source_group
206                     .update(idx as InterruptIndex, InterruptSourceConfig::MsiIrq(config))
207                 {
208                     error!("Failed updating vector: {:?}", e);
209                 }
210 
211                 if self.cap.vector_masked(idx) {
212                     if let Err(e) = self.interrupt_source_group.mask(idx as InterruptIndex) {
213                         error!("Failed masking vector: {:?}", e);
214                     }
215                 } else if let Err(e) = self.interrupt_source_group.unmask(idx as InterruptIndex) {
216                     error!("Failed unmasking vector: {:?}", e);
217                 }
218             }
219 
220             if !old_enabled {
221                 if let Err(e) = self.interrupt_source_group.enable() {
222                     error!("Failed enabling irq_fd: {:?}", e);
223                 }
224             }
225         } else if old_enabled {
226             if let Err(e) = self.interrupt_source_group.disable() {
227                 error!("Failed disabling irq_fd: {:?}", e);
228             }
229         }
230     }
231 }
232