twizzler_driver/device/
events.rs1use std::{
4 collections::VecDeque,
5 io::ErrorKind,
6 pin::Pin,
7 sync::{atomic::Ordering, Arc, Mutex},
8};
9
10use async_io::Async;
11use futures::future::select_all;
12use twizzler_abi::{
13 device::{
14 BusType, DeviceInterruptFlags, DeviceRepr, InterruptVector, MailboxPriority,
15 NUM_DEVICE_INTERRUPTS,
16 },
17 syscall::{ThreadSyncFlags, ThreadSyncReference, ThreadSyncSleep},
18};
19use twizzler_futures::TwizzlerWaitable;
20use twizzler_rt_abi::{
21 error::{ResourceError, TwzError},
22 Result,
23};
24
25use super::Device;
26
27struct DeviceEventStreamInner {
28 msg_queue: Vec<VecDeque<u64>>,
29}
30
31impl DeviceEventStreamInner {
32 fn new() -> Self {
33 Self {
34 msg_queue: (0..(MailboxPriority::Num as usize))
35 .into_iter()
36 .map(|_| VecDeque::new())
37 .collect(),
38 }
39 }
40}
41
42struct IntInner {
43 inum: usize,
44 repr: Arc<Device>,
45}
46
47impl IntInner {
48 fn repr(&self) -> &DeviceRepr {
49 self.repr.repr()
50 }
51
52 fn new(repr: Arc<Device>, inum: usize) -> Self {
53 Self { inum, repr }
54 }
55}
56
57impl TwizzlerWaitable for IntInner {
58 fn wait_item_read(&self) -> twizzler_abi::syscall::ThreadSyncSleep {
59 let repr = self.repr();
60 repr.setup_interrupt_sleep(self.inum)
61 }
62
63 fn wait_item_write(&self) -> twizzler_abi::syscall::ThreadSyncSleep {
64 let repr = self.repr();
65 repr.setup_interrupt_sleep(self.inum)
66 }
67}
68
69struct MailboxInner {
70 repr: Arc<Device>,
71 inum: usize,
72}
73
74impl Unpin for MailboxInner {}
75impl Unpin for IntInner {}
76
77impl MailboxInner {
78 fn repr(&self) -> &DeviceRepr {
79 self.repr.repr()
80 }
81
82 fn new(repr: Arc<Device>, inum: usize) -> Self {
83 Self { inum, repr }
84 }
85}
86
87impl TwizzlerWaitable for MailboxInner {
88 fn wait_item_read(&self) -> twizzler_abi::syscall::ThreadSyncSleep {
89 ThreadSyncSleep::new(
90 ThreadSyncReference::Virtual(&self.repr().mailboxes[self.inum]),
91 0,
92 twizzler_abi::syscall::ThreadSyncOp::Equal,
93 ThreadSyncFlags::empty(),
94 )
95 }
96
97 fn wait_item_write(&self) -> twizzler_abi::syscall::ThreadSyncSleep {
98 ThreadSyncSleep::new(
99 ThreadSyncReference::Virtual(&self.repr().mailboxes[self.inum]),
100 0,
101 twizzler_abi::syscall::ThreadSyncOp::Equal,
102 ThreadSyncFlags::empty(),
103 )
104 }
105}
106
107pub struct DeviceEventStream {
109 inner: Mutex<DeviceEventStreamInner>,
110 asyncs: Vec<Async<Pin<Box<IntInner>>>>,
111 async_mb: Vec<Async<Pin<Box<MailboxInner>>>>,
112 device: Arc<Device>,
113}
114
115pub struct InterruptInfo {
117 es: Arc<DeviceEventStream>,
118 _vec: InterruptVector,
119 devint: u32,
120 inum: usize,
121}
122
123impl InterruptInfo {
124 pub async fn next(&self) -> Option<u64> {
126 self.es.next(self.inum).await
127 }
128
129 pub fn devint(&self) -> u32 {
131 self.devint
132 }
133}
134
135impl Drop for InterruptInfo {
136 fn drop(&mut self) {
137 self.es.free_interrupt(self)
138 }
139}
140
141impl DeviceEventStream {
142 pub(crate) fn free_interrupt(&self, _ii: &InterruptInfo) {
143 }
145
146 pub(crate) fn allocate_interrupt(self: &Arc<Self>) -> Result<InterruptInfo> {
148 for i in 0..NUM_DEVICE_INTERRUPTS {
150 if self.device.repr().interrupts[i]
151 .taken
152 .swap(1, std::sync::atomic::Ordering::SeqCst)
153 == 0
154 {
155 let (vec, devint) = match self.device.bus_type() {
156 BusType::Pcie => self.device.allocate_interrupt(i)?,
157 _ => return Err(TwzError::NOT_SUPPORTED),
158 };
159 self.device
160 .repr_mut()
161 .register_interrupt(i, vec, DeviceInterruptFlags::empty());
162 return Ok(InterruptInfo {
163 es: self.clone(),
164 _vec: vec,
165 devint,
166 inum: i,
167 });
168 }
169 }
170 Err(TwzError::Resource(ResourceError::OutOfResources))
171 }
172
173 pub(crate) fn new(device: Arc<Device>) -> Self {
174 let asyncs = (0..NUM_DEVICE_INTERRUPTS)
175 .into_iter()
176 .map(|i| Async::new(IntInner::new(device.clone(), i)).unwrap())
177 .collect();
178 let async_mb = (0..(MailboxPriority::Num as usize))
179 .into_iter()
180 .map(|i| Async::new(MailboxInner::new(device.clone(), i)).unwrap())
181 .collect();
182 Self {
183 inner: Mutex::new(DeviceEventStreamInner::new()),
184 asyncs,
185 async_mb,
186 device,
187 }
188 }
189
190 fn repr(&self) -> &DeviceRepr {
191 self.device.repr()
192 }
193
194 pub(crate) fn check_mailbox(&self, pri: MailboxPriority) -> Option<u64> {
195 let mut inner = self.inner.lock().unwrap();
196 inner.msg_queue[pri as usize].pop_front()
197 }
198
199 fn future_of_int(
200 &self,
201 inum: usize,
202 ) -> impl std::future::Future<Output = std::io::Result<(usize, u64)>> + '_ {
203 Box::pin(self.asyncs[inum].read_with(move |ii| {
204 ii.repr()
205 .check_for_interrupt(ii.inum)
206 .ok_or(ErrorKind::WouldBlock.into())
207 .map(|x| (inum, x))
208 }))
209 }
210
211 fn future_of_mb(
212 &self,
213 inum: usize,
214 ) -> impl std::future::Future<Output = std::io::Result<(usize, u64)>> + '_ {
215 Box::pin(self.async_mb[inum].read_with(move |ii| {
216 ii.repr()
217 .check_for_mailbox(ii.inum)
218 .ok_or(ErrorKind::WouldBlock.into())
219 .map(|x| (inum, x))
220 }))
221 }
222
223 fn check_add_msg(&self, i: usize) {
224 if let Some(x) = self.repr().check_for_mailbox(i) {
225 self.inner.lock().unwrap().msg_queue[i].push_back(x)
226 }
227 }
228
229 pub(crate) async fn next(&self, int: usize) -> Option<u64> {
230 if self.repr().interrupts[int].taken.load(Ordering::SeqCst) == 0 {
231 return None;
232 }
233 if let Some(x) = self.repr().check_for_interrupt(int) {
234 return Some(x);
235 }
236
237 let fut = self.future_of_int(int);
238 fut.await.ok().map(|x| x.1)
239 }
240
241 pub(crate) async fn next_msg(&self, min: MailboxPriority) -> (MailboxPriority, u64) {
242 loop {
243 for i in 0..(MailboxPriority::Num as usize) {
244 self.check_add_msg(i);
245 }
246
247 for i in ((min as usize)..(MailboxPriority::Num as usize)).rev() {
248 if let Some(x) = self.check_mailbox(i.try_into().unwrap()) {
249 return (i.try_into().unwrap(), x);
250 }
251 }
252
253 let futs = ((min as usize)..(MailboxPriority::Num as usize))
254 .into_iter()
255 .map(|i| self.future_of_mb(i));
256
257 let (pri, x) = select_all(futs).await.0.unwrap();
258 self.inner.lock().unwrap().msg_queue[pri].push_back(x);
259 }
260 }
261}