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 #[inspect(hex)]
144 address: u64,
145 #[inspect(hex)]
146 data: u32,
147}
148
149impl Debug for MsiInterruptInner {
150 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151 f.debug_struct("MsiInterruptInner")
152 .field("pending", &self.pending)
153 .field("enabled", &self.enabled)
154 .field("address", &self.address)
155 .field("data", &self.data)
156 .field("has_route", &self.route.is_some())
157 .finish()
158 }
159}
160
161impl MsiInterruptInner {
162 fn signal_msi(&self) {
163 self.target.signal_msi(self.address, self.data);
164 }
165
166 fn enable_route(&self, route: &MsiRoute) {
167 route.enable(self.address, self.data);
168 }
169}
170
171impl MsiInterrupt {
172 pub fn new(target: MsiTarget) -> Self {
173 Self(Arc::new(Mutex::new(MsiInterruptInner {
174 target,
175 route: None,
176 pending: false,
177 enabled: false,
178 address: 0,
179 data: 0,
180 })))
181 }
182
183 pub fn enable(&self, address: u64, data: u32, set_pending: bool) {
184 let mut state = self.0.lock();
185 state.pending |= set_pending;
186 state.address = address;
187 state.data = data;
188 state.enabled = true;
189
190 if let Some(route) = &state.route {
192 state.enable_route(route);
193 }
194
195 if state.pending {
196 state.signal_msi();
197 state.pending = false;
198 }
199 }
200
201 pub fn disable(&self) {
202 let mut state = self.0.lock();
203 state.enabled = false;
204 if let Some(route) = &state.route {
205 route.disable();
206 }
207 }
208
209 pub fn drain_pending(&self) -> bool {
210 let mut state = self.0.lock();
211 if let Some(route) = &state.route {
212 state.pending |= route.consume_pending();
213 }
214 let was_pending = state.pending;
215 state.pending = false;
216 was_pending
217 }
218
219 pub fn interrupt(&self) -> Interrupt {
220 Interrupt::from_target(MsiInterruptTarget(self.0.clone()))
221 }
222}
223
224struct MsiInterruptTarget(Arc<Mutex<MsiInterruptInner>>);
227
228impl InterruptTarget for MsiInterruptTarget {
229 fn deliver(&self) {
230 let mut state = self.0.lock();
231 if state.enabled {
232 state.signal_msi();
233 } else {
234 state.pending = true;
235 }
236 }
237
238 fn event(&self) -> Option<Arc<Event>> {
239 let mut state = self.0.lock();
240 if let Some(route) = &state.route {
241 return Some(Arc::new(route.event().clone()));
242 }
243 let route = match state.target.new_route() {
244 Some(Ok(route)) => route,
245 Some(Err(e)) => {
246 tracelimit::warn_ratelimited!(error = ?e, "failed to allocate MSI route");
247 return None;
248 }
249 None => return None,
250 };
251 if state.enabled {
252 state.enable_route(&route);
253 } else {
254 route.disable();
255 }
256 let event = Arc::new(route.event().clone());
257 state.route = Some(route);
258 Some(event)
259 }
260}
261
262struct MsixMessageTableEntry {
263 msi: MsiInterrupt,
264 state: EntryState,
265}
266
267impl InspectMut for MsixMessageTableEntry {
268 fn inspect_mut(&mut self, req: inspect::Request<'_>) {
269 req.respond()
270 .hex("address", self.state.address)
271 .hex("data", self.state.data)
272 .hex("control", self.state.control)
273 .field("enabled", self.state.control & 1 == 0)
274 .field("is_pending", self.check_is_pending(true))
275 .field("msi", &self.msi);
278 }
279}
280
281#[derive(Debug)]
282struct EntryState {
283 address: u64,
284 data: u32,
285 control: u32,
286 is_pending: bool,
287}
288
289impl EntryState {
290 fn new() -> Self {
291 Self {
292 address: 0,
293 data: 0,
294 control: 1,
295 is_pending: false,
296 }
297 }
298}
299
300impl MsixMessageTableEntry {
301 fn new(msi: MsiInterrupt) -> Self {
302 Self {
303 msi,
304 state: EntryState::new(),
305 }
306 }
307
308 fn read_u32(&self, offset: u64) -> u32 {
309 match MsixTableEntryIdx(offset) {
310 MsixTableEntryIdx::MSG_ADDR_LO => self.state.address as u32,
311 MsixTableEntryIdx::MSG_ADDR_HI => (self.state.address >> 32) as u32,
312 MsixTableEntryIdx::MSG_DATA => self.state.data,
313 MsixTableEntryIdx::VECTOR_CTL => self.state.control,
314 _ => panic!("Unexpected read offset {}", offset),
315 }
316 }
317
318 fn write_u32(&mut self, offset: u64, val: u32) {
319 match MsixTableEntryIdx(offset) {
320 MsixTableEntryIdx::MSG_ADDR_LO => {
321 self.state.address = (self.state.address & 0xffffffff00000000) | val as u64
322 }
323 MsixTableEntryIdx::MSG_ADDR_HI => {
324 self.state.address = (val as u64) << 32 | self.state.address & 0xffffffff
325 }
326 MsixTableEntryIdx::MSG_DATA => self.state.data = val,
327 MsixTableEntryIdx::VECTOR_CTL => self.state.control = val,
328 _ => panic!("Unexpected write offset {}", offset),
329 }
330 }
331
332 fn is_enabled(&self, global_enabled: bool) -> bool {
333 global_enabled && self.state.control & 1 == 0
334 }
335
336 fn check_is_pending(&mut self, global_enabled: bool) -> bool {
337 if !self.state.is_pending && !self.is_enabled(global_enabled) {
338 self.state.is_pending = self.msi.drain_pending();
339 }
340 self.state.is_pending
341 }
342}
343
344#[derive(InspectMut)]
345struct MsixState {
346 enabled: bool,
347 #[inspect(mut, with = "inspect_entries")]
348 vectors: Vec<MsixMessageTableEntry>,
349}
350
351fn inspect_entries(entries: &mut [MsixMessageTableEntry]) -> impl '_ + InspectMut {
352 inspect::adhoc_mut(|req| {
353 let mut resp = req.respond();
354 for (i, entry) in entries.iter_mut().enumerate() {
355 resp.field_mut(&i.to_string(), entry);
356 }
357 })
358}
359
360#[derive(Clone)]
363pub struct MsixEmulator {
364 state: Arc<Mutex<MsixState>>,
365 pending_bits_offset: u32,
367 pending_bits_dword_count: u16,
368}
369
370impl MsixEmulator {
371 pub fn new(bar: u8, count: u16, msi_target: &MsiTarget) -> (Self, impl PciCapability + use<>) {
385 let state = MsixState {
386 enabled: false,
387 vectors: (0..count)
388 .map(|_| MsixMessageTableEntry::new(MsiInterrupt::new(msi_target.clone())))
389 .collect(),
390 };
391 let state = Arc::new(Mutex::new(state));
392 let pending_bits_offset = count as u32 * 16;
393 (
394 Self {
395 state: state.clone(),
396 pending_bits_offset,
397 pending_bits_dword_count: count.div_ceil(32),
398 },
399 MsixCapability {
400 count,
401 state,
402 config_table_location: MsiTableLocation::new(bar, 0),
403 pending_bits_location: MsiTableLocation::new(bar, pending_bits_offset),
404 },
405 )
406 }
407
408 pub fn bar_len(&self) -> u64 {
412 self.pending_bits_offset as u64 + self.pending_bits_dword_count as u64 * 4
413 }
414
415 pub fn read_u32(&self, offset: u64) -> u32 {
417 let mut state = self.state.lock();
418 let state: &mut MsixState = &mut state;
419 if offset < self.pending_bits_offset as u64 {
420 let index = offset / 16;
421 if let Some(entry) = state.vectors.get(index as usize) {
422 return entry.read_u32(offset & 0xf);
423 }
424 } else {
425 let dword = (offset - self.pending_bits_offset as u64) / 4;
426 let start = dword as usize * 32;
427 if start < state.vectors.len() {
428 let end = (start + 32).min(state.vectors.len());
429 let mut val = 0u32;
430 for (i, entry) in state.vectors[start..end].iter_mut().enumerate() {
431 if entry.check_is_pending(state.enabled) {
432 val |= 1 << i;
433 }
434 }
435 return val;
436 }
437 }
438 tracelimit::warn_ratelimited!(offset, "Unexpected read offset");
439 0
440 }
441
442 pub fn write_u32(&mut self, offset: u64, val: u32) {
444 let mut state = self.state.lock();
445 if offset < self.pending_bits_offset as u64 {
446 let index = offset / 16;
447 let global = state.enabled;
448 if let Some(entry) = state.vectors.get_mut(index as usize) {
449 let was_enabled = entry.is_enabled(global);
450 entry.write_u32(offset & 0xf, val);
451 let is_enabled = entry.is_enabled(global);
452 if is_enabled && !was_enabled {
453 entry.msi.enable(
455 entry.state.address,
456 entry.state.data,
457 entry.state.is_pending,
458 );
459 entry.state.is_pending = false;
460 } else if was_enabled && !is_enabled {
461 entry.msi.disable();
463 } else if is_enabled {
464 entry
467 .msi
468 .enable(entry.state.address, entry.state.data, false);
469 }
470 return;
471 }
472 } else if offset - (self.pending_bits_offset as u64)
473 < self.pending_bits_dword_count as u64 * 4
474 {
475 return;
476 }
477 tracelimit::warn_ratelimited!(offset, "Unexpected write offset");
478 }
479
480 pub fn interrupt(&self, index: u16) -> Option<Interrupt> {
483 Some(
484 self.state
485 .lock()
486 .vectors
487 .get_mut(index as usize)?
488 .msi
489 .interrupt(),
490 )
491 }
492
493 #[cfg(test)]
494 fn clear_pending_bit(&self, index: u8) {
495 let mut state = self.state.lock();
496 state.vectors[index as usize].state.is_pending = false;
497 }
498
499 pub fn set_pending_bit(&self, index: u16) {
505 let mut state = self.state.lock();
506 if let Some(entry) = state.vectors.get_mut(index as usize) {
507 entry.state.is_pending = true;
508 } else {
509 tracelimit::warn_ratelimited!(
510 index,
511 count = state.vectors.len(),
512 "set_pending_bit: vector index out of range"
513 );
514 }
515 }
516}
517
518mod save_restore {
519 use super::*;
520 use thiserror::Error;
521 use vmcore::save_restore::RestoreError;
522 use vmcore::save_restore::SaveError;
523 use vmcore::save_restore::SaveRestore;
524
525 mod state {
526 use mesh::payload::Protobuf;
527 use vmcore::save_restore::SavedStateRoot;
528
529 #[derive(Debug, Protobuf)]
530 #[mesh(package = "pci.caps.msix")]
531 pub struct SavedMsixMessageTableEntryState {
532 #[mesh(1)]
533 pub address: u64,
534 #[mesh(2)]
535 pub data: u32,
536 #[mesh(3)]
537 pub control: u32,
538 #[mesh(4)]
539 pub is_pending: bool,
540 }
541
542 #[derive(Debug, Protobuf, SavedStateRoot)]
543 #[mesh(package = "pci.caps.msix")]
544 pub struct SavedState {
545 #[mesh(2)]
546 pub enabled: bool,
547 #[mesh(3)]
548 pub vectors: Vec<SavedMsixMessageTableEntryState>,
549 }
550 }
551
552 #[derive(Debug, Error)]
553 enum MsixRestoreError {
554 #[error("mismatched vector lengths: current:{0}, saved:{1}")]
555 MismatchedTableLengths(usize, usize),
556 }
557
558 impl SaveRestore for MsixCapability {
559 type SavedState = state::SavedState;
560
561 fn save(&mut self) -> Result<Self::SavedState, SaveError> {
562 let state = self.state.lock();
563 let saved_state = state::SavedState {
564 enabled: state.enabled,
565 vectors: {
566 state
567 .vectors
568 .iter()
569 .map(|vec| {
570 let EntryState {
571 address,
572 data,
573 control,
574 is_pending,
575 } = vec.state;
576
577 state::SavedMsixMessageTableEntryState {
578 address,
579 data,
580 control,
581 is_pending,
582 }
583 })
584 .collect()
585 },
586 };
587 Ok(saved_state)
588 }
589
590 fn restore(&mut self, state: Self::SavedState) -> Result<(), RestoreError> {
591 let state::SavedState { enabled, vectors } = state;
592
593 let mut state = self.state.lock();
594 state.enabled = enabled;
595
596 if vectors.len() != state.vectors.len() {
597 return Err(RestoreError::InvalidSavedState(
598 MsixRestoreError::MismatchedTableLengths(vectors.len(), state.vectors.len())
599 .into(),
600 ));
601 }
602
603 for (new_vec, vec) in vectors.into_iter().zip(state.vectors.iter_mut()) {
604 vec.state = EntryState {
605 address: new_vec.address,
606 data: new_vec.data,
607 control: new_vec.control,
608 is_pending: new_vec.is_pending,
609 }
610 }
611
612 Ok(())
613 }
614 }
615}
616
617#[cfg(test)]
618mod tests {
619 use super::*;
620 use crate::msi::MsiConnection;
621 use crate::test_helpers::TestPciInterruptController;
622 use crate::test_helpers::read_cap_u32;
623 use crate::test_helpers::write_cap_u32;
624
625 #[test]
626 fn msix_check() {
627 let msi_conn = MsiConnection::new();
628 let (mut msix, mut cap) = MsixEmulator::new(2, 64, &msi_conn.target());
629 let msi_controller = TestPciInterruptController::new();
630 msi_conn.connect(msi_controller.signal_msi());
631 assert_eq!(read_cap_u32(&cap, 0), 0x3f0011);
633 assert_eq!(read_cap_u32(&cap, 4), 2);
634 assert_eq!(read_cap_u32(&cap, 8), 0x402);
635 write_cap_u32(&mut cap, 0, 0xffffffff);
636 assert_eq!(read_cap_u32(&cap, 0), 0x803f0011);
637 assert_eq!(msix.read_u32(0), 0);
640 assert_eq!(msix.read_u32(4), 0);
641 assert_eq!(msix.read_u32(8), 0);
642 assert_eq!(msix.read_u32(12), 1);
643 msix.write_u32(0, 0x12345678);
644 msix.write_u32(4, 0x9abcdef0);
645 msix.write_u32(8, 0x123);
646 msix.write_u32(12, 0x456);
647 assert_eq!(msix.read_u32(0), 0x12345678);
648 assert_eq!(msix.read_u32(4), 0x9abcdef0);
649 assert_eq!(msix.read_u32(8), 0x123);
650 assert_eq!(msix.read_u32(12), 0x456);
651 assert_eq!(msix.read_u32(0x3f0), 0);
653 assert_eq!(msix.read_u32(0x3f4), 0);
654 assert_eq!(msix.read_u32(0x3f8), 0);
655 assert_eq!(msix.read_u32(0x3fc), 1);
656 msix.write_u32(0x3f0, 0x12345678);
657 msix.write_u32(0x3f4, 0x9abcdef0);
658 msix.write_u32(0x3f8, 0x123);
659 msix.write_u32(0x3fc, 0x456);
660 assert_eq!(msix.read_u32(0x3f0), 0x12345678);
661 assert_eq!(msix.read_u32(0x3f4), 0x9abcdef0);
662 assert_eq!(msix.read_u32(0x3f8), 0x123);
663 assert_eq!(msix.read_u32(0x3fc), 0x456);
664 assert_eq!(msix.read_u32(0x400), 0);
666 assert_eq!(msix.read_u32(0x404), 0);
667 msix.set_pending_bit(1);
668 assert_eq!(msix.read_u32(0x400), 2);
669 assert_eq!(msix.read_u32(0x404), 0);
670 msix.set_pending_bit(33);
671 assert_eq!(msix.read_u32(0x400), 2);
672 assert_eq!(msix.read_u32(0x404), 2);
673 msix.set_pending_bit(63);
674 msix.set_pending_bit(31);
675 assert_eq!(msix.read_u32(0x400), 0x80000002);
676 assert_eq!(msix.read_u32(0x404), 0x80000002);
677 msix.clear_pending_bit(1);
678 assert_eq!(msix.read_u32(0x400), 0x80000000);
679 assert_eq!(msix.read_u32(0x404), 0x80000002);
680 }
681
682 use pal_event::Event;
683 use parking_lot::Mutex;
684
685 #[derive(Debug, Clone, PartialEq)]
687 enum RouteCall {
688 SetMsi { address: u64, data: u32 },
689 ClearMsi,
690 }
691
692 struct MockIrqFdRoute {
694 event: Event,
695 calls: Arc<Mutex<Vec<RouteCall>>>,
696 }
697
698 impl vmcore::irqfd::IrqFdRoute for MockIrqFdRoute {
699 fn event(&self) -> &Event {
700 &self.event
701 }
702
703 fn enable(&self, address: u64, data: u32, _devid: Option<u32>) {
704 self.calls.lock().push(RouteCall::SetMsi { address, data });
705 }
706
707 fn disable(&self) {
708 self.calls.lock().push(RouteCall::ClearMsi);
709 }
710 }
711
712 fn mock_irqfd(
714 count: usize,
715 ) -> (
716 Arc<dyn vmcore::irqfd::IrqFd>,
717 Vec<Arc<Mutex<Vec<RouteCall>>>>,
718 ) {
719 let mut call_logs = Vec::new();
720 let route_params = Arc::new(Mutex::new(Vec::new()));
721 for _ in 0..count {
722 let calls = Arc::new(Mutex::new(Vec::new()));
723 call_logs.push(calls.clone());
724 route_params.lock().push(calls);
725 }
726
727 struct MockIrqFd {
728 routes: Mutex<Vec<Arc<Mutex<Vec<RouteCall>>>>>,
729 }
730 impl vmcore::irqfd::IrqFd for MockIrqFd {
731 fn new_irqfd_route(&self) -> anyhow::Result<Box<dyn vmcore::irqfd::IrqFdRoute>> {
732 let calls = self.routes.lock().remove(0);
733 Ok(Box::new(MockIrqFdRoute {
734 event: Event::new(),
735 calls,
736 }))
737 }
738 }
739
740 (
741 Arc::new(MockIrqFd {
742 routes: Mutex::new(call_logs.clone()),
743 }),
744 call_logs,
745 )
746 }
747
748 #[test]
749 fn route_set_msi_on_unmask() {
750 let (irqfd, calls) = mock_irqfd(2);
751 let msi_conn = MsiConnection::new();
752 msi_conn.connect_irqfd(irqfd);
753 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
754 let msi_controller = TestPciInterruptController::new();
755 msi_conn.connect(msi_controller.signal_msi());
756
757 for i in 0..2 {
759 msix.interrupt(i).unwrap().event();
760 }
761
762 write_cap_u32(&mut cap, 0, 0x80000000);
764
765 msix.write_u32(0, 0xFEE00000); msix.write_u32(4, 0); msix.write_u32(8, 0x42); assert!(
772 !calls[0]
773 .lock()
774 .iter()
775 .any(|c| matches!(c, RouteCall::SetMsi { .. }))
776 );
777
778 calls[0].lock().clear();
780 msix.write_u32(12, 0);
781
782 let log = calls[0].lock().clone();
784 assert!(log.contains(&RouteCall::SetMsi {
785 address: 0xFEE00000,
786 data: 0x42
787 }));
788 }
789
790 #[test]
791 fn route_mask_on_vector_mask() {
792 let (irqfd, calls) = mock_irqfd(2);
793 let msi_conn = MsiConnection::new();
794 msi_conn.connect_irqfd(irqfd);
795 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
796 let msi_controller = TestPciInterruptController::new();
797 msi_conn.connect(msi_controller.signal_msi());
798
799 for i in 0..2 {
801 msix.interrupt(i).unwrap().event();
802 }
803
804 write_cap_u32(&mut cap, 0, 0x80000000);
806 msix.write_u32(0, 0xFEE00000);
807 msix.write_u32(8, 0x42);
808 msix.write_u32(12, 0); calls[0].lock().clear();
811
812 msix.write_u32(12, 1);
814
815 let log = calls[0].lock().clone();
816 assert!(log.contains(&RouteCall::ClearMsi));
817 }
818
819 #[test]
820 fn route_global_disable_masks_all() {
821 let (irqfd, calls) = mock_irqfd(2);
822 let msi_conn = MsiConnection::new();
823 msi_conn.connect_irqfd(irqfd);
824 let (mut msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
825 let msi_controller = TestPciInterruptController::new();
826 msi_conn.connect(msi_controller.signal_msi());
827
828 for i in 0..2 {
830 msix.interrupt(i).unwrap().event();
831 }
832
833 write_cap_u32(&mut cap, 0, 0x80000000);
835 for v in 0..2u64 {
836 msix.write_u32(v * 16, 0xFEE00000);
837 msix.write_u32(v * 16 + 8, (v + 1) as u32);
838 msix.write_u32(v * 16 + 12, 0); }
840 calls[0].lock().clear();
841 calls[1].lock().clear();
842
843 write_cap_u32(&mut cap, 0, 0);
845
846 assert!(calls[0].lock().contains(&RouteCall::ClearMsi));
848 assert!(calls[1].lock().contains(&RouteCall::ClearMsi));
849 }
850
851 #[test]
852 fn route_consume_pending_on_pba_read() {
853 let (irqfd, _calls) = mock_irqfd(2);
854 let msi_conn = MsiConnection::new();
855 msi_conn.connect_irqfd(irqfd);
856 let (msix, mut cap) = MsixEmulator::new(2, 2, &msi_conn.target());
857 let msi_controller = TestPciInterruptController::new();
858 msi_conn.connect(msi_controller.signal_msi());
859
860 let events: Vec<_> = (0..2)
862 .map(|i| msix.interrupt(i).unwrap().event().unwrap().clone())
863 .collect();
864
865 write_cap_u32(&mut cap, 0, 0x80000000);
867
868 events[0].signal();
870
871 let pba = msix.read_u32(32);
873
874 assert_eq!(pba & 1, 1);
876 }
877
878 #[test]
879 fn route_set_msi_on_addr_data_change_while_unmasked() {
880 let (irqfd, calls) = mock_irqfd(1);
881 let msi_conn = MsiConnection::new();
882 msi_conn.connect_irqfd(irqfd);
883 let (mut msix, mut cap) = MsixEmulator::new(2, 1, &msi_conn.target());
884 let msi_controller = TestPciInterruptController::new();
885 msi_conn.connect(msi_controller.signal_msi());
886
887 msix.interrupt(0).unwrap().event();
889
890 write_cap_u32(&mut cap, 0, 0x80000000);
892 msix.write_u32(0, 0xFEE00000);
893 msix.write_u32(8, 0x42);
894 msix.write_u32(12, 0);
895 calls[0].lock().clear();
896
897 msix.write_u32(8, 0x99);
899
900 let log = calls[0].lock().clone();
901 assert!(log.contains(&RouteCall::SetMsi {
902 address: 0xFEE00000,
903 data: 0x99
904 }));
905 }
906}