1ee39e465SSebastien Boeuf // Copyright © 2019 Intel Corporation
2ee39e465SSebastien Boeuf //
3ee39e465SSebastien Boeuf // SPDX-License-Identifier: Apache-2.0 OR BSD-3-Clause
4ee39e465SSebastien Boeuf //
5ee39e465SSebastien Boeuf
6f076819dSSebastien Boeuf use std::io;
74bb12a2dSSebastien Boeuf use std::sync::Arc;
888a9f799SRob Bradford
988a9f799SRob Bradford use byteorder::{ByteOrder, LittleEndian};
1088a9f799SRob Bradford use serde::{Deserialize, Serialize};
11f076819dSSebastien Boeuf use thiserror::Error;
124bb12a2dSSebastien Boeuf use vm_device::interrupt::{
134bb12a2dSSebastien Boeuf InterruptIndex, InterruptSourceConfig, InterruptSourceGroup, MsiIrqSourceConfig,
144bb12a2dSSebastien Boeuf };
1510ab87d6SRob Bradford use vm_migration::{MigratableError, Pausable, Snapshot, Snapshottable};
16ee39e465SSebastien Boeuf
17ee39e465SSebastien Boeuf // MSI control masks
18ee39e465SSebastien Boeuf const MSI_CTL_ENABLE: u16 = 0x1;
19ee39e465SSebastien Boeuf const MSI_CTL_MULTI_MSG_ENABLE: u16 = 0x70;
20ee39e465SSebastien Boeuf const MSI_CTL_64_BITS: u16 = 0x80;
21ee39e465SSebastien Boeuf const MSI_CTL_PER_VECTOR: u16 = 0x100;
22ee39e465SSebastien Boeuf
23ee39e465SSebastien Boeuf // MSI message offsets
24ee39e465SSebastien Boeuf const MSI_MSG_CTL_OFFSET: u64 = 0x2;
25ee39e465SSebastien Boeuf const MSI_MSG_ADDR_LO_OFFSET: u64 = 0x4;
26ee39e465SSebastien Boeuf
27ee39e465SSebastien Boeuf // MSI message masks
28ee39e465SSebastien Boeuf const MSI_MSG_ADDR_LO_MASK: u32 = 0xffff_fffc;
29ee39e465SSebastien Boeuf
msi_num_enabled_vectors(msg_ctl: u16) -> usize304bb12a2dSSebastien Boeuf pub fn msi_num_enabled_vectors(msg_ctl: u16) -> usize {
314bb12a2dSSebastien Boeuf let field = (msg_ctl >> 4) & 0x7;
324bb12a2dSSebastien Boeuf
334bb12a2dSSebastien Boeuf if field > 5 {
344bb12a2dSSebastien Boeuf return 0;
354bb12a2dSSebastien Boeuf }
364bb12a2dSSebastien Boeuf
374bb12a2dSSebastien Boeuf 1 << field
384bb12a2dSSebastien Boeuf }
394bb12a2dSSebastien Boeuf
40f076819dSSebastien Boeuf #[derive(Error, Debug)]
411eac37bdSSebastien Boeuf pub enum Error {
42*a3692144SPhilipp Schuster #[error("Failed enabling the interrupt route")]
4380e66657SPhilipp Schuster EnableInterruptRoute(#[source] io::Error),
44*a3692144SPhilipp Schuster #[error("Failed updating the interrupt route")]
4580e66657SPhilipp Schuster UpdateInterruptRoute(#[source] io::Error),
46f076819dSSebastien Boeuf }
47f076819dSSebastien Boeuf
481eac37bdSSebastien Boeuf pub const MSI_CONFIG_ID: &str = "msi_config";
491eac37bdSSebastien Boeuf
5010ab87d6SRob Bradford #[derive(Clone, Copy, Default, Serialize, Deserialize)]
51ee39e465SSebastien Boeuf pub struct MsiCap {
52ee39e465SSebastien Boeuf // Message Control Register
53ee39e465SSebastien Boeuf // 0: MSI enable.
54ee39e465SSebastien Boeuf // 3-1; Multiple message capable.
55ee39e465SSebastien Boeuf // 6-4: Multiple message enable.
56ee39e465SSebastien Boeuf // 7: 64 bits address capable.
57ee39e465SSebastien Boeuf // 8: Per-vector masking capable.
58ee39e465SSebastien Boeuf // 15-9: Reserved.
59ee39e465SSebastien Boeuf pub msg_ctl: u16,
60ee39e465SSebastien Boeuf // Message Address (LSB)
61ee39e465SSebastien Boeuf // 1-0: Reserved.
62ee39e465SSebastien Boeuf // 31-2: Message address.
63ee39e465SSebastien Boeuf pub msg_addr_lo: u32,
64ee39e465SSebastien Boeuf // Message Upper Address (MSB)
65ee39e465SSebastien Boeuf // 31-0: Message address.
66ee39e465SSebastien Boeuf pub msg_addr_hi: u32,
67ee39e465SSebastien Boeuf // Message Data
68ee39e465SSebastien Boeuf // 15-0: Message data.
69ee39e465SSebastien Boeuf pub msg_data: u16,
70ee39e465SSebastien Boeuf // Mask Bits
71ee39e465SSebastien Boeuf // 31-0: Mask bits.
72ee39e465SSebastien Boeuf pub mask_bits: u32,
73ee39e465SSebastien Boeuf // Pending Bits
74ee39e465SSebastien Boeuf // 31-0: Pending bits.
75ee39e465SSebastien Boeuf pub pending_bits: u32,
76ee39e465SSebastien Boeuf }
77ee39e465SSebastien Boeuf
78ee39e465SSebastien Boeuf impl MsiCap {
addr_64_bits(&self) -> bool79ee39e465SSebastien Boeuf fn addr_64_bits(&self) -> bool {
80ee39e465SSebastien Boeuf self.msg_ctl & MSI_CTL_64_BITS == MSI_CTL_64_BITS
81ee39e465SSebastien Boeuf }
82ee39e465SSebastien Boeuf
per_vector_mask(&self) -> bool83ee39e465SSebastien Boeuf fn per_vector_mask(&self) -> bool {
84ee39e465SSebastien Boeuf self.msg_ctl & MSI_CTL_PER_VECTOR == MSI_CTL_PER_VECTOR
85ee39e465SSebastien Boeuf }
86ee39e465SSebastien Boeuf
enabled(&self) -> bool87f3c38701SSebastien Boeuf fn enabled(&self) -> bool {
88ee39e465SSebastien Boeuf self.msg_ctl & MSI_CTL_ENABLE == MSI_CTL_ENABLE
89ee39e465SSebastien Boeuf }
90ee39e465SSebastien Boeuf
num_enabled_vectors(&self) -> usize91f3c38701SSebastien Boeuf fn num_enabled_vectors(&self) -> usize {
924bb12a2dSSebastien Boeuf msi_num_enabled_vectors(self.msg_ctl)
93ee39e465SSebastien Boeuf }
94ee39e465SSebastien Boeuf
vector_masked(&self, vector: usize) -> bool95f3c38701SSebastien Boeuf fn vector_masked(&self, vector: usize) -> bool {
96ee39e465SSebastien Boeuf if !self.per_vector_mask() {
97ee39e465SSebastien Boeuf return false;
98ee39e465SSebastien Boeuf }
99ee39e465SSebastien Boeuf
100ee39e465SSebastien Boeuf (self.mask_bits >> vector) & 0x1 == 0x1
101ee39e465SSebastien Boeuf }
102ee39e465SSebastien Boeuf
size(&self) -> u64103f3c38701SSebastien Boeuf fn size(&self) -> u64 {
104ee39e465SSebastien Boeuf let mut size: u64 = 0xa;
105ee39e465SSebastien Boeuf
106ee39e465SSebastien Boeuf if self.addr_64_bits() {
107ee39e465SSebastien Boeuf size += 0x4;
108ee39e465SSebastien Boeuf }
109ee39e465SSebastien Boeuf if self.per_vector_mask() {
110ee39e465SSebastien Boeuf size += 0xa;
111ee39e465SSebastien Boeuf }
112ee39e465SSebastien Boeuf
113ee39e465SSebastien Boeuf size
114ee39e465SSebastien Boeuf }
115ee39e465SSebastien Boeuf
update(&mut self, offset: u64, data: &[u8])116f3c38701SSebastien Boeuf fn update(&mut self, offset: u64, data: &[u8]) {
117ee39e465SSebastien Boeuf // Calculate message data offset depending on the address being 32 or
118ee39e465SSebastien Boeuf // 64 bits.
119ee39e465SSebastien Boeuf // Calculate upper address offset if the address is 64 bits.
120ee39e465SSebastien Boeuf // Calculate mask bits offset based on the address being 32 or 64 bits
121ee39e465SSebastien Boeuf // and based on the per vector masking being enabled or not.
122ee39e465SSebastien Boeuf let (msg_data_offset, addr_hi_offset, mask_bits_offset): (u64, Option<u64>, Option<u64>) =
123ee39e465SSebastien Boeuf if self.addr_64_bits() {
124ee39e465SSebastien Boeuf let mask_bits = if self.per_vector_mask() {
125ee39e465SSebastien Boeuf Some(0x10)
126ee39e465SSebastien Boeuf } else {
127ee39e465SSebastien Boeuf None
128ee39e465SSebastien Boeuf };
129ee39e465SSebastien Boeuf (0xc, Some(0x8), mask_bits)
130ee39e465SSebastien Boeuf } else {
131ee39e465SSebastien Boeuf let mask_bits = if self.per_vector_mask() {
132ee39e465SSebastien Boeuf Some(0xc)
133ee39e465SSebastien Boeuf } else {
134ee39e465SSebastien Boeuf None
135ee39e465SSebastien Boeuf };
136ee39e465SSebastien Boeuf (0x8, None, mask_bits)
137ee39e465SSebastien Boeuf };
138ee39e465SSebastien Boeuf
139ee39e465SSebastien Boeuf // Update cache without overriding the read-only bits.
140ee39e465SSebastien Boeuf match data.len() {
141ee39e465SSebastien Boeuf 2 => {
142ee39e465SSebastien Boeuf let value = LittleEndian::read_u16(data);
143ee39e465SSebastien Boeuf match offset {
144ee39e465SSebastien Boeuf MSI_MSG_CTL_OFFSET => {
145ee39e465SSebastien Boeuf self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
146ee39e465SSebastien Boeuf | (value & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
147ee39e465SSebastien Boeuf }
148ee39e465SSebastien Boeuf x if x == msg_data_offset => self.msg_data = value,
149ee39e465SSebastien Boeuf _ => error!("invalid offset"),
150ee39e465SSebastien Boeuf }
151ee39e465SSebastien Boeuf }
152ee39e465SSebastien Boeuf 4 => {
153ee39e465SSebastien Boeuf let value = LittleEndian::read_u32(data);
154ee39e465SSebastien Boeuf match offset {
1551379abb9SSebastien Boeuf 0x0 => {
156ee39e465SSebastien Boeuf self.msg_ctl = (self.msg_ctl & !(MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
157ee39e465SSebastien Boeuf | ((value >> 16) as u16 & (MSI_CTL_ENABLE | MSI_CTL_MULTI_MSG_ENABLE))
158ee39e465SSebastien Boeuf }
159ee39e465SSebastien Boeuf MSI_MSG_ADDR_LO_OFFSET => self.msg_addr_lo = value & MSI_MSG_ADDR_LO_MASK,
160ee39e465SSebastien Boeuf x if x == msg_data_offset => self.msg_data = value as u16,
161ee39e465SSebastien Boeuf x if addr_hi_offset.is_some() && x == addr_hi_offset.unwrap() => {
162ee39e465SSebastien Boeuf self.msg_addr_hi = value
163ee39e465SSebastien Boeuf }
164ee39e465SSebastien Boeuf x if mask_bits_offset.is_some() && x == mask_bits_offset.unwrap() => {
165ee39e465SSebastien Boeuf self.mask_bits = value
166ee39e465SSebastien Boeuf }
167ee39e465SSebastien Boeuf _ => error!("invalid offset"),
168ee39e465SSebastien Boeuf }
169ee39e465SSebastien Boeuf }
170ee39e465SSebastien Boeuf _ => error!("invalid data length"),
171ee39e465SSebastien Boeuf }
172ee39e465SSebastien Boeuf }
173ee39e465SSebastien Boeuf }
174f3c38701SSebastien Boeuf
17510ab87d6SRob Bradford #[derive(Serialize, Deserialize)]
1761eac37bdSSebastien Boeuf pub struct MsiConfigState {
177f076819dSSebastien Boeuf cap: MsiCap,
178f076819dSSebastien Boeuf }
179f076819dSSebastien Boeuf
180f3c38701SSebastien Boeuf pub struct MsiConfig {
181a1b996acSSebastien Boeuf pub cap: MsiCap,
182dcc646f5SSebastien Boeuf interrupt_source_group: Arc<dyn InterruptSourceGroup>,
183f3c38701SSebastien Boeuf }
184f3c38701SSebastien Boeuf
185f3c38701SSebastien Boeuf impl MsiConfig {
new( msg_ctl: u16, interrupt_source_group: Arc<dyn InterruptSourceGroup>, state: Option<MsiConfigState>, ) -> Result<Self, Error>1861eac37bdSSebastien Boeuf pub fn new(
1871eac37bdSSebastien Boeuf msg_ctl: u16,
1881eac37bdSSebastien Boeuf interrupt_source_group: Arc<dyn InterruptSourceGroup>,
1891eac37bdSSebastien Boeuf state: Option<MsiConfigState>,
1901eac37bdSSebastien Boeuf ) -> Result<Self, Error> {
1911eac37bdSSebastien Boeuf let cap = if let Some(state) = state {
1921eac37bdSSebastien Boeuf if state.cap.enabled() {
1931eac37bdSSebastien Boeuf for idx in 0..state.cap.num_enabled_vectors() {
1941eac37bdSSebastien Boeuf let config = MsiIrqSourceConfig {
1951eac37bdSSebastien Boeuf high_addr: state.cap.msg_addr_hi,
1961eac37bdSSebastien Boeuf low_addr: state.cap.msg_addr_lo,
1971eac37bdSSebastien Boeuf data: state.cap.msg_data as u32,
1981eac37bdSSebastien Boeuf devid: 0,
199f3c38701SSebastien Boeuf };
200f3c38701SSebastien Boeuf
2011eac37bdSSebastien Boeuf interrupt_source_group
2021eac37bdSSebastien Boeuf .update(
2031eac37bdSSebastien Boeuf idx as InterruptIndex,
2041eac37bdSSebastien Boeuf InterruptSourceConfig::MsiIrq(config),
2051eac37bdSSebastien Boeuf state.cap.vector_masked(idx),
2060149e650SYong He false,
2071eac37bdSSebastien Boeuf )
2081eac37bdSSebastien Boeuf .map_err(Error::UpdateInterruptRoute)?;
2091eac37bdSSebastien Boeuf }
2101eac37bdSSebastien Boeuf
2111eac37bdSSebastien Boeuf interrupt_source_group
2120149e650SYong He .set_gsi()
2130149e650SYong He .map_err(Error::EnableInterruptRoute)?;
2140149e650SYong He
2150149e650SYong He interrupt_source_group
2161eac37bdSSebastien Boeuf .enable()
2171eac37bdSSebastien Boeuf .map_err(Error::EnableInterruptRoute)?;
2181eac37bdSSebastien Boeuf }
2191eac37bdSSebastien Boeuf
2201eac37bdSSebastien Boeuf state.cap
2211eac37bdSSebastien Boeuf } else {
2221eac37bdSSebastien Boeuf MsiCap {
2231eac37bdSSebastien Boeuf msg_ctl,
2241eac37bdSSebastien Boeuf ..Default::default()
2251eac37bdSSebastien Boeuf }
2261eac37bdSSebastien Boeuf };
2271eac37bdSSebastien Boeuf
2281eac37bdSSebastien Boeuf Ok(MsiConfig {
229f3c38701SSebastien Boeuf cap,
2304bb12a2dSSebastien Boeuf interrupt_source_group,
2311eac37bdSSebastien Boeuf })
232f3c38701SSebastien Boeuf }
233f3c38701SSebastien Boeuf
state(&self) -> MsiConfigState234f076819dSSebastien Boeuf fn state(&self) -> MsiConfigState {
235f076819dSSebastien Boeuf MsiConfigState { cap: self.cap }
236f076819dSSebastien Boeuf }
237f076819dSSebastien Boeuf
enabled(&self) -> bool238f3c38701SSebastien Boeuf pub fn enabled(&self) -> bool {
239f3c38701SSebastien Boeuf self.cap.enabled()
240f3c38701SSebastien Boeuf }
241f3c38701SSebastien Boeuf
size(&self) -> u64242f3c38701SSebastien Boeuf pub fn size(&self) -> u64 {
243f3c38701SSebastien Boeuf self.cap.size()
244f3c38701SSebastien Boeuf }
245f3c38701SSebastien Boeuf
num_enabled_vectors(&self) -> usize2464bb12a2dSSebastien Boeuf pub fn num_enabled_vectors(&self) -> usize {
2474bb12a2dSSebastien Boeuf self.cap.num_enabled_vectors()
2484bb12a2dSSebastien Boeuf }
2494bb12a2dSSebastien Boeuf
update(&mut self, offset: u64, data: &[u8])2501a4b5eccSSebastien Boeuf pub fn update(&mut self, offset: u64, data: &[u8]) {
2511a4b5eccSSebastien Boeuf let old_enabled = self.cap.enabled();
2521a4b5eccSSebastien Boeuf
2531a4b5eccSSebastien Boeuf self.cap.update(offset, data);
2541a4b5eccSSebastien Boeuf
2551a4b5eccSSebastien Boeuf if self.cap.enabled() {
2564bb12a2dSSebastien Boeuf for idx in 0..self.num_enabled_vectors() {
2574bb12a2dSSebastien Boeuf let config = MsiIrqSourceConfig {
2584bb12a2dSSebastien Boeuf high_addr: self.cap.msg_addr_hi,
2594bb12a2dSSebastien Boeuf low_addr: self.cap.msg_addr_lo,
2604bb12a2dSSebastien Boeuf data: self.cap.msg_data as u32,
261cce62375SMichael Zhao devid: 0,
2624bb12a2dSSebastien Boeuf };
2634bb12a2dSSebastien Boeuf
264ed87e42eSRob Bradford if let Err(e) = self.interrupt_source_group.update(
265ed87e42eSRob Bradford idx as InterruptIndex,
266ed87e42eSRob Bradford InterruptSourceConfig::MsiIrq(config),
267ed87e42eSRob Bradford self.cap.vector_masked(idx),
2680149e650SYong He true,
269ed87e42eSRob Bradford ) {
2704bb12a2dSSebastien Boeuf error!("Failed updating vector: {:?}", e);
2714bb12a2dSSebastien Boeuf }
2724bb12a2dSSebastien Boeuf }
2734bb12a2dSSebastien Boeuf
2741a4b5eccSSebastien Boeuf if !old_enabled {
2754bb12a2dSSebastien Boeuf if let Err(e) = self.interrupt_source_group.enable() {
2761a4b5eccSSebastien Boeuf error!("Failed enabling irq_fd: {:?}", e);
2771a4b5eccSSebastien Boeuf }
2781a4b5eccSSebastien Boeuf }
2794bb12a2dSSebastien Boeuf } else if old_enabled {
2804bb12a2dSSebastien Boeuf if let Err(e) = self.interrupt_source_group.disable() {
2811a4b5eccSSebastien Boeuf error!("Failed disabling irq_fd: {:?}", e);
2821a4b5eccSSebastien Boeuf }
2831a4b5eccSSebastien Boeuf }
2841a4b5eccSSebastien Boeuf }
285f3c38701SSebastien Boeuf }
286f076819dSSebastien Boeuf
287f076819dSSebastien Boeuf impl Pausable for MsiConfig {}
288f076819dSSebastien Boeuf
289f076819dSSebastien Boeuf impl Snapshottable for MsiConfig {
id(&self) -> String290f076819dSSebastien Boeuf fn id(&self) -> String {
2911eac37bdSSebastien Boeuf String::from(MSI_CONFIG_ID)
292f076819dSSebastien Boeuf }
293f076819dSSebastien Boeuf
snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError>294f076819dSSebastien Boeuf fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
29510ab87d6SRob Bradford Snapshot::new_from_state(&self.state())
296f076819dSSebastien Boeuf }
297f076819dSSebastien Boeuf }
298