1use crate::KvmPartitionInner;
7use pal_event::Event;
8use parking_lot::Mutex;
9use std::os::unix::prelude::*;
10use std::sync::Arc;
11use std::sync::Weak;
12use std::sync::atomic::AtomicBool;
13use std::sync::atomic::Ordering;
14
15const NUM_GSIS: usize = 2048;
16
17#[derive(Debug)]
19pub struct GsiRouting {
20 states: Box<[GsiState; NUM_GSIS]>,
21}
22
23impl GsiRouting {
24 pub fn new() -> Self {
26 Self {
27 states: Box::new([GsiState::Unallocated; NUM_GSIS]),
28 }
29 }
30
31 pub fn claim(&mut self, gsi: u32) {
33 let gsi = gsi as usize;
34 assert_eq!(self.states[gsi], GsiState::Unallocated);
35 self.states[gsi] = GsiState::Disabled;
36 }
37
38 pub fn alloc(&mut self) -> Option<u32> {
40 let gsi = self.states.iter().position(|state| !state.is_allocated())?;
41 self.states[gsi] = GsiState::Disabled;
42 Some(gsi as u32)
43 }
44
45 pub fn free(&mut self, gsi: u32) {
47 let gsi = gsi as usize;
48 assert_eq!(self.states[gsi], GsiState::Disabled);
49 self.states[gsi] = GsiState::Unallocated;
50 }
51
52 pub fn set(&mut self, gsi: u32, entry: Option<kvm::RoutingEntry>) -> bool {
54 let new_state = entry.map_or(GsiState::Disabled, GsiState::Enabled);
55 let state = &mut self.states[gsi as usize];
56 assert!(state.is_allocated());
57 if *state != new_state {
58 *state = new_state;
59 true
60 } else {
61 false
62 }
63 }
64
65 pub fn update_routes(&mut self, kvm: &kvm::Partition) {
67 let routing: Vec<_> = self
68 .states
69 .iter()
70 .enumerate()
71 .filter_map(|(gsi, state)| match state {
72 GsiState::Unallocated | GsiState::Disabled => None,
73 GsiState::Enabled(entry) => Some((gsi as u32, *entry)),
74 })
75 .collect();
76
77 kvm.set_gsi_routes(&routing).expect("should not fail");
78 }
79}
80
81impl KvmPartitionInner {
82 pub(crate) fn new_route(self: &Arc<Self>, irqfd_event: Option<Event>) -> Option<GsiRoute> {
84 let gsi = self.gsi_routing.lock().alloc()?;
85 Some(GsiRoute {
86 partition: Arc::downgrade(self),
87 gsi,
88 irqfd_event,
89 enabled: false.into(),
90 enable_mutex: Mutex::new(()),
91 })
92 }
93}
94
95#[derive(Debug, Copy, Clone, PartialEq, Eq)]
96enum GsiState {
97 Unallocated,
98 Disabled,
99 Enabled(kvm::RoutingEntry),
100}
101
102impl GsiState {
103 fn is_allocated(&self) -> bool {
104 !matches!(self, GsiState::Unallocated)
105 }
106}
107
108#[derive(Debug)]
110pub struct GsiRoute {
111 partition: Weak<KvmPartitionInner>,
112 gsi: u32,
113 irqfd_event: Option<Event>,
114 enabled: AtomicBool,
115 enable_mutex: Mutex<()>, }
117
118impl Drop for GsiRoute {
119 fn drop(&mut self) {
120 self.disable();
121 self.set_entry(None);
122 if let Some(partition) = self.partition.upgrade() {
123 partition.gsi_routing.lock().free(self.gsi);
124 }
125 }
126}
127
128impl GsiRoute {
129 fn set_entry(&self, new_entry: Option<kvm::RoutingEntry>) -> Option<Arc<KvmPartitionInner>> {
130 let partition = self.partition.upgrade();
131 if let Some(partition) = &partition {
132 let mut routing = partition.gsi_routing.lock();
133 if routing.set(self.gsi, new_entry) {
134 routing.update_routes(&partition.kvm);
135 }
136 }
137 partition
138 }
139
140 pub fn enable(&self, entry: kvm::RoutingEntry) {
142 let partition = self.set_entry(Some(entry));
143 let _lock = self.enable_mutex.lock();
144 if !self.enabled.load(Ordering::Relaxed) {
145 if let (Some(partition), Some(event)) = (&partition, &self.irqfd_event) {
146 partition
147 .kvm
148 .irqfd(self.gsi, event.as_fd().as_raw_fd(), true)
149 .expect("should not fail");
150 }
151 self.enabled.store(true, Ordering::Relaxed);
152 }
153 }
154
155 pub fn disable(&self) {
160 let _lock = self.enable_mutex.lock();
161 if self.enabled.load(Ordering::Relaxed) {
162 if let Some(irqfd_event) = &self.irqfd_event {
163 if let Some(partition) = self.partition.upgrade() {
164 partition
165 .kvm
166 .irqfd(self.gsi, irqfd_event.as_fd().as_raw_fd(), false)
167 .expect("should not fail");
168 }
169 }
170 self.enabled.store(false, Ordering::Relaxed);
171 }
172 }
173
174 pub fn irqfd_event(&self) -> Option<&Event> {
176 self.irqfd_event.as_ref()
177 }
178
179 pub fn _signal(&self) {
181 if self.enabled.load(Ordering::Relaxed) {
185 if let Some(event) = &self.irqfd_event {
186 event.signal();
187 } else if let Some(partition) = self.partition.upgrade() {
188 assert!(cfg!(target_arch = "x86_64"));
194 partition
195 .kvm
196 .irq_line(self.gsi, true)
197 .expect("interrupt delivery failure");
198 }
199 }
200 }
201}