1use super::spec;
7use crate::driver::save_restore::CompletionQueueSavedState;
8use crate::driver::save_restore::SubmissionQueueSavedState;
9use crate::registers::DeviceRegisters;
10use inspect::Inspect;
11use safeatomic::AtomicSliceOps;
12use std::sync::atomic::AtomicU64;
13use std::sync::atomic::Ordering::Acquire;
14use std::sync::atomic::Ordering::Relaxed;
15use user_driver::DeviceBacking;
16use user_driver::memory::MemoryBlock;
17
18#[derive(Inspect)]
19pub(crate) struct SubmissionQueue {
20 sqid: u16,
21 head: u32,
22 tail: u32,
23 committed_tail: u32,
24 len: u32,
25 #[inspect(skip)]
26 mem: MemoryBlock,
27}
28
29#[derive(Debug)]
30pub(crate) struct QueueFull;
31
32impl SubmissionQueue {
33 pub fn new(sqid: u16, len: u16, mem: MemoryBlock) -> Self {
34 tracing::debug!(sqid, len, pfns = ?mem.pfns(), "new submission queue");
35
36 Self {
37 sqid,
38 head: 0,
39 tail: 0,
40 committed_tail: 0,
41 len: len.into(),
42 mem,
43 }
44 }
45
46 pub fn id(&self) -> u16 {
47 self.sqid
48 }
49
50 pub fn update_head(&mut self, head: u16) {
51 let head = head as u32;
52 assert!(head < self.len);
53 self.head = head;
54 }
55
56 pub fn is_full(&self) -> bool {
57 advance(self.tail, self.len) == self.head
58 }
59
60 pub fn write(&mut self, command: spec::Command) -> Result<(), QueueFull> {
61 let next_tail = advance(self.tail, self.len);
62 if next_tail == self.head {
63 return Err(QueueFull);
64 }
65 self.mem
66 .write_obj(self.tail as usize * size_of_val(&command), &command);
67 self.tail = next_tail;
68 Ok(())
69 }
70
71 pub fn commit<T: DeviceBacking>(&mut self, region: &DeviceRegisters<T>) {
72 if self.tail != self.committed_tail {
73 safe_intrinsics::store_fence();
74 region.doorbell(self.sqid, false, self.tail);
75 self.committed_tail = self.tail;
76 }
77 }
78
79 pub fn save(&self) -> SubmissionQueueSavedState {
81 SubmissionQueueSavedState {
82 sqid: self.sqid,
83 head: self.head,
84 tail: self.tail,
85 committed_tail: self.committed_tail,
86 len: self.len,
87 }
88 }
89
90 pub fn restore(
92 mem: MemoryBlock,
93 saved_state: &SubmissionQueueSavedState,
94 ) -> anyhow::Result<Self> {
95 let SubmissionQueueSavedState {
96 sqid,
97 head,
98 tail,
99 committed_tail,
100 len,
101 } = saved_state;
102 Ok(Self {
103 sqid: *sqid,
104 head: *head,
105 tail: *tail,
106 committed_tail: *committed_tail,
107 len: *len,
108 mem,
109 })
110 }
111}
112
113#[derive(Inspect)]
114pub(crate) struct CompletionQueue {
115 cqid: u16,
116 head: u32,
117 committed_head: u32,
118 len: u32,
120 phase: bool,
121 #[inspect(skip)]
122 mem: MemoryBlock,
123}
124
125impl CompletionQueue {
126 pub fn new(cqid: u16, len: u16, mem: MemoryBlock) -> CompletionQueue {
127 tracing::debug!(cqid, len, pfns = ?mem.pfns(), "new completion queue");
128 Self {
129 cqid,
130 head: 0,
131 committed_head: 0,
132 len: len.into(),
133 phase: true,
134 mem,
135 }
136 }
137
138 pub fn _id(&self) -> u16 {
139 self.cqid
140 }
141
142 pub fn read(&mut self) -> Option<spec::Completion> {
143 let completion_mem = self.mem.as_slice()
144 [self.head as usize * size_of::<spec::Completion>()..][..size_of::<spec::Completion>()]
145 .as_atomic_slice::<AtomicU64>()
146 .unwrap();
147
148 let high = completion_mem[1].load(Acquire);
151 let status = spec::CompletionStatus::from((high >> 48) as u16);
152 if status.phase() != self.phase {
153 return None;
154 }
155 let low = completion_mem[0].load(Relaxed);
156 let completion: spec::Completion = zerocopy::transmute!([low, high]);
157 self.head += 1;
158 if self.head == self.len {
159 self.head = 0;
160 self.phase = !self.phase;
161 }
162 Some(completion)
163 }
164
165 pub fn commit<T: DeviceBacking>(&mut self, registers: &DeviceRegisters<T>) {
166 if self.head != self.committed_head {
167 safe_intrinsics::store_fence();
168 registers.doorbell(self.cqid, true, self.head);
169 self.committed_head = self.head;
170 }
171 }
172
173 pub fn save(&self) -> CompletionQueueSavedState {
175 CompletionQueueSavedState {
176 cqid: self.cqid,
177 head: self.head,
178 committed_head: self.committed_head,
179 len: self.len,
180 phase: self.phase,
181 }
182 }
183
184 pub fn restore(
186 mem: MemoryBlock,
187 saved_state: &CompletionQueueSavedState,
188 ) -> anyhow::Result<Self> {
189 let CompletionQueueSavedState {
190 cqid,
191 head,
192 committed_head,
193 len,
194 phase,
195 } = saved_state;
196
197 Ok(Self {
198 cqid: *cqid,
199 head: *head,
200 committed_head: *committed_head,
201 len: *len,
202 phase: *phase,
203 mem,
204 })
205 }
206}
207
208fn advance(n: u32, l: u32) -> u32 {
209 if n + 1 < l { n + 1 } else { 0 }
210}