Skip to main content

rdif_msi/
lib.rs

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    /// IRQ registered by the device driver.
44    pub irq: IrqId,
45    /// IRQ owned by the parent MSI interrupt controller.
46    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}