1use crate::DOORBELL_STRIDE_BITS;
7use crate::spec;
8use guestmem::GuestMemory;
9use guestmem::GuestMemoryError;
10use inspect::Inspect;
11use parking_lot::RwLock;
12use std::sync::Arc;
13use std::sync::atomic::Ordering;
14use std::task::Context;
15use std::task::Poll;
16use std::task::Waker;
17use std::task::ready;
18use thiserror::Error;
19use vmcore::interrupt::Interrupt;
20
21pub struct DoorbellMemory {
22 mem: GuestMemory,
23 private_mem: GuestMemory,
24 offset: u64,
25 event_idx_offset: Option<u64>,
26 wakers: Vec<Option<Waker>>,
27}
28
29pub struct InvalidDoorbell;
30
31impl DoorbellMemory {
32 pub fn new(num_qids: u16) -> Self {
33 let private_mem = GuestMemory::allocate((num_qids as usize) << DOORBELL_STRIDE_BITS);
34 Self {
35 mem: private_mem.clone(),
36 private_mem,
37 offset: 0,
38 event_idx_offset: None,
39 wakers: (0..num_qids).map(|_| None).collect(),
40 }
41 }
42
43 pub fn reset(&mut self) {
44 let Self {
45 mem,
46 private_mem,
47 offset,
48 event_idx_offset,
49 wakers,
50 } = self;
51 private_mem
52 .fill_at(0, 0, wakers.len() << DOORBELL_STRIDE_BITS)
53 .expect("private doorbell memory must be writable");
54 *mem = private_mem.clone();
55 *offset = 0;
56 *event_idx_offset = None;
57 wakers.fill(None);
58 }
59
60 pub fn replace_mem(
63 &mut self,
64 mem: GuestMemory,
65 offset: u64,
66 event_idx_offset: Option<u64>,
67 ) -> Result<(), GuestMemoryError> {
68 let len = self.wakers.len() << DOORBELL_STRIDE_BITS;
70 let mut current = vec![0; len];
71 self.mem.read_at(self.offset, &mut current)?;
72 mem.write_at(offset, ¤t)?;
73 if let Some(event_idx_offset) = event_idx_offset {
74 mem.write_at(event_idx_offset, ¤t)?;
76 }
77 self.mem = mem;
78 self.offset = offset;
79 self.event_idx_offset = event_idx_offset;
80 Ok(())
81 }
82
83 pub fn try_write(&self, db_id: u16, value: u32) -> Result<(), InvalidDoorbell> {
84 if (db_id as usize) >= self.wakers.len() {
85 return Err(InvalidDoorbell);
86 }
87 self.write(db_id, value);
88 Ok(())
89 }
90
91 fn write(&self, db_id: u16, value: u32) {
92 assert!((db_id as usize) < self.wakers.len());
93 let addr = self
94 .offset
95 .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS);
96 if let Err(err) = self.mem.write_plain(addr, &value) {
97 tracelimit::error_ratelimited!(
98 error = &err as &dyn std::error::Error,
99 "failed to write doorbell memory"
100 );
101 }
102 if let Some(waker) = &self.wakers[db_id as usize] {
103 waker.wake_by_ref();
104 }
105 }
106
107 fn read(&self, db_id: u16) -> Option<u32> {
108 assert!((db_id as usize) < self.wakers.len());
109 self.mem
110 .read_plain(
111 self.offset
112 .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
113 )
114 .inspect_err(|err| {
115 tracelimit::error_ratelimited!(
116 error = err as &dyn std::error::Error,
117 "failed to read doorbell memory"
118 );
119 })
120 .ok()
121 }
122
123 fn has_event_idx(&self) -> bool {
124 self.event_idx_offset.is_some()
125 }
126
127 fn write_event_idx(&self, db_id: u16, val: u32) {
128 assert!((db_id as usize) < self.wakers.len());
129 if let Err(err) = self.mem.write_plain(
130 self.event_idx_offset
131 .unwrap()
132 .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
133 &val,
134 ) {
135 tracelimit::error_ratelimited!(
136 error = &err as &dyn std::error::Error,
137 "failed to read event_idx memory"
138 )
139 }
140 }
141
142 fn read_event_idx(&self, db_id: u16) -> Option<u32> {
143 assert!((db_id as usize) < self.wakers.len());
144 self.mem
145 .read_plain(
146 self.event_idx_offset?
147 .wrapping_add((db_id as u64) << DOORBELL_STRIDE_BITS),
148 )
149 .inspect_err(|err| {
150 tracelimit::error_ratelimited!(
151 error = err as &dyn std::error::Error,
152 "failed to read doorbell memory"
153 );
154 })
155 .ok()
156 }
157}
158
159#[derive(Inspect)]
160#[inspect(extra = "Self::inspect_shadow")]
161struct DoorbellState {
162 #[inspect(hex)]
163 current: u32,
164 #[inspect(hex)]
165 event_idx: u32,
166 db_id: u16,
167 db_offset: u64,
168 #[inspect(hex)]
169 len: u32,
170 #[inspect(skip)]
171 doorbells: Arc<RwLock<DoorbellMemory>>,
172 #[inspect(skip)]
173 registered_waker: Option<Waker>,
174}
175
176impl DoorbellState {
177 fn inspect_shadow(&self, resp: &mut inspect::Response<'_>) {
178 resp.field_with("doorbell", || {
179 self.doorbells.read().read(self.db_id).map(inspect::AsHex)
180 })
181 .field_with("shadow_event_idx", || {
182 self.doorbells
183 .read()
184 .read_event_idx(self.db_id)
185 .map(inspect::AsHex)
186 });
187 }
188
189 fn new(doorbells: Arc<RwLock<DoorbellMemory>>, db_id: u16, len: u32) -> Self {
190 Self {
191 current: 0,
192 event_idx: 0,
193 len,
194 doorbells,
195 registered_waker: None,
196 db_id,
197 db_offset: (db_id as u64) << DOORBELL_STRIDE_BITS,
198 }
199 }
200
201 fn probe_inner(&mut self, update_event_idx: bool) -> Option<u32> {
202 let doorbell = self.doorbells.read();
204 let val = doorbell.read(self.db_id)?;
205 if val != self.current {
206 return Some(val);
207 }
208
209 if self.event_idx == val || !update_event_idx || !doorbell.has_event_idx() {
210 return None;
211 }
212
213 doorbell.write_event_idx(self.db_id, val);
216 self.event_idx = val;
217
218 std::sync::atomic::fence(Ordering::SeqCst);
220 let val = doorbell.read(self.db_id)?;
221 if val != self.current { Some(val) } else { None }
222 }
223
224 fn probe(&mut self, update_event_idx: bool) -> Result<bool, QueueError> {
225 if let Some(val) = self.probe_inner(update_event_idx) {
228 if val >= self.len {
229 return Err(QueueError::InvalidDoorbell { val, len: self.len });
230 }
231 self.current = val;
232 Ok(true)
233 } else {
234 Ok(false)
235 }
236 }
237
238 fn poll(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), QueueError>> {
239 if self
241 .registered_waker
242 .as_ref()
243 .is_none_or(|w| !cx.waker().will_wake(w))
244 {
245 let _old_waker =
246 self.doorbells.write().wakers[self.db_id as usize].replace(cx.waker().clone());
247 self.registered_waker = Some(cx.waker().clone());
248 }
249 if !self.probe(true)? {
250 return Poll::Pending;
251 }
252 Poll::Ready(Ok(()))
253 }
254}
255
256#[derive(Inspect)]
257pub struct SubmissionQueue {
258 tail: DoorbellState,
259 mem: GuestMemory,
260 #[inspect(hex)]
261 head: u32,
262 #[inspect(hex)]
263 gpa: u64,
264}
265
266#[derive(Debug, Error)]
267pub enum QueueError {
268 #[error("invalid doorbell value {val:#x}, len {len:#x}")]
269 InvalidDoorbell { val: u32, len: u32 },
270 #[error("queue access error")]
271 Memory(#[source] GuestMemoryError),
272}
273
274impl SubmissionQueue {
275 pub fn new(cq: &CompletionQueue, db_id: u16, gpa: u64, len: u16) -> Self {
276 let doorbells = cq.head.doorbells.clone();
277 let mem = cq.mem.clone();
278 doorbells.read().write(db_id, 0);
279 Self {
280 tail: DoorbellState::new(doorbells, db_id, len.into()),
281 head: 0,
282 gpa,
283 mem,
284 }
285 }
286
287 pub fn poll_next(&mut self, cx: &mut Context<'_>) -> Poll<Result<spec::Command, QueueError>> {
290 let tail = self.tail.current;
291 if tail == self.head {
292 ready!(self.tail.poll(cx))?;
293 }
294 let command: spec::Command = self
295 .mem
296 .read_plain(
297 self.gpa
298 .wrapping_add(self.head as u64 * size_of::<spec::Command>() as u64),
299 )
300 .map_err(QueueError::Memory)?;
301
302 self.head = advance(self.head, self.tail.len);
303 Poll::Ready(Ok(command))
304 }
305
306 pub fn sqhd(&self) -> u16 {
307 self.head as u16
308 }
309}
310
311#[derive(Inspect)]
312pub struct CompletionQueue {
313 #[inspect(hex)]
314 tail: u32,
315 head: DoorbellState,
316 phase: bool,
317 #[inspect(hex)]
318 gpa: u64,
319 #[inspect(with = "Option::is_some")]
320 interrupt: Option<Interrupt>,
321 mem: GuestMemory,
322}
323
324impl CompletionQueue {
325 pub fn new(
326 doorbells: Arc<RwLock<DoorbellMemory>>,
327 db_id: u16,
328 mem: GuestMemory,
329 interrupt: Option<Interrupt>,
330 gpa: u64,
331 len: u16,
332 ) -> Self {
333 doorbells.read().write(db_id, 0);
334 Self {
335 tail: 0,
336 head: DoorbellState::new(doorbells, db_id, len.into()),
337 phase: true,
338 gpa,
339 interrupt,
340 mem,
341 }
342 }
343
344 pub fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), QueueError>> {
346 let next_tail = advance(self.tail, self.head.len);
347 if self.head.current == next_tail {
348 ready!(self.head.poll(cx))?;
349 }
350 Poll::Ready(Ok(()))
351 }
352
353 pub fn write(&mut self, mut data: spec::Completion) -> Result<bool, QueueError> {
354 let next = advance(self.tail, self.head.len);
355 if self.head.current == next && !self.head.probe(false)? {
358 return Ok(false);
359 }
360 data.status.set_phase(self.phase);
361
362 let [low, high]: [u64; 2] = zerocopy::transmute!(data);
368 let gpa = self
369 .gpa
370 .wrapping_add(self.tail as u64 * size_of::<spec::Completion>() as u64);
371 self.mem
372 .write_plain(gpa, &low)
373 .map_err(QueueError::Memory)?;
374 std::sync::atomic::fence(Ordering::Release);
375 self.mem
376 .write_plain(gpa + 8, &high)
377 .map_err(QueueError::Memory)?;
378 std::sync::atomic::fence(Ordering::Release);
379
380 if let Some(interrupt) = &self.interrupt {
381 interrupt.deliver();
382 }
383 self.tail = next;
384 if self.tail == 0 {
385 self.phase = !self.phase;
386 }
387 Ok(true)
388 }
389}
390
391fn advance(n: u32, l: u32) -> u32 {
392 if n + 1 < l { n + 1 } else { 0 }
393}