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