1use alloc::vec::Vec;
2
3use crate::RequestId;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
6pub struct IrqSourceInfo {
7 pub id: usize,
8 pub queues: IdList,
9}
10
11impl IrqSourceInfo {
12 pub const fn new(id: usize, queues: IdList) -> Self {
13 Self { id, queues }
14 }
15
16 pub const fn legacy(queues: IdList) -> Self {
17 Self { id: 0, queues }
18 }
19}
20
21pub type IrqSourceList = Vec<IrqSourceInfo>;
22
23pub trait IrqHandler: Send + 'static {
24 fn handle_irq(&mut self) -> Event;
37}
38
39#[repr(transparent)]
40#[derive(Debug, Clone, Copy, PartialEq, Eq)]
41pub struct IdList(u64);
42
43impl IdList {
44 pub const fn none() -> Self {
45 Self(0)
46 }
47
48 pub const fn from_bits(bits: u64) -> Self {
49 Self(bits)
50 }
51
52 pub const fn bits(self) -> u64 {
53 self.0
54 }
55
56 pub fn contains(&self, id: usize) -> bool {
57 id < 64 && (self.0 & (1 << id)) != 0
58 }
59
60 pub fn insert(&mut self, id: usize) {
61 if id < 64 {
62 self.0 |= 1 << id;
63 }
64 }
65
66 pub fn remove(&mut self, id: usize) {
67 if id < 64 {
68 self.0 &= !(1 << id);
69 }
70 }
71
72 pub fn iter(&self) -> impl Iterator<Item = usize> {
73 (0..64).filter(move |i| self.contains(*i))
74 }
75}
76
77pub const MAX_COMPLETION_HINTS: usize = 8;
78pub const MAX_BATCH_COMPLETION_IDS: usize = 16;
79
80#[derive(Debug, Clone, Copy)]
81pub enum CompletionHint {
82 Queue {
83 queue_id: usize,
84 },
85 Request {
86 queue_id: usize,
87 request_id: RequestId,
88 },
89 Batch {
90 queue_id: usize,
91 ids: CompletionIds,
92 },
93}
94
95impl CompletionHint {
96 pub const fn queue_id(self) -> usize {
97 match self {
98 Self::Queue { queue_id }
99 | Self::Request { queue_id, .. }
100 | Self::Batch { queue_id, .. } => queue_id,
101 }
102 }
103}
104
105#[derive(Debug, Clone, Copy)]
106pub struct CompletionIds {
107 len: usize,
108 ids: [RequestId; MAX_BATCH_COMPLETION_IDS],
109}
110
111impl CompletionIds {
112 pub const fn new() -> Self {
113 Self {
114 len: 0,
115 ids: [RequestId::new(0); MAX_BATCH_COMPLETION_IDS],
116 }
117 }
118
119 pub fn push(&mut self, request_id: RequestId) -> bool {
120 if self.len == self.ids.len() {
121 return false;
122 }
123 self.ids[self.len] = request_id;
124 self.len += 1;
125 true
126 }
127
128 pub const fn len(&self) -> usize {
129 self.len
130 }
131
132 pub const fn is_empty(&self) -> bool {
133 self.len == 0
134 }
135
136 pub fn iter(&self) -> impl Iterator<Item = RequestId> + '_ {
137 self.ids[..self.len].iter().copied()
138 }
139}
140
141impl Default for CompletionIds {
142 fn default() -> Self {
143 Self::new()
144 }
145}
146
147#[derive(Debug, Clone, Copy)]
148pub struct CompletionList {
149 len: usize,
150 hints: [Option<CompletionHint>; MAX_COMPLETION_HINTS],
151}
152
153impl CompletionList {
154 pub const fn new() -> Self {
155 Self {
156 len: 0,
157 hints: [None; MAX_COMPLETION_HINTS],
158 }
159 }
160
161 pub fn push(&mut self, hint: CompletionHint) -> bool {
162 if self.len == self.hints.len() {
163 return false;
164 }
165 self.hints[self.len] = Some(hint);
166 self.len += 1;
167 true
168 }
169
170 pub const fn len(&self) -> usize {
171 self.len
172 }
173
174 pub const fn is_empty(&self) -> bool {
175 self.len == 0
176 }
177
178 pub fn iter(&self) -> impl Iterator<Item = CompletionHint> + '_ {
179 self.hints[..self.len]
180 .iter()
181 .filter_map(|hint| hint.as_ref().copied())
182 }
183}
184
185impl Default for CompletionList {
186 fn default() -> Self {
187 Self::new()
188 }
189}
190
191#[derive(Debug, Clone, Copy)]
192pub struct Event {
193 pub queues: IdList,
194 pub completions: CompletionList,
195}
196
197impl Event {
198 pub const fn none() -> Self {
199 Self {
200 queues: IdList::none(),
201 completions: CompletionList::new(),
202 }
203 }
204
205 pub const fn from_queue_bits(bits: u64) -> Self {
206 Self {
207 queues: IdList::from_bits(bits),
208 completions: CompletionList::new(),
209 }
210 }
211
212 pub fn from_hint(hint: CompletionHint) -> Self {
213 let mut event = Self::none();
214 event.push_hint(hint);
215 event
216 }
217
218 pub fn push_queue(&mut self, queue_id: usize) {
219 self.queues.insert(queue_id);
220 let _ = self.completions.push(CompletionHint::Queue { queue_id });
221 }
222
223 pub fn push_request(&mut self, queue_id: usize, request_id: RequestId) {
224 if !self.completions.push(CompletionHint::Request {
225 queue_id,
226 request_id,
227 }) {
228 self.queues.insert(queue_id);
229 }
230 }
231
232 pub fn push_hint(&mut self, hint: CompletionHint) {
233 if let CompletionHint::Queue { queue_id } = hint {
234 self.queues.insert(queue_id);
235 }
236 if !self.completions.push(hint) {
237 self.queues.insert(hint.queue_id());
238 }
239 }
240
241 pub fn is_empty(&self) -> bool {
242 self.queues.bits() == 0 && self.completions.is_empty()
243 }
244}
245
246#[cfg(test)]
247mod tests {
248 use super::*;
249
250 #[test]
251 fn irq_source_lists_queue_masks() {
252 let mut queues = IdList::none();
253 queues.insert(2);
254 let source = IrqSourceInfo::legacy(queues);
255
256 assert_eq!(source.id, 0);
257 assert!(source.queues.contains(2));
258 }
259
260 #[test]
261 fn completion_hints_preserve_queue_level_compatibility() {
262 let mut event = Event::none();
263 event.push_queue(3);
264 event.push_request(3, RequestId::new(7));
265
266 assert!(event.queues.contains(3));
267 assert_eq!(event.completions.len(), 2);
268 }
269
270 #[test]
271 fn completion_hint_overflow_falls_back_to_queue_bit() {
272 let mut event = Event::none();
273 for id in 0..(MAX_COMPLETION_HINTS + 1) {
274 event.push_request(5, RequestId::new(id));
275 }
276
277 assert_eq!(event.completions.len(), MAX_COMPLETION_HINTS);
278 assert!(event.queues.contains(5));
279 }
280
281 #[test]
282 fn queue_event_represents_driver_local_completion_ready() {
283 let event = Event::from_hint(CompletionHint::Queue { queue_id: 2 });
284
285 assert!(event.queues.contains(2));
286 assert_eq!(event.completions.len(), 1);
287 }
288}