nic_queues/lib.rs
1#![no_std]
2
3pub trait RxDescriptor: Copy {
4 /// Sets buffer addr.
5 fn set_buffer_addr(&mut self, phys: u64);
6 /// Returns whether done.
7 fn is_done(&self) -> bool;
8 /// Performs the packet length operation.
9 fn packet_length(&self) -> u16;
10 /// Performs the clear status operation.
11 fn clear_status(&mut self);
12}
13
14pub trait TxDescriptor: Copy {
15 /// Sets buffer.
16 fn set_buffer(&mut self, phys: u64, len: u16);
17 /// Sets eop ifcs rs.
18 fn set_eop_ifcs_rs(&mut self);
19 /// Returns whether done.
20 fn is_done(&self) -> bool;
21 /// Performs the clear operation.
22 fn clear(&mut self);
23}
24
25pub struct RxRing<D: RxDescriptor> {
26 descs: *mut D,
27 count: usize,
28 tail: usize,
29}
30
31// SAFETY: RxRing only contains a raw pointer to a descriptor ring and plain
32// indices. Sending it to another thread is safe as long as external code
33// upholds exclusive mutation/aliasing rules for the underlying ring memory.
34unsafe impl<D: RxDescriptor> Send for RxRing<D> {}
35
36impl<D: RxDescriptor> RxRing<D> {
37 /// # Safety
38 /// `descs` must point to `count` valid, zero-initialised descriptors.
39 pub unsafe fn new(descs: *mut D, count: usize) -> Self {
40 Self {
41 descs,
42 count,
43 tail: count - 1,
44 }
45 }
46
47 /// Performs the count operation.
48 pub fn count(&self) -> usize {
49 self.count
50 }
51
52 /// Performs the tail operation.
53 pub fn tail(&self) -> usize {
54 self.tail
55 }
56
57 /// Performs the desc operation.
58 pub fn desc(&self, idx: usize) -> &D {
59 // SAFETY: `idx % count` is in bounds and `descs` points to `count` valid descriptors.
60 unsafe { &*self.descs.add(idx % self.count) }
61 }
62
63 /// Performs the desc mut operation.
64 pub fn desc_mut(&mut self, idx: usize) -> &mut D {
65 // SAFETY: `new` guarantees `descs` points to `count` valid descriptors.
66 // Indexing is wrapped modulo `count`, so pointer arithmetic stays in ring bounds.
67 unsafe { &mut *self.descs.add(idx % self.count) }
68 }
69
70 /// Check the next descriptor; returns `(index, packet_length)` if ready.
71 pub fn poll(&self) -> Option<(usize, u16)> {
72 let next = (self.tail + 1) % self.count;
73 // SAFETY: `next < count` and `descs` points to `count` valid descriptors.
74 // Immutable access does not violate aliasing.
75 let desc = unsafe { &*self.descs.add(next) };
76 if desc.is_done() {
77 Some((next, desc.packet_length()))
78 } else {
79 None
80 }
81 }
82
83 /// Advance tail after consuming a packet. Returns new tail.
84 pub fn advance(&mut self) -> usize {
85 self.tail = (self.tail + 1) % self.count;
86 self.tail
87 }
88
89 /// Set up one RX descriptor with a pre-allocated buffer.
90 pub fn setup_desc(&mut self, idx: usize, buf_phys: u64) {
91 let d = self.desc_mut(idx);
92 d.clear_status();
93 d.set_buffer_addr(buf_phys);
94 }
95}
96
97pub struct TxRing<D: TxDescriptor> {
98 descs: *mut D,
99 count: usize,
100 tail: usize,
101}
102
103// SAFETY: TxRing stores a raw descriptor pointer and indices only. Transfer
104// across threads is sound when callers synchronize ownership of descriptor memory.
105unsafe impl<D: TxDescriptor> Send for TxRing<D> {}
106
107impl<D: TxDescriptor> TxRing<D> {
108 /// # Safety
109 /// `descs` must point to `count` valid, zero-initialised descriptors.
110 pub unsafe fn new(descs: *mut D, count: usize) -> Self {
111 Self {
112 descs,
113 count,
114 tail: 0,
115 }
116 }
117
118 /// Performs the count operation.
119 pub fn count(&self) -> usize {
120 self.count
121 }
122
123 /// Performs the tail operation.
124 pub fn tail(&self) -> usize {
125 self.tail
126 }
127
128 /// Performs the desc operation.
129 pub fn desc(&self, idx: usize) -> &D {
130 // SAFETY: `idx % count` is in bounds and `descs` points to `count` valid descriptors.
131 unsafe { &*self.descs.add(idx % self.count) }
132 }
133
134 /// Performs the desc mut operation.
135 pub fn desc_mut(&mut self, idx: usize) -> &mut D {
136 // SAFETY: `idx % count` is in bounds and mutable access is gated by `&mut self`.
137 unsafe { &mut *self.descs.add(idx % self.count) }
138 }
139
140 /// Prepare and submit a packet at the current tail slot.
141 /// Returns the descriptor index used.
142 pub fn submit(&mut self, phys: u64, len: u16) -> usize {
143 let idx = self.tail;
144 let d = self.desc_mut(idx);
145 d.clear();
146 d.set_buffer(phys, len);
147 d.set_eop_ifcs_rs();
148 self.tail = (idx + 1) % self.count;
149 idx
150 }
151
152 /// Returns whether done.
153 pub fn is_done(&self, idx: usize) -> bool {
154 self.desc(idx).is_done()
155 }
156}