1use crate::save_restore::CqEqSavedState;
7use crate::save_restore::DoorbellSavedState;
8use crate::save_restore::WqSavedState;
9use gdma_defs::CLIENT_OOB_8;
10use gdma_defs::CLIENT_OOB_24;
11use gdma_defs::CLIENT_OOB_32;
12use gdma_defs::CqEqDoorbellValue;
13use gdma_defs::Cqe;
14use gdma_defs::DB_CQ;
15use gdma_defs::DB_EQ;
16use gdma_defs::DB_RQ;
17use gdma_defs::DB_SQ;
18use gdma_defs::Eqe;
19use gdma_defs::GdmaQueueType;
20use gdma_defs::OWNER_BITS;
21use gdma_defs::OWNER_MASK;
22use gdma_defs::Sge;
23use gdma_defs::WQE_ALIGNMENT;
24use gdma_defs::WqDoorbellValue;
25use gdma_defs::WqeHeader;
26use gdma_defs::WqeParams;
27use inspect::Inspect;
28use std::marker::PhantomData;
29use std::sync::Arc;
30use std::sync::atomic::Ordering::Acquire;
31use user_driver::memory::MemoryBlock;
32use zerocopy::FromBytes;
33use zerocopy::Immutable;
34use zerocopy::IntoBytes;
35use zerocopy::KnownLayout;
36
37pub trait Doorbell: Send + Sync {
39 fn page_count(&self) -> u32;
41 fn write(&self, page: u32, address: u32, value: u64);
43 fn save(&self, doorbell_id: Option<u64>) -> DoorbellSavedState;
45}
46
47struct NullDoorbell;
48
49impl Doorbell for NullDoorbell {
50 fn page_count(&self) -> u32 {
51 0
52 }
53
54 fn write(&self, _page: u32, _address: u32, _value: u64) {}
55
56 fn save(&self, _doorbell_id: Option<u64>) -> DoorbellSavedState {
57 DoorbellSavedState {
58 doorbell_id: 0,
59 page_count: 0,
60 }
61 }
62}
63
64#[derive(Clone)]
66pub struct DoorbellPage {
67 doorbell: Arc<dyn Doorbell>,
68 doorbell_id: u32,
69}
70
71impl DoorbellPage {
72 pub(crate) fn null() -> Self {
73 Self {
74 doorbell: Arc::new(NullDoorbell),
75 doorbell_id: 0,
76 }
77 }
78
79 pub fn new(doorbell: Arc<dyn Doorbell>, doorbell_id: u32) -> anyhow::Result<Self> {
81 let page_count = doorbell.page_count();
82 if doorbell_id >= page_count {
83 anyhow::bail!(
84 "doorbell id {} exceeds page count {}",
85 doorbell_id,
86 page_count
87 );
88 }
89 Ok(Self {
90 doorbell,
91 doorbell_id,
92 })
93 }
94
95 pub fn write(&self, address: u32, value: u64) {
97 assert!(address < 4096);
98 self.doorbell.write(self.doorbell_id, address, value);
99 }
100}
101
102pub struct CqEq<T> {
104 doorbell: DoorbellPage,
105 doorbell_addr: u32,
106 queue_type: GdmaQueueType,
107 mem: MemoryBlock,
108 id: u32,
109 next: u32,
110 size: u32,
111 shift: u32,
112 _phantom: PhantomData<fn() -> T>,
113}
114
115impl<T> Inspect for CqEq<T> {
116 fn inspect(&self, req: inspect::Request<'_>) {
117 req.respond()
118 .field("id", self.id)
119 .hex("size", self.size)
120 .hex("next", self.next);
121 }
122}
123
124impl CqEq<Cqe> {
125 pub fn new_cq(mem: MemoryBlock, doorbell: DoorbellPage, id: u32) -> Self {
127 Self::new(GdmaQueueType::GDMA_CQ, DB_CQ, mem, doorbell, id)
128 }
129
130 pub fn restore_cq(mem: MemoryBlock, state: CqEqSavedState, doorbell: DoorbellPage) -> Self {
132 Self::restore(GdmaQueueType::GDMA_CQ, mem, doorbell, state)
133 }
134}
135
136impl CqEq<Eqe> {
137 pub fn new_eq(mem: MemoryBlock, doorbell: DoorbellPage, id: u32) -> Self {
139 Self::new(GdmaQueueType::GDMA_EQ, DB_EQ, mem, doorbell, id)
140 }
141
142 pub fn restore_eq(mem: MemoryBlock, state: CqEqSavedState, doorbell: DoorbellPage) -> Self {
144 Self::restore(GdmaQueueType::GDMA_EQ, mem, doorbell, state)
145 }
146}
147
148impl<T: IntoBytes + FromBytes + Immutable + KnownLayout> CqEq<T> {
149 fn new(
151 queue_type: GdmaQueueType,
152 doorbell_addr: u32,
153 mem: MemoryBlock,
154 doorbell: DoorbellPage,
155 id: u32,
156 ) -> Self {
157 let size = mem.len();
158 assert!(size.is_power_of_two());
159 Self {
160 doorbell,
161 doorbell_addr,
162 queue_type,
163 mem,
164 id,
165 next: size as u32,
166 size: size as u32,
167 shift: size.trailing_zeros(),
168 _phantom: PhantomData,
169 }
170 }
171
172 pub fn save(&self) -> CqEqSavedState {
174 CqEqSavedState {
175 doorbell: DoorbellSavedState {
176 doorbell_id: self.doorbell.doorbell_id as u64,
177 page_count: self.doorbell.doorbell.page_count(),
178 },
179 doorbell_addr: self.doorbell_addr,
180 id: self.id,
181 next: self.next,
182 size: self.size,
183 shift: self.shift,
184 }
185 }
186
187 pub fn restore(
189 queue_type: GdmaQueueType,
190 mem: MemoryBlock,
191 doorbell: DoorbellPage,
192 state: CqEqSavedState,
193 ) -> Self {
194 Self {
195 doorbell,
196 doorbell_addr: state.doorbell_addr,
197 queue_type,
198 mem,
199 id: state.id,
200 next: state.next,
201 size: state.size,
202 shift: state.shift,
203 _phantom: PhantomData,
204 }
205 }
206
207 pub(crate) fn set_id(&mut self, id: u32) {
209 self.id = id;
210 }
211
212 pub(crate) fn set_doorbell(&mut self, page: DoorbellPage) {
214 self.doorbell = page;
215 }
216
217 pub fn id(&self) -> u32 {
219 self.id
220 }
221
222 fn read_next<U: FromBytes + Immutable + KnownLayout>(&self, offset: u32) -> U {
223 assert!((offset as usize & (size_of::<T>() - 1)) + size_of::<U>() <= size_of::<T>());
224 self.mem
225 .read_obj((self.next.wrapping_add(offset) & (self.size - 1)) as usize)
226 }
227
228 pub fn pop(&mut self) -> Option<T> {
230 let b = self.mem.as_slice()
233 [(self.next.wrapping_add(size_of::<T>() as u32 - 1) & (self.size - 1)) as usize]
234 .load(Acquire);
235 let owner_count = b >> 5;
236 let cur_owner_count = (self.next >> self.shift) as u8;
237 if owner_count == (cur_owner_count.wrapping_sub(1)) & OWNER_MASK as u8 {
238 None
239 } else if owner_count == cur_owner_count & OWNER_MASK as u8 {
240 let qe = self.read_next::<T>(0);
241 self.next = self.next.wrapping_add(size_of_val(&qe) as u32);
242 Some(qe)
243 } else {
244 tracing::error!(next = self.next, owner_count, queue_type = ?self.queue_type, id = self.id, "eq/cq wrapped");
245 None
246 }
247 }
248
249 fn flush(&mut self, arm: bool) {
250 let tail = self.next & ((self.size << OWNER_BITS) - 1);
251 let value = CqEqDoorbellValue::new()
252 .with_arm(arm)
253 .with_id(self.id)
254 .with_tail(tail / size_of::<T>() as u32);
255 tracing::trace!(queue_type = ?self.queue_type, id = self.id, ?value, "cq/eq doorbell write");
256 self.doorbell.write(self.doorbell_addr, value.into());
257 }
258
259 pub fn arm(&mut self) {
262 self.flush(true);
263 }
264
265 pub fn ack(&mut self) {
267 self.flush(false);
268 }
269
270 pub fn get_next(&mut self) -> u32 {
272 self.next
273 }
274}
275
276pub type Cq = CqEq<Cqe>;
278
279pub type Eq = CqEq<Eqe>;
281
282pub struct Wq {
284 doorbell: DoorbellPage,
285 queue_type: GdmaQueueType,
286 doorbell_addr: u32,
287 mem: MemoryBlock,
288 id: u32,
289 head: u32,
290 tail: u32,
291 mask: u32,
292 uncommitted_count: u32,
293}
294
295impl Inspect for Wq {
296 fn inspect(&self, req: inspect::Request<'_>) {
297 req.respond()
298 .field("id", self.id)
299 .hex("size", self.mask + 1)
300 .hex("head", self.head)
301 .hex("tail", self.tail)
302 .field("uncommited", self.uncommitted_count);
303 }
304}
305
306#[derive(Debug)]
308pub struct QueueFull;
309
310impl Wq {
311 pub fn new_sq(mem: MemoryBlock, doorbell: DoorbellPage, id: u32) -> Self {
313 Self::new(GdmaQueueType::GDMA_SQ, DB_SQ, mem, doorbell, id)
314 }
315
316 pub fn new_rq(mem: MemoryBlock, doorbell: DoorbellPage, id: u32) -> Self {
318 Self::new(GdmaQueueType::GDMA_RQ, DB_RQ, mem, doorbell, id)
319 }
320
321 fn new(
323 queue_type: GdmaQueueType,
324 doorbell_addr: u32,
325 mem: MemoryBlock,
326 doorbell: DoorbellPage,
327 id: u32,
328 ) -> Self {
329 let size = mem.len() as u32;
330 assert!(size.is_power_of_two());
331 Self {
332 doorbell,
333 queue_type,
334 doorbell_addr,
335 mem,
336 id,
337 head: size,
338 tail: 0,
339 mask: size - 1,
340 uncommitted_count: 0,
341 }
342 }
343
344 pub fn save(&self) -> WqSavedState {
346 WqSavedState {
347 doorbell: DoorbellSavedState {
348 doorbell_id: self.doorbell.doorbell_id as u64,
349 page_count: self.doorbell.doorbell.page_count(),
350 },
351 doorbell_addr: self.doorbell_addr,
352 id: self.id,
353 head: self.head,
354 tail: self.tail,
355 mask: self.mask,
356 }
357 }
358
359 pub fn restore_rq(
361 mem: MemoryBlock,
362 state: WqSavedState,
363 doorbell: DoorbellPage,
364 ) -> anyhow::Result<Self> {
365 Ok(Self {
366 doorbell,
367 doorbell_addr: state.doorbell_addr,
368 queue_type: GdmaQueueType::GDMA_RQ,
369 mem,
370 id: state.id,
371 head: state.head,
372 tail: state.tail,
373 mask: state.mask,
374 uncommitted_count: 0,
375 })
376 }
377
378 pub fn restore_sq(
380 mem: MemoryBlock,
381 state: WqSavedState,
382 doorbell: DoorbellPage,
383 ) -> anyhow::Result<Self> {
384 Ok(Self {
385 doorbell,
386 doorbell_addr: state.doorbell_addr,
387 queue_type: GdmaQueueType::GDMA_SQ,
388 mem,
389 id: state.id,
390 head: state.head,
391 tail: state.tail,
392 mask: state.mask,
393 uncommitted_count: 0,
394 })
395 }
396
397 pub fn id(&self) -> u32 {
399 self.id
400 }
401
402 pub fn advance_head(&mut self, n: u32) {
404 assert!(n.is_multiple_of(WQE_ALIGNMENT as u32));
405 self.head = self.head.wrapping_add(n);
406 }
407
408 fn get_offset_in_buffer_in_bytes(&self, offset: u32) -> usize {
409 (offset as usize * WQE_ALIGNMENT) & self.mask as usize
410 }
411
412 pub fn read(&mut self, offset: u32, n: usize) -> Vec<u8> {
414 let mut buf = vec![0; n];
415 let offset_in_buffer = self.get_offset_in_buffer_in_bytes(offset);
416 self.mem.read_at(offset_in_buffer, &mut buf);
417 buf
418 }
419
420 fn write_tail(&self, offset: u32, data: &[u8]) {
421 assert!(
422 offset as usize % WQE_ALIGNMENT + data.len() <= WQE_ALIGNMENT,
423 "can't write more than one queue segment at a time to avoid wrapping"
424 );
425 self.mem
426 .write_at((self.tail.wrapping_add(offset) & self.mask) as usize, data);
427 }
428
429 pub fn available(&self) -> u32 {
431 self.head.wrapping_sub(self.tail)
432 }
433
434 pub const fn entry_size(oob_len: usize, sge_count: usize) -> u32 {
437 let len = size_of::<WqeHeader>() + oob_len + size_of::<Sge>() * sge_count;
438 let len = (len + WQE_ALIGNMENT - 1) & !(WQE_ALIGNMENT - 1);
439 len as u32
440 }
441
442 pub fn push<I: IntoIterator<Item = Sge>>(
445 &mut self,
446 oob: &(impl IntoBytes + Immutable + KnownLayout),
447 sgl: I,
448 client_oob_in_sgl: Option<u8>,
449 gd_client_unit_data: u16,
450 ) -> Result<u32, QueueFull>
451 where
452 I::IntoIter: ExactSizeIterator,
453 {
454 let sgl = sgl.into_iter();
455 let oob_size = match size_of_val(oob) {
456 0 | 8 => CLIENT_OOB_8,
457 24 => CLIENT_OOB_24,
458 32 => CLIENT_OOB_32,
459 _ => panic!("invalid oob size"),
460 };
461 let len = Self::entry_size(size_of_val(oob), sgl.len());
462 if self.available() < len {
463 return Err(QueueFull);
464 }
465
466 let hdr = WqeHeader {
467 reserved: [0; 3],
468 last_vbytes: client_oob_in_sgl.unwrap_or(0),
469 params: WqeParams::new()
470 .with_num_sgl_entries(sgl.len() as u8)
471 .with_inline_client_oob_size(oob_size)
472 .with_client_oob_in_sgl(client_oob_in_sgl.is_some())
473 .with_gd_client_unit_data(gd_client_unit_data),
474 };
475
476 self.write_tail(0, hdr.as_bytes());
477
478 let offset = match size_of_val(oob) {
479 0 => 16,
480 8 => {
481 self.write_tail(8, oob.as_bytes());
482 16
483 }
484 24 => {
485 self.write_tail(8, oob.as_bytes());
486 32
487 }
488 32 => {
489 self.write_tail(8, &oob.as_bytes()[..24]);
490 self.mem.write_at(32, &oob.as_bytes()[24..]);
491 48
492 }
493 _ => unreachable!(),
494 };
495
496 for (i, sge) in sgl.enumerate() {
497 self.write_tail(offset + i as u32 * 16, sge.as_bytes());
498 }
499
500 self.tail = self.tail.wrapping_add(len);
501 self.uncommitted_count += 1;
502 Ok(len)
503 }
504
505 pub fn commit(&mut self) {
508 let mut value = WqDoorbellValue::new().with_id(self.id).with_tail(self.tail);
510 if self.queue_type == GdmaQueueType::GDMA_RQ {
511 value.set_num_rwqe(self.uncommitted_count as u8);
514 }
515 tracing::trace!(queue_type = ?self.queue_type, id = self.id, ?value, "wq doorbell write");
516 self.doorbell.write(self.doorbell_addr, value.into());
517 self.uncommitted_count = 0;
518 }
519
520 pub fn get_tail(&mut self) -> u32 {
522 self.tail
523 }
524}