1use crate::queue::QueueDescriptor;
7use crate::queue::QueueError;
8use crate::queue::QueueParams;
9use crate::queue::descriptor_offset;
10use crate::spec::VirtioDeviceFeatures;
11use crate::spec::queue as spec;
12use crate::spec::queue::DescriptorFlags;
13use guestmem::GuestMemory;
14use inspect::Inspect;
15use spec::EventSuppressionFlags;
16use spec::PackedDescriptor;
17use spec::PackedEventSuppression;
18use std::sync::atomic;
19
20pub struct PackedQueueCompletionContext {
21 buffer_id: u16,
22 descriptor_count: u16,
23}
24
25impl PackedQueueCompletionContext {
26 pub(super) fn new(last_descriptor: &QueueDescriptor, descriptor_count: u16) -> Self {
27 Self {
28 buffer_id: last_descriptor
29 .buffer_id
30 .expect("packed descriptors have buffer id"),
31 descriptor_count,
32 }
33 }
34
35 pub(super) fn descriptor_count(&self) -> u16 {
36 self.descriptor_count
37 }
38}
39
40#[derive(Debug, Inspect)]
41#[inspect(extra = "Self::inspect_extra")]
42pub(crate) struct PackedQueueGetWork {
43 #[inspect(skip)]
44 queue_desc: GuestMemory,
45 #[inspect(skip)]
46 device_event: GuestMemory,
47 queue_size: u16,
48 next_avail_index: u16,
49 wrapped_bit: bool,
50 next_is_available: bool,
51}
52
53impl PackedQueueGetWork {
54 fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
55 if let Ok(event) = self.device_event.read_plain::<PackedEventSuppression>(0) {
56 resp.field("device_event_flags", event.flags());
57 resp.field("device_event_offset", event.offset());
58 resp.field("device_event_wrap", event.wrap());
59 }
60 }
61
62 pub fn new(
63 _features: VirtioDeviceFeatures,
64 mem: GuestMemory,
65 params: QueueParams,
66 initial_index: u16,
67 initial_wrap: bool,
68 ) -> Result<Self, QueueError> {
69 let queue_desc = mem
70 .subrange(params.desc_addr, descriptor_offset(params.size), true)
71 .map_err(QueueError::Memory)?;
72 let device_event = mem
73 .subrange(
74 params.used_addr,
75 size_of::<PackedEventSuppression>() as u64,
76 true,
77 )
78 .map_err(QueueError::Memory)?;
79 Ok(Self {
80 queue_desc,
81 device_event,
82 queue_size: params.size,
83 next_avail_index: initial_index,
84 wrapped_bit: initial_wrap,
85 next_is_available: false,
86 })
87 }
88
89 pub fn avail_state(&self) -> u16 {
91 self.next_avail_index | (u16::from(self.wrapped_bit) << 15)
92 }
93
94 pub fn is_available(&mut self) -> Result<Option<u16>, QueueError> {
101 if !self.next_is_available {
102 let flags: DescriptorFlags = self
103 .queue_desc
104 .read_plain(
105 descriptor_offset(self.next_avail_index)
106 + std::mem::offset_of!(PackedDescriptor, flags_raw) as u64,
107 )
108 .map_err(QueueError::Memory)?;
109 if flags.available() != self.wrapped_bit || flags.used() == self.wrapped_bit {
110 return Ok(None);
111 }
112 atomic::fence(atomic::Ordering::Acquire);
115 self.next_is_available = true;
116 }
117 Ok(Some(self.next_avail_index))
118 }
119
120 pub fn arm_kick(&mut self) -> Result<bool, QueueError> {
125 let enable_event = PackedEventSuppression::new().with_flags(EventSuppressionFlags::Enabled);
126 self.device_event
127 .write_plain(0, &enable_event)
128 .map_err(QueueError::Memory)?;
129 atomic::fence(atomic::Ordering::SeqCst);
131 if self.is_available()?.is_some() {
132 self.suppress_kicks()?;
134 return Ok(false);
135 }
136 Ok(true)
137 }
138
139 pub fn suppress_kicks(&self) -> Result<(), QueueError> {
142 let disable_event =
143 PackedEventSuppression::new().with_flags(EventSuppressionFlags::Disabled);
144 self.device_event
145 .write_plain(0, &disable_event)
146 .map_err(QueueError::Memory)?;
147 Ok(())
148 }
149
150 pub fn advance(&mut self, count: u16) {
152 let raw = self.next_avail_index + count;
155 self.next_avail_index = if raw >= self.queue_size {
156 self.wrapped_bit = !self.wrapped_bit;
157 raw - self.queue_size
158 } else {
159 raw
160 };
161 self.next_is_available = false;
162 }
163}
164
165#[derive(Debug, Inspect)]
166#[inspect(extra = "Self::inspect_extra")]
167pub(crate) struct PackedQueueCompleteWork {
168 #[inspect(skip)]
169 queue_desc: GuestMemory,
170 #[inspect(skip)]
171 driver_event: GuestMemory,
172 queue_size: u16,
173 next_index: u16,
174 wrapped_bit: bool,
175 use_event_index: bool,
176}
177
178impl PackedQueueCompleteWork {
179 fn inspect_extra(&self, resp: &mut inspect::Response<'_>) {
180 if let Ok(event) = self.driver_event.read_plain::<PackedEventSuppression>(0) {
181 resp.field("driver_event_flags", event.flags());
182 resp.field("driver_event_offset", event.offset());
183 resp.field("driver_event_wrap", event.wrap());
184 }
185 }
186
187 pub fn new(
188 features: VirtioDeviceFeatures,
189 mem: GuestMemory,
190 params: QueueParams,
191 initial_index: u16,
192 initial_wrap: bool,
193 ) -> Result<Self, QueueError> {
194 let queue_desc = mem
195 .subrange(params.desc_addr, descriptor_offset(params.size), true)
196 .map_err(QueueError::Memory)?;
197 let driver_event = mem
198 .subrange(
199 params.avail_addr,
200 size_of::<PackedEventSuppression>() as u64,
201 true,
202 )
203 .map_err(QueueError::Memory)?;
204 Ok(Self {
205 queue_desc,
206 driver_event,
207 queue_size: params.size,
208 next_index: initial_index,
209 wrapped_bit: initial_wrap,
210 use_event_index: features.ring_event_idx(),
211 })
212 }
213
214 pub fn used_state(&self) -> u16 {
216 self.next_index | (u16::from(self.wrapped_bit) << 15)
217 }
218
219 pub fn complete_descriptor(
220 &mut self,
221 context: &PackedQueueCompletionContext,
222 bytes_written: u32,
223 ) -> Result<bool, QueueError> {
224 let descriptor = PackedDescriptor::new()
225 .with_buffer_id(context.buffer_id)
226 .with_length(bytes_written)
227 .with_flags(
228 DescriptorFlags::new()
229 .with_available(self.wrapped_bit)
230 .with_used(self.wrapped_bit),
231 );
232 atomic::fence(atomic::Ordering::Release);
235 self.queue_desc
236 .write_plain(descriptor_offset(self.next_index), &descriptor)
237 .map_err(QueueError::Memory)?;
238 atomic::fence(atomic::Ordering::SeqCst);
240 let driver_event: PackedEventSuppression = self
241 .driver_event
242 .read_plain(0)
243 .map_err(QueueError::Memory)?;
244 let send_signal = match driver_event.flags() {
245 EventSuppressionFlags::Disabled => false,
246 EventSuppressionFlags::DescriptorIndex if self.use_event_index => {
247 driver_event.offset() == self.next_index && driver_event.wrap() == self.wrapped_bit
248 }
249 _ => true,
250 };
251 let raw = self.next_index + context.descriptor_count;
253 self.next_index = if raw >= self.queue_size {
254 self.wrapped_bit = !self.wrapped_bit;
255 raw - self.queue_size
256 } else {
257 raw
258 };
259 Ok(send_signal)
260 }
261}