1#![no_std]
2
3extern crate alloc;
4
5use alloc::{boxed::Box, vec::Vec};
6use core::ops::{Deref, DerefMut};
7
8pub use irq_framework::{IrqAffinity, IrqError, IrqId};
9pub use rdif_base::DriverGeneric;
10
11#[repr(transparent)]
12#[derive(Clone, Copy, Debug, Eq, PartialEq)]
13pub struct MsiProviderId(pub u64);
14
15#[repr(transparent)]
16#[derive(Clone, Copy, Debug, Eq, PartialEq)]
17pub struct MsiDeviceId(pub u32);
18
19#[repr(transparent)]
20#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
21pub struct MsiEventId(pub u32);
22
23#[repr(transparent)]
24#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd)]
25pub struct MsiVectorIndex(pub u16);
26
27#[derive(Clone, Copy, Debug, Eq, PartialEq)]
28pub struct MsiMessage {
29 pub address: u64,
30 pub data: u32,
31}
32
33impl MsiMessage {
34 pub const fn new(address: u64, data: u32) -> Self {
35 Self { address, data }
36 }
37}
38
39#[derive(Clone, Copy, Debug, Eq, PartialEq)]
40pub struct MsiVector {
41 pub index: MsiVectorIndex,
42 pub event: MsiEventId,
43 pub irq: IrqId,
45 pub parent_irq: IrqId,
47}
48
49impl MsiVector {
50 pub const fn new(index: MsiVectorIndex, event: MsiEventId, irq: IrqId) -> Self {
51 Self {
52 index,
53 event,
54 irq,
55 parent_irq: irq,
56 }
57 }
58
59 pub const fn with_parent(
60 index: MsiVectorIndex,
61 event: MsiEventId,
62 irq: IrqId,
63 parent_irq: IrqId,
64 ) -> Self {
65 Self {
66 index,
67 event,
68 irq,
69 parent_irq,
70 }
71 }
72}
73
74#[derive(Clone, Debug, Eq, PartialEq)]
75pub struct MsiAllocation {
76 provider: MsiProviderId,
77 device: MsiDeviceId,
78 vectors: Box<[MsiVector]>,
79}
80
81impl MsiAllocation {
82 pub fn new(provider: MsiProviderId, device: MsiDeviceId, vectors: Box<[MsiVector]>) -> Self {
83 Self {
84 provider,
85 device,
86 vectors,
87 }
88 }
89
90 pub const fn provider(&self) -> MsiProviderId {
91 self.provider
92 }
93
94 pub const fn device(&self) -> MsiDeviceId {
95 self.device
96 }
97
98 pub fn vectors(&self) -> &[MsiVector] {
99 &self.vectors
100 }
101
102 pub fn into_vectors(self) -> Box<[MsiVector]> {
103 self.vectors
104 }
105}
106
107#[derive(Clone, Copy, Debug, Eq, PartialEq)]
108pub struct MsiRequest {
109 pub device: MsiDeviceId,
110 pub vector_count: u16,
111 pub affinity: IrqAffinity,
112}
113
114impl MsiRequest {
115 pub const fn new(device: MsiDeviceId, vector_count: u16) -> Self {
116 Self {
117 device,
118 vector_count,
119 affinity: IrqAffinity::Any,
120 }
121 }
122
123 pub const fn affinity(mut self, affinity: IrqAffinity) -> Self {
124 self.affinity = affinity;
125 self
126 }
127}
128
129pub trait Interface: DriverGeneric {
130 fn allocate_vectors(&mut self, request: &MsiRequest) -> Result<Vec<MsiVector>, IrqError>;
131
132 fn compose_message(&self, vector: &MsiVector) -> Result<MsiMessage, IrqError>;
133
134 fn set_vector_enabled(&mut self, _vector: &MsiVector, _enabled: bool) -> Result<(), IrqError> {
135 Err(IrqError::Unsupported)
136 }
137
138 fn set_vector_affinity(
139 &mut self,
140 _vector: &MsiVector,
141 _affinity: IrqAffinity,
142 ) -> Result<(), IrqError> {
143 Err(IrqError::Unsupported)
144 }
145
146 fn free_vectors(&mut self, allocation: MsiAllocation) -> Result<(), IrqError>;
147}
148
149pub struct Msi {
150 provider: MsiProviderId,
151 inner: Box<dyn Interface>,
152}
153
154impl Msi {
155 pub fn new<T: Interface>(provider: MsiProviderId, driver: T) -> Self {
156 Self {
157 provider,
158 inner: Box::new(driver),
159 }
160 }
161
162 pub const fn provider(&self) -> MsiProviderId {
163 self.provider
164 }
165
166 pub fn allocate(&mut self, request: MsiRequest) -> Result<MsiAllocation, IrqError> {
167 if request.vector_count == 0 {
168 return Err(IrqError::InvalidIrq);
169 }
170 let vectors = self.inner.allocate_vectors(&request)?;
171 if vectors.len() != usize::from(request.vector_count) {
172 return Err(IrqError::InvalidIrq);
173 }
174 Ok(MsiAllocation::new(
175 self.provider,
176 request.device,
177 vectors.into_boxed_slice(),
178 ))
179 }
180
181 pub fn compose_message(&self, vector: &MsiVector) -> Result<MsiMessage, IrqError> {
182 self.inner.compose_message(vector)
183 }
184
185 pub fn set_vector_enabled(
186 &mut self,
187 vector: &MsiVector,
188 enabled: bool,
189 ) -> Result<(), IrqError> {
190 self.inner.set_vector_enabled(vector, enabled)
191 }
192
193 pub fn set_vector_affinity(
194 &mut self,
195 vector: &MsiVector,
196 affinity: IrqAffinity,
197 ) -> Result<(), IrqError> {
198 self.inner.set_vector_affinity(vector, affinity)
199 }
200
201 pub fn free(&mut self, allocation: MsiAllocation) -> Result<(), IrqError> {
202 if allocation.provider != self.provider {
203 return Err(IrqError::InvalidIrq);
204 }
205 self.inner.free_vectors(allocation)
206 }
207
208 pub fn typed_ref<T: Interface>(&self) -> Option<&T> {
209 self.raw_any()?.downcast_ref()
210 }
211
212 pub fn typed_mut<T: Interface>(&mut self) -> Option<&mut T> {
213 self.raw_any_mut()?.downcast_mut()
214 }
215}
216
217impl DriverGeneric for Msi {
218 fn name(&self) -> &str {
219 self.inner.name()
220 }
221
222 fn raw_any(&self) -> Option<&dyn core::any::Any> {
223 Some(self.inner.as_ref() as &dyn core::any::Any)
224 }
225
226 fn raw_any_mut(&mut self) -> Option<&mut dyn core::any::Any> {
227 Some(self.inner.as_mut() as &mut dyn core::any::Any)
228 }
229}
230
231impl Deref for Msi {
232 type Target = dyn Interface;
233
234 fn deref(&self) -> &Self::Target {
235 self.inner.as_ref()
236 }
237}
238
239impl DerefMut for Msi {
240 fn deref_mut(&mut self) -> &mut Self::Target {
241 self.inner.as_mut()
242 }
243}
244
245#[cfg(test)]
246mod tests {
247 use alloc::{boxed::Box, vec::Vec};
248 use core::cell::RefCell;
249
250 extern crate alloc;
251
252 use irq_framework::{HwIrq, IrqDomainId, IrqError, IrqId};
253 use rdif_base::DriverGeneric;
254
255 use crate::{
256 Interface, Msi, MsiAllocation, MsiDeviceId, MsiEventId, MsiMessage, MsiProviderId,
257 MsiRequest, MsiVector, MsiVectorIndex,
258 };
259
260 struct MockProvider {
261 freed: RefCell<Vec<MsiAllocation>>,
262 }
263
264 impl DriverGeneric for MockProvider {
265 fn name(&self) -> &str {
266 "mock-msi"
267 }
268 }
269
270 impl Interface for MockProvider {
271 fn allocate_vectors(&mut self, request: &MsiRequest) -> Result<Vec<MsiVector>, IrqError> {
272 Ok((0..request.vector_count)
273 .map(|index| {
274 MsiVector::new(
275 MsiVectorIndex(index),
276 MsiEventId(32 + u32::from(index)),
277 IrqId::new(IrqDomainId(7), HwIrq(8192 + u32::from(index))),
278 )
279 })
280 .collect())
281 }
282
283 fn compose_message(&self, vector: &MsiVector) -> Result<MsiMessage, IrqError> {
284 Ok(MsiMessage::new(0x0808_0000, vector.event.0))
285 }
286
287 fn free_vectors(&mut self, allocation: MsiAllocation) -> Result<(), IrqError> {
288 self.freed.borrow_mut().push(allocation);
289 Ok(())
290 }
291 }
292
293 #[test]
294 fn allocation_records_provider_device_and_vectors() {
295 let provider = MsiProviderId(3);
296 let mut msi = Msi::new(
297 provider,
298 MockProvider {
299 freed: RefCell::new(Vec::new()),
300 },
301 );
302
303 let allocation = msi
304 .allocate(MsiRequest::new(MsiDeviceId(0x1234), 2))
305 .unwrap();
306
307 assert_eq!(allocation.provider(), provider);
308 assert_eq!(allocation.device(), MsiDeviceId(0x1234));
309 assert_eq!(allocation.vectors().len(), 2);
310 assert_eq!(allocation.vectors()[1].index, MsiVectorIndex(1));
311 assert_eq!(
312 allocation.vectors()[1].parent_irq,
313 allocation.vectors()[1].irq
314 );
315 assert_eq!(
316 msi.compose_message(&allocation.vectors()[1]).unwrap(),
317 MsiMessage::new(0x0808_0000, 33)
318 );
319 }
320
321 #[test]
322 fn vector_can_expose_leaf_irq_while_remembering_parent_irq() {
323 let parent_irq = IrqId::new(IrqDomainId(7), HwIrq(8192));
324 let leaf_irq = IrqId::new(IrqDomainId(8), HwIrq(0));
325
326 let vector = MsiVector::with_parent(MsiVectorIndex(0), MsiEventId(4), leaf_irq, parent_irq);
327
328 assert_eq!(vector.irq, leaf_irq);
329 assert_eq!(vector.parent_irq, parent_irq);
330 }
331
332 #[test]
333 fn freeing_allocation_rejects_wrong_provider() {
334 let mut msi = Msi::new(
335 MsiProviderId(7),
336 MockProvider {
337 freed: RefCell::new(Vec::new()),
338 },
339 );
340 let wrong = MsiAllocation::new(
341 MsiProviderId(8),
342 MsiDeviceId(1),
343 Box::new([MsiVector::new(
344 MsiVectorIndex(0),
345 MsiEventId(4),
346 IrqId::new(IrqDomainId(7), HwIrq(8192)),
347 )]),
348 );
349
350 assert_eq!(msi.free(wrong), Err(IrqError::InvalidIrq));
351 }
352}