Skip to main content

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}