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}