1use super::PciCapability;
7use crate::msi::MsiRoute;
8use crate::msi::MsiTarget;
9use crate::spec::caps::CapabilityId;
10use crate::spec::caps::msix::MsixCapabilityHeader;
11use crate::spec::caps::msix::MsixTableEntryIdx;
12use chipset_device::pci::ByteEnabledDwordRead;
13use chipset_device::pci::ByteEnabledDwordWrite;
14use inspect::Inspect;
15use inspect::InspectMut;
16use pal_event::Event;
17use parking_lot::Mutex;
18use std::fmt::Debug;
19use std::sync::Arc;
20use vmcore::interrupt::Interrupt;
21use vmcore::interrupt::InterruptTarget;
22
23#[derive(Debug, Inspect)]
24struct MsiTableLocation {
25 #[inspect(hex)]
26 offset: u32,
28 bar: u8,
29}
30
31impl MsiTableLocation {
32 fn new(bar: u8, offset: u32) -> Self {
33 assert!(bar < 6);
34 assert!(offset & 7 == 0);
35 Self { offset, bar }
36 }
37
38 fn read_u32(&self) -> u32 {
39 self.offset | self.bar as u32
40 }
41}
42
43#[derive(Inspect)]
44struct MsixCapability {
45 count: u16,
46 #[inspect(with = "|x| inspect::adhoc(|req| x.lock().inspect_mut(req))")]
47 state: Arc<Mutex<MsixState>>,
48 config_table_location: MsiTableLocation,
49 pending_bits_location: MsiTableLocation,
50}
51
52impl PciCapability for MsixCapability {
53 fn label(&self) -> &str {
54 "msi-x"
55 }
56
57 fn capability_id(&self) -> CapabilityId {
58 CapabilityId::MSIX
59 }
60
61 fn len(&self) -> usize {
62 12
63 }
64
65 fn read(&self, offset: u16, mut value: ByteEnabledDwordRead<'_>) {
66 match MsixCapabilityHeader(offset) {
67 MsixCapabilityHeader::CONTROL_CAPS => {
68 value.set_low_high(
69 CapabilityId::MSIX.0.into(),
70 (self.count - 1) | if self.state.lock().enabled { 0x8000 } else { 0 },
71 );
72 }
73 MsixCapabilityHeader::OFFSET_TABLE => value.set(self.config_table_location.read_u32()),
74 MsixCapabilityHeader::OFFSET_PBA => value.set(self.pending_bits_location.read_u32()),
75 _ => panic!("Unreachable read offset {}", offset),
76 }
77 }
78
79 fn write(&mut self, offset: u16, val: ByteEnabledDwordWrite) {
80 match MsixCapabilityHeader(offset) {
81 MsixCapabilityHeader::CONTROL_CAPS => {
82 const MSIX_ENABLE_BIT_MASK: u32 = 0x8000_0000;
83 if val.valid_mask() & MSIX_ENABLE_BIT_MASK != 0 {
84 let mut state = self.state.lock();
85 let was_enabled = state.enabled;
86 let new_enabled = (val.extract() & MSIX_ENABLE_BIT_MASK) != 0;
87
88 state.enabled = new_enabled;
89 if was_enabled && !new_enabled {
90 for entry in &mut state.vectors {
91 if entry.is_enabled(true) {
92 entry.msi.disable();
93 }
94 }
95 } else if new_enabled && !was_enabled {
96 for entry in &mut state.vectors {
97 if entry.is_enabled(true) {
98 entry.msi.enable(
99 entry.state.address,
100 entry.state.data,
101 entry.state.is_pending,
102 );
103 entry.state.is_pending = false;
104 }
105 }
106 }
107 }
108 }
109 MsixCapabilityHeader::OFFSET_TABLE | MsixCapabilityHeader::OFFSET_PBA => {
110 tracelimit::warn_ratelimited!(
111 "Unexpected write offset {:?}",
112 MsixCapabilityHeader(offset)
113 )
114 }
115 _ => panic!("Unreachable write offset {}", offset),
116 }
117 }
118
119 fn reset(&mut self) {
120 let mut state = self.state.lock();
121 state.enabled = false;
122 for vector in &mut state.vectors {
123 vector.msi.disable();
124 vector.state = EntryState::new();
125 }
126 }
127}
128
129#[derive(Clone, Inspect, Debug)]
130pub(crate) struct MsiInterrupt(#[inspect(flatten)] Arc<Mutex<MsiInterruptInner>>);
131
132#[derive(Inspect)]
133struct MsiInterruptInner {
134 #[inspect(skip)]
135 target: MsiTarget,
136 #[inspect(skip)]
140 route: Option<MsiRoute>,
141 pending: bool,
142 enabled: bool,
143 address: u64,
144 data: u32,
145}
146
147impl Debug for MsiInterruptInner {
148 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
149 f.debug_struct("MsiInterruptInner")
150 .field("pending", &self.pending)
151 .field("enabled", &self.enabled)
152 .field("address", &self.address)
153 .field("data", &self.data)
154 .field("has_route", &self.route.is_some())
155 .finish()
156 }
157}
158
159impl MsiInterruptInner {
160 fn signal_msi(&self) {
161 self.target.signal_msi(self.address, self.data);
162 }
163
164 fn enable_route(&self, route: &MsiRoute) {
165 route.enable(self.address, self.data);
166 }
167}
168
169impl MsiInterrupt {
170 pub fn new(target: MsiTarget) -> Self {
171 Self(Arc::new(Mutex::new(MsiInterruptInner {
172 target,
173 route: None,
174 pending: false,
175 enabled: false,
176 address: 0,
177 data: 0,
178 })))
179 }
180
181 pub fn enable(&self, address: u64, data: u32, set_pending: bool) {
182 let mut state = self.0.lock();
183 state.pending |= set_pending;
184 state.address = address;
185 state.data = data;
186 state.enabled = true;
187
188 if let Some(route) = &state.route {
190 state.enable_route(route);
191 }
192
193 if state.pending {
194 state.signal_msi();
195 state.pending = false;
196 }
197 }
198
199 pub fn disable(&self) {
200 let mut state = self.0.lock();
201 state.enabled = false;
202 if let Some(route) = &state.route {
203 route.disable();
204 }
205 }
206
207 pub fn drain_pending(&self) -> bool {
208 let mut state = self.0.lock();
209 if let Some(route) = &state.route {
210 state.pending |= route.consume_pending();
211 }
212 let was_pending = state.pending;
213 state.pending = false;
214 was_pending
215 }
216
217 pub fn interrupt(&self) -> Interrupt {
218 Interrupt::from_target(MsiInterruptTarget(self.0.clone()))
219 }
220}
221
222struct MsiInterruptTarget(Arc<Mutex<MsiInterruptInner>>);
225
226impl InterruptTarget for MsiInterruptTarget {
227 fn deliver(&self) {
228 let mut state = self.0.lock();
229 if state.enabled {
230 state.signal_msi();
231 } else {
232 state.pending = true;
233 }
234 }
235
236 fn event(&self) -> Option<Arc<Event>> {
237 let mut state = self.0.lock();
238 if let Some(route) = &state.route {
239 return Some(Arc::new(route.event().clone()));
240 }
241 let route = match state.target.new_route() {
242 Some(Ok(route)) => route,
243 Some(Err(e)) => {
244 tracelimit::warn_ratelimited!(error = ?e, "failed to allocate MSI route");
245 return None;
246 }
247 None => return None,
248 };
249 if state.enabled {
250 state.enable_route(&route);
251 } else {
252 route.disable();
253 }
254 let event = Arc::new(route.event().clone());
255 state.route = Some(route);
256 Some(event)
257 }
258}
259
260struct MsixMessageTableEntry {
261 msi: MsiInterrupt,
262 state: EntryState,
263}
264
265impl InspectMut for MsixMessageTableEntry {
266 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
267 req.respond()
268 .hex("address", self.state.address)
269 .hex("data", self.state.data)
270 .hex("control", self.state.control)
271 .field("enabled", self.state.control & 1 == 0)
272 .field("is_pending", self.check_is_pending(true));
273 }
274}
275
276#[derive(Debug)]
277struct EntryState {
278 address: u64,
279 data: u32,
280 control: u32,
281 is_pending: bool,
282}
283
284impl EntryState {
285 fn new() -> Self {
286 Self {
287 address: 0,
288 data: 0,
289 control: 1,
290 is_pending: false,
291 }
292 }
293}
294
295impl MsixMessageTableEntry {
296 fn new(msi: MsiInterrupt) -> Self {
297 Self {
298 msi,
299 state: EntryState::new(),
300 }
301 }
302
303 fn read_u32(&self, offset: u64) -> u32 {
304 match MsixTableEntryIdx(offset) {
305 MsixTableEntryIdx::MSG_ADDR_LO => self.state.address as u32,
306 MsixTableEntryIdx::MSG_ADDR_HI => (self.state.address >> 32) as u32,
307 MsixTableEntryIdx::MSG_DATA => self.state.data,
308 MsixTableEntryIdx::VECTOR_CTL => self.state.control,
309 _ => panic!("Unexpected read offset {}", offset),
310 }
311 }
312
313 fn write_u32(&mut self, offset: u64, val: u32) {
314 match MsixTableEntryIdx(offset) {
315 MsixTableEntryIdx::MSG_ADDR_LO => {
316 self.state.address = (self.state.address & 0xffffffff00000000) | val as u64
317 }
318 MsixTableEntryIdx::MSG_ADDR_HI => {
319 self.state.address = (val as u64) << 32 | self.state.address & 0xffffffff
320 }
321 MsixTableEntryIdx::MSG_DATA => self.state.data = val,
322 MsixTableEntryIdx::VECTOR_CTL => self.state.control = val,
323 _ => panic!("Unexpected write offset {}", offset),
324 }
325 }
326
327 fn is_enabled(&self, global_enabled: bool) -> bool {
328 global_enabled && self.state.control & 1 == 0
329 }
330
331 fn check_is_pending(&mut self, global_enabled: bool) -> bool {
332 if !self.state.is_pending && !self.is_enabled(global_enabled) {
333 self.state.is_pending = self.msi.drain_pending();
334 }
335 self.state.is_pending
336 }
337}
338
339#[derive(InspectMut)]
340struct MsixState {
341 enabled: bool,
342 #[inspect(mut, with = "inspect_entries")]
343 vectors: Vec<MsixMessageTableEntry>,
344}
345
346fn inspect_entries(entries: &mut [MsixMessageTableEntry]) -> impl '_ + InspectMut {
347 inspect::adhoc_mut(|req| {
348 let mut resp = req.respond();
349 for (i, entry) in entries.iter_mut().enumerate() {
350 resp.field_mut(&i.to_string(), entry);
351 }
352 })
353}
354
355#[derive(Clone)]
358pub struct MsixEmulator {
359 state: Arc<Mutex<MsixState>>,
360 pending_bits_offset: u32,
362 pending_bits_dword_count: u16,
363}
364
365impl MsixEmulator {
366 pub fn new(bar: u8, count: u16, msi_target: &MsiTarget) -> (Self, impl PciCapability + use<>) {
380 let state = MsixState {
381 enabled: false,
382 vectors: (0..count)
383 .map(|_| MsixMessageTableEntry::new(MsiInterrupt::new(msi_target.clone())))
384 .collect(),
385 };
386 let state = Arc::new(Mutex::new(state));
387 let pending_bits_offset = count as u32 * 16;
388 (
389 Self {
390 state: state.clone(),
391 pending_bits_offset,
392 pending_bits_dword_count: count.div_ceil(32),
393 },
394 MsixCapability {
395 count,
396 state,
397 config_table_location: MsiTableLocation::new(bar, 0),
398 pending_bits_location: MsiTableLocation::new(bar, pending_bits_offset),
399 },
400 )
401 }
402
403 pub fn bar_len(&self) -> u64 {
407 self.pending_bits_offset as u64 + self.pending_bits_dword_count as u64 * 4
408 }
409
410 pub fn read_u32(&self, offset: u64) -> u32 {
412 let mut state = self.state.lock();
413 let state: &mut MsixState = &mut state;
414 if offset < self.pending_bits_offset as u64 {
415 let index = offset / 16;
416 if let Some(entry) = state.vectors.get(index as usize) {
417 return entry.read_u32(offset & 0xf);
418 }
419 } else {
420 let dword = (offset - self.pending_bits_offset as u64) / 4;
421 let start = dword as usize * 32;
422 if start < state.vectors.len() {
423 let end = (start + 32).min(state.vectors.len());
424 let mut val = 0u32;
425 for (i, entry) in state.vectors[start..end].iter_mut().enumerate() {
426 if entry.check_is_pending(state.enabled) {
427 val |= 1 << i;
428 }
429 }
430 return val;
431 }
432 }
433 tracelimit::warn_ratelimited!(offset, "Unexpected read offset");
434 0
435 }
436
437 pub fn write_u32(&mut self, offset: u64, val: u32) {
439 let mut state = self.state.lock();
440 if offset < self.pending_bits_offset as u64 {
441 let index = offset / 16;
442 let global = state.enabled;
443 if let Some(entry) = state.vectors.get_mut(index as usize) {
444 let was_enabled = entry.is_enabled(global);
445 entry.write_u32(offset & 0xf, val);
446 let is_enabled = entry.is_enabled(global);
447 if is_enabled && !was_enabled {
448 entry.msi.enable(
450 entry.state.address,
451 entry.state.data,
452 entry.state.is_pending,
453 );
454 entry.state.is_pending = false;
455 } else if was_enabled && !is_enabled {
456 entry.msi.disable();
458 } else if is_enabled {
459 entry
462 .msi
463 .enable(entry.state.address, entry.state.data, false);
464 }
465 return;
466 }
467 } else if offset - (self.pending_bits_offset as u64)
468 < self.pending_bits_dword_count as u64 * 4
469 {
470 return;
471 }
472 tracelimit::warn_ratelimited!(offset, "Unexpected write offset");
473 }
474
475 pub fn interrupt(&self, index: u16) -> Option<Interrupt> {
478 Some(
479 self.state
480 .lock()
481 .vectors
482 .get_mut(index as usize)?
483 .msi
484 .interrupt(),
485 )
486 }
487
488 #[cfg(test)]
489 fn clear_pending_bit(&self, index: u8) {
490 let mut state = self.state.lock();
491 state.vectors[index as usize].state.is_pending = false;
492 }
493
494 pub fn set_pending_bit(&self, index: u16) {
500 let mut state = self.state.lock();
501 if let Some(entry) = state.vectors.get_mut(index as usize) {
502 entry.state.is_pending = true;
503 } else {
504 tracelimit::warn_ratelimited!(
505 index,
506 count = state.vectors.len(),
507 "set_pending_bit: vector index out of range"
508 );
509 }
510 }
511}
512
513mod save_restore {
514 use super::*;
515 use thiserror::Error;
516 use vmcore::save_restore::RestoreError;
517 use vmcore::save_restore::SaveError;
518 use vmcore::save_restore::SaveRestore;
519
520 mod state {
521 use mesh::payload::Protobuf;
522 use vmcore::save_restore::SavedStateRoot;
523
524 #[derive(Debug, Protobuf)]
525 #[mesh(package = "pci.caps.msix")]
526 pub struct SavedMsixMessageTableEntryState {
527 #[mesh(1)]
528 pub address: u64,
529 #[mesh(2)]
530 pub data: u32,
531 #[mesh(3)]
532 pub control: u32,
533 #[mesh(4)]
534 pub is_pending: bool,
535 }
536
537 #[derive(Debug, Protobuf, SavedStateRoot)]
538 #[mesh(package = "pci.caps.msix")]
539 pub struct SavedState {
540 #[mesh(2)]
541 pub enabled: bool,
542 #[mesh(3)]
543 pub vectors: Vec<SavedMsixMessageTableEntryState>,
544 }
545 }
546
547 #[derive(Debug, Error)]
548 enum MsixRestoreError {
549 #[error("mismatched vector lengths: current:{0}, saved:{1}")]
550 MismatchedTableLengths(usize, usize),
551 }
552
553 impl SaveRestore for MsixCapability {
554 type SavedState = state::SavedState;
555
556 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
557 let state = self.state.lock();
558 let saved_state = state::SavedState {
559 enabled: state.enabled,
560 vectors: {
561 state
562 .vectors
563 .iter()
564 .map(|vec| {
565 let EntryState {
566 address,
567 data,
568 control,
569 is_pending,
570 } = vec.state;
571
572 state::SavedMsixMessageTableEntryState {
573 address,
574 data,
575 control,
576 is_pending,
577 }
578 })
579 .collect()
580 },
581 };
582 Ok(saved_state)
583 }
584
585 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
586 let state::SavedState { enabled, vectors } = state;
587
588 let mut state = self.state.lock();
589 state.enabled = enabled;
590
591 if vectors.len() != state.vectors.len() {
592 return Err(RestoreError::InvalidSavedState(
593 MsixRestoreError::MismatchedTableLengths(vectors.len(), state.vectors.len())
594 .into(),
595 ));
596 }
597
598 for (new_vec, vec) in vectors.into_iter().zip(state.vectors.iter_mut()) {
599 vec.state = EntryState {
600 address: new_vec.address,
601 data: new_vec.data,
602 control: new_vec.control,
603 is_pending: new_vec.is_pending,
604 }
605 }
606
607 Ok(())
608 }
609 }
610}
611
612#[cfg(test)]
613mod tests {
614 use super::*;
615 use crate::msi::MsiConnection;
616 use crate::test_helpers::TestPciInterruptController;
617 use crate::test_helpers::read_cap_u32;
618 use crate::test_helpers::write_cap_u32;
619
620 #[test]
621 fn msix_check() {
622 let msi_conn = MsiConnection::new();
623 let (mut msix, mut cap) = MsixEmulator::new(2, 64, &msi_conn.target());
624 let msi_controller = TestPciInterruptController::new();
625 msi_conn.connect(msi_controller.signal_msi());
626 assert_eq!(read_cap_u32(&cap, 0), 0x3f0011);
628 assert_eq!(read_cap_u32(&cap, 4), 2);
629 assert_eq!(read_cap_u32(&cap, 8), 0x402);
630 write_cap_u32(&mut cap, 0, 0xffffffff);
631 assert_eq!(read_cap_u32(&cap, 0), 0x803f0011);
632 assert_eq!(msix.read_u32(0), 0);
635 assert_eq!(msix.read_u32(4), 0);
636 assert_eq!(msix.read_u32(8), 0);
637 assert_eq!(msix.read_u32(12), 1);
638 msix.write_u32(0, 0x12345678);
639 msix.write_u32(4, 0x9abcdef0);
640 msix.write_u32(8, 0x123);
641 msix.write_u32(12, 0x456);
642 assert_eq!(msix.read_u32(0), 0x12345678);
643 assert_eq!(msix.read_u32(4), 0x9abcdef0);
644 assert_eq!(msix.read_u32(8), 0x123);
645 assert_eq!(msix.read_u32(12), 0x456);
646 assert_eq!(msix.read_u32(0x3f0), 0);
648 assert_eq!(msix.read_u32(0x3f4), 0);
649 assert_eq!(msix.read_u32(0x3f8), 0);
650 assert_eq!(msix.read_u32(0x3fc), 1);
651 msix.write_u32(0x3f0, 0x12345678);
652 msix.write_u32(0x3f4, 0x9abcdef0);
653 msix.write_u32(0x3f8, 0x123);
654 msix.write_u32(0x3fc, 0x456);
655 assert_eq!(msix.read_u32(0x3f0), 0x12345678);
656 assert_eq!(msix.read_u32(0x3f4), 0x9abcdef0);
657 assert_eq!(msix.read_u32(0x3f8), 0x123);
658 assert_eq!(msix.read_u32(0x3fc), 0x456);
659 assert_eq!(msix.read_u32(0x400), 0);
661 assert_eq!(msix.read_u32(0x404), 0);
662 msix.set_pending_bit(1);
663 assert_eq!(msix.read_u32(0x400), 2);
664 assert_eq!(msix.read_u32(0x404), 0);
665 msix.set_pending_bit(33);
666 assert_eq!(msix.read_u32(0x400), 2);
667 assert_eq!(msix.read_u32(0x404), 2);
668 msix.set_pending_bit(63);
669 msix.set_pending_bit(31);
670 assert_eq!(msix.read_u32(0x400), 0x80000002);
671 assert_eq!(msix.read_u32(0x404), 0x80000002);
672 msix.clear_pending_bit(1);
673 assert_eq!(msix.read_u32(0x400), 0x80000000);
674 assert_eq!(msix.read_u32(0x404), 0x80000002);
675 }
676
677 use pal_event::Event;
678 use parking_lot::Mutex;
679
680 #[derive(Debug, Clone, PartialEq)]
682 enum RouteCall {
683 SetMsi { address: u64, data: u32 },
684 ClearMsi,
685 }
686
687 struct MockIrqFdRoute {
689 event: Event,
690 calls: Arc<Mutex<Vec<RouteCall>>>,
691 }
692
693 impl vmcore::irqfd::IrqFdRoute for MockIrqFdRoute {
694 fn event(&self) -> &Event {
695 &self.event
696 }
697
698 fn enable(&self, address: u64, data: u32, _devid: Option<u32>) {
699 self.calls.lock().push(RouteCall::SetMsi { address, data });
700 }
701
702 fn disable(&self) {
703 self.calls.lock().push(RouteCall::ClearMsi);
704 }
705 }
706
707 fn mock_irqfd(
709 count: usize,
710 ) -> (
711 Arc<dyn vmcore::irqfd::IrqFd>,
712 Vec<Arc<Mutex<Vec<RouteCall>>>>,
713 ) {
714 let mut call_logs = Vec::new();
715 let route_params = Arc::new(Mutex::new(Vec::new()));
716 for _ in 0..count {
717 let calls = Arc::new(Mutex::new(Vec::new()));
718 call_logs.push(calls.clone());
719 route_params.lock().push(calls);
720 }
721
722 struct MockIrqFd {
723 routes: Mutex<Vec<Arc<Mutex<Vec<RouteCall>>>>>,
724 }
725 impl vmcore::irqfd::IrqFd for MockIrqFd {
726 fn new_irqfd_route(&self) -> anyhow::Result<Box<dyn vmcore::irqfd::IrqFdRoute>> {
727 let calls = self.routes.lock().remove(0);
728 Ok(Box::new(MockIrqFdRoute {
729 event: Event::new(),
730 calls,
731 }))
732 }
733 }
734
735 (
736 Arc::new(MockIrqFd {
737 routes: Mutex::new(call_logs.clone()),
738 }),
739 call_logs,
740 )
741 }
742
743 #[test]
744 fn route_set_msi_on_unmask() {
745 let (irqfd, calls) = mock_irqfd(2);
746 let msi_conn = MsiConnection::new();
747 msi_conn.connect_irqfd(irqfd);
748 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
749 let msi_controller = TestPciInterruptController::new();
750 msi_conn.connect(msi_controller.signal_msi());
751
752 for i in 0..2 {
754 msix.interrupt(i).unwrap().event();
755 }
756
757 write_cap_u32(&mut cap, 0, 0x80000000);
759
760 msix.write_u32(0, 0xFEE00000); msix.write_u32(4, 0); msix.write_u32(8, 0x42); assert!(
767 !calls[0]
768 .lock()
769 .iter()
770 .any(|c| matches!(c, RouteCall::SetMsi { .. }))
771 );
772
773 calls[0].lock().clear();
775 msix.write_u32(12, 0);
776
777 let log = calls[0].lock().clone();
779 assert!(log.contains(&RouteCall::SetMsi {
780 address: 0xFEE00000,
781 data: 0x42
782 }));
783 }
784
785 #[test]
786 fn route_mask_on_vector_mask() {
787 let (irqfd, calls) = mock_irqfd(2);
788 let msi_conn = MsiConnection::new();
789 msi_conn.connect_irqfd(irqfd);
790 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
791 let msi_controller = TestPciInterruptController::new();
792 msi_conn.connect(msi_controller.signal_msi());
793
794 for i in 0..2 {
796 msix.interrupt(i).unwrap().event();
797 }
798
799 write_cap_u32(&mut cap, 0, 0x80000000);
801 msix.write_u32(0, 0xFEE00000);
802 msix.write_u32(8, 0x42);
803 msix.write_u32(12, 0); calls[0].lock().clear();
806
807 msix.write_u32(12, 1);
809
810 let log = calls[0].lock().clone();
811 assert!(log.contains(&RouteCall::ClearMsi));
812 }
813
814 #[test]
815 fn route_global_disable_masks_all() {
816 let (irqfd, calls) = mock_irqfd(2);
817 let msi_conn = MsiConnection::new();
818 msi_conn.connect_irqfd(irqfd);
819 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
820 let msi_controller = TestPciInterruptController::new();
821 msi_conn.connect(msi_controller.signal_msi());
822
823 for i in 0..2 {
825 msix.interrupt(i).unwrap().event();
826 }
827
828 write_cap_u32(&mut cap, 0, 0x80000000);
830 for v in 0..2u64 {
831 msix.write_u32(v * 16, 0xFEE00000);
832 msix.write_u32(v * 16 + 8, (v + 1) as u32);
833 msix.write_u32(v * 16 + 12, 0); }
835 calls[0].lock().clear();
836 calls[1].lock().clear();
837
838 write_cap_u32(&mut cap, 0, 0);
840
841 assert!(calls[0].lock().contains(&RouteCall::ClearMsi));
843 assert!(calls[1].lock().contains(&RouteCall::ClearMsi));
844 }
845
846 #[test]
847 fn route_consume_pending_on_pba_read() {
848 let (irqfd, _calls) = mock_irqfd(2);
849 let msi_conn = MsiConnection::new();
850 msi_conn.connect_irqfd(irqfd);
851 let (msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
852 let msi_controller = TestPciInterruptController::new();
853 msi_conn.connect(msi_controller.signal_msi());
854
855 let events: Vec<_> = (0..2)
857 .map(|i| msix.interrupt(i).unwrap().event().unwrap().clone())
858 .collect();
859
860 write_cap_u32(&mut cap, 0, 0x80000000);
862
863 events[0].signal();
865
866 let pba = msix.read_u32(32);
868
869 assert_eq!(pba & 1, 1);
871 }
872
873 #[test]
874 fn route_set_msi_on_addr_data_change_while_unmasked() {
875 let (irqfd, calls) = mock_irqfd(1);
876 let msi_conn = MsiConnection::new();
877 msi_conn.connect_irqfd(irqfd);
878 let (mut msix, mut cap) = MsixEmulator::new(2, 1, &msi_conn.target());
879 let msi_controller = TestPciInterruptController::new();
880 msi_conn.connect(msi_controller.signal_msi());
881
882 msix.interrupt(0).unwrap().event();
884
885 write_cap_u32(&mut cap, 0, 0x80000000);
887 msix.write_u32(0, 0xFEE00000);
888 msix.write_u32(8, 0x42);
889 msix.write_u32(12, 0);
890 calls[0].lock().clear();
891
892 msix.write_u32(8, 0x99);
894
895 let log = calls[0].lock().clone();
896 assert!(log.contains(&RouteCall::SetMsi {
897 address: 0xFEE00000,
898 data: 0x99
899 }));
900 }
901}