twizzler_driver/device/
events.rs

1//! Manage events for a device, including mailbox messages and interrupts.
2
3use 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
107/// A manager for device events, including interrupt handling.
108pub 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
115/// A handle for an allocated interrupt on a device.
116pub struct InterruptInfo {
117    es: Arc<DeviceEventStream>,
118    _vec: InterruptVector,
119    devint: u32,
120    inum: usize,
121}
122
123impl InterruptInfo {
124    /// Wait until the next interrupt occurs.
125    pub async fn next(&self) -> Option<u64> {
126        self.es.next(self.inum).await
127    }
128
129    /// Get the interrupt number for programming the device.
130    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        // TODO
144    }
145
146    /// Allocate a new interrupt on this device.
147    pub(crate) fn allocate_interrupt(self: &Arc<Self>) -> Result<InterruptInfo> {
148        // SAFETY: We grab ownership of the interrupt repr data via the atomic swap.
149        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}