1use core::sync::atomic::{Ordering, fence};
8
9use crate::{dma::aligned::InternalMemory, reg_access::VolatileCell};
10
11pub const MAX_FRAME_SIZE: usize = 1524;
13pub const MIN_RX_FRAME_SIZE: usize = 14;
15
16const TX_CHECKSUM_OFFLOAD: bool = property!("ethernet.tx_checksum_offload");
17
18pub const TDES0_OWN: u32 = 1 << 31;
22pub const TDES0_IC: u32 = 1 << 30;
24pub const TDES0_LS: u32 = 1 << 29;
26pub const TDES0_FS: u32 = 1 << 28;
28pub const TDES0_CHAINED: u32 = 1 << 20;
30pub const TDES0_CIC_SHIFT: u32 = 22;
33pub const TDES0_CIC_FULL: u32 = 0b11 << TDES0_CIC_SHIFT;
35
36pub const RDES0_OWN: u32 = 1 << 31;
40pub const RDES0_FL_SHIFT: u32 = 16;
42pub const RDES0_FL_MASK: u32 = 0x3fff << RDES0_FL_SHIFT;
44pub const RDES0_ES: u32 = 1 << 15;
46pub const RDES0_FS: u32 = 1 << 9;
48pub const RDES0_LS: u32 = 1 << 8;
50
51pub const RDES1_BUF1_SIZE_MASK: u32 = 0x1fff;
53pub const RDES1_CHAINED: u32 = 1 << 14;
55
56cfg_select! {
61 ethernet_rx_checksum_offload => {
62 pub const RDES0_ESA: u32 = 1 << 0;
64 pub const RDES4_IP_HEADER_ERROR: u32 = 1 << 3;
66 pub const RDES4_IP_PAYLOAD_ERROR: u32 = 1 << 4;
68 pub const RDES4_IP_CHECKSUM_BYPASSED: u32 = 1 << 5;
70 pub const RDES4_IPV4_PACKET: u32 = 1 << 6;
72 pub const RDES4_IPV6_PACKET: u32 = 1 << 7;
74 }
75 _ => {}
76}
77
78#[derive(Clone, Copy, Debug, Eq, PartialEq)]
82pub enum OwnedBy {
83 Cpu,
85 Dma,
87}
88
89#[repr(C)]
94pub struct TDes {
95 pub(super) tdes0: VolatileCell<u32>,
96 pub(super) tdes1: VolatileCell<u32>,
97 pub(super) buf_addr: VolatileCell<u32>,
98 pub(super) next_desc: VolatileCell<u32>,
99 _tdes4: VolatileCell<u32>,
101 _tdes5: VolatileCell<u32>,
102 _tdes6: VolatileCell<u32>,
103 _tdes7: VolatileCell<u32>,
104}
105
106impl TDes {
107 pub const fn new_zeroed() -> Self {
109 Self {
110 tdes0: VolatileCell::new(0),
111 tdes1: VolatileCell::new(0),
112 buf_addr: VolatileCell::new(0),
113 next_desc: VolatileCell::new(0),
114 _tdes4: VolatileCell::new(0),
115 _tdes5: VolatileCell::new(0),
116 _tdes6: VolatileCell::new(0),
117 _tdes7: VolatileCell::new(0),
118 }
119 }
120
121 pub fn owned_by(&self) -> OwnedBy {
123 if self.tdes0.get() & TDES0_OWN != 0 {
124 OwnedBy::Dma
125 } else {
126 OwnedBy::Cpu
127 }
128 }
129
130 pub fn set_owned_by(&mut self, owner: OwnedBy) {
132 let v = self.tdes0.get();
133 self.tdes0.set(match owner {
134 OwnedBy::Cpu => v & !TDES0_OWN,
135 OwnedBy::Dma => v | TDES0_OWN,
136 });
137 }
138
139 fn set_chained(&mut self) {
140 self.tdes0.set(self.tdes0.get() | TDES0_CHAINED);
141 }
142
143 fn set_len_and_flags(&mut self, len: usize) {
149 self.tdes1.set(len as u32 & RDES1_BUF1_SIZE_MASK);
150 let cic = if TX_CHECKSUM_OFFLOAD {
151 TDES0_CIC_FULL
152 } else {
153 0
154 };
155 self.tdes0
156 .set((self.tdes0.get() & TDES0_CHAINED) | TDES0_FS | TDES0_LS | TDES0_IC | cic);
157 }
158
159 fn set_buffer_addr(&mut self, addr: *const u8) {
160 self.buf_addr.set(addr as u32);
161 }
162
163 fn set_next_desc(&mut self, addr: *const TDes) {
164 self.next_desc.set(addr as u32);
165 }
166}
167
168#[repr(C)]
172pub struct RDes {
173 pub(super) rdes0: VolatileCell<u32>,
174 pub(super) rdes1: VolatileCell<u32>,
175 pub(super) buf_addr: VolatileCell<u32>,
176 pub(super) next_desc: VolatileCell<u32>,
177 #[cfg_attr(
179 not(ethernet_rx_checksum_offload),
180 allow(dead_code, reason = "only read when RX checksum offload is enabled")
181 )]
182 rdes4: VolatileCell<u32>,
183 _rdes5: VolatileCell<u32>,
184 _rdes6: VolatileCell<u32>,
185 _rdes7: VolatileCell<u32>,
186}
187
188impl RDes {
189 pub const fn new_zeroed() -> Self {
191 Self {
192 rdes0: VolatileCell::new(0),
193 rdes1: VolatileCell::new(0),
194 buf_addr: VolatileCell::new(0),
195 next_desc: VolatileCell::new(0),
196 rdes4: VolatileCell::new(0),
197 _rdes5: VolatileCell::new(0),
198 _rdes6: VolatileCell::new(0),
199 _rdes7: VolatileCell::new(0),
200 }
201 }
202
203 pub fn owned_by(&self) -> OwnedBy {
205 if self.rdes0.get() & RDES0_OWN != 0 {
206 OwnedBy::Dma
207 } else {
208 OwnedBy::Cpu
209 }
210 }
211
212 fn set_rdes0(&mut self, value: u32) {
213 self.rdes0.set(value);
214 }
215
216 fn set_owned_by(&mut self, owner: OwnedBy) {
217 let v = self.rdes0.get();
218 self.set_rdes0(match owner {
219 OwnedBy::Cpu => v & !RDES0_OWN,
220 OwnedBy::Dma => v | RDES0_OWN,
221 });
222 }
223
224 fn is_complete_frame(&self) -> bool {
225 let s = self.rdes0.get();
226 s & RDES0_FS != 0 && s & RDES0_LS != 0
227 }
228
229 fn frame_len(&self) -> usize {
230 ((self.rdes0.get() & RDES0_FL_MASK) >> RDES0_FL_SHIFT) as usize
231 }
232
233 #[cfg(ethernet_rx_checksum_offload)]
241 fn checksum_error(&self) -> bool {
242 if self.rdes0.get() & RDES0_ESA == 0 {
244 return false;
245 }
246
247 let ext = self.rdes4.get();
248
249 let is_ip = ext & (RDES4_IPV4_PACKET | RDES4_IPV6_PACKET) != 0;
251 let bypassed = ext & RDES4_IP_CHECKSUM_BYPASSED != 0;
253
254 is_ip && !bypassed && ext & (RDES4_IP_HEADER_ERROR | RDES4_IP_PAYLOAD_ERROR) != 0
255 }
256
257 fn configure_buffer(&mut self, size: usize) {
258 self.rdes1.set(
259 (self.rdes1.get() & !RDES1_BUF1_SIZE_MASK)
260 | (size as u32 & RDES1_BUF1_SIZE_MASK)
261 | RDES1_CHAINED,
262 );
263 }
264
265 fn set_buffer_addr(&mut self, addr: *const u8) {
266 self.buf_addr.set(addr as u32);
267 }
268
269 fn set_next_desc(&mut self, addr: *const RDes) {
270 self.next_desc.set(addr as u32);
271 }
272}
273
274pub struct EthernetDmaStorage<const RX: usize, const TX: usize> {
281 pub(super) rx_descs: [InternalMemory<RDes>; RX],
282 pub(super) tx_descs: [InternalMemory<TDes>; TX],
283 pub(super) rx_bufs: [InternalMemory<[u8; MAX_FRAME_SIZE]>; RX],
284 pub(super) tx_bufs: [InternalMemory<[u8; MAX_FRAME_SIZE]>; TX],
285}
286
287impl<const RX: usize, const TX: usize> Default for EthernetDmaStorage<RX, TX> {
288 fn default() -> Self {
289 Self::new()
290 }
291}
292
293impl<const RX: usize, const TX: usize> EthernetDmaStorage<RX, TX> {
294 pub const fn new() -> Self {
296 Self {
297 rx_descs: [const { InternalMemory::new(RDes::new_zeroed()) }; RX],
298 tx_descs: [const { InternalMemory::new(TDes::new_zeroed()) }; TX],
299 rx_bufs: [const { InternalMemory::new([0u8; MAX_FRAME_SIZE]) }; RX],
300 tx_bufs: [const { InternalMemory::new([0u8; MAX_FRAME_SIZE]) }; TX],
301 }
302 }
303}
304
305unsafe impl<const RX: usize, const TX: usize> Send for EthernetDmaStorage<RX, TX> {}
308unsafe impl<const RX: usize, const TX: usize> Sync for EthernetDmaStorage<RX, TX> {}
309
310pub struct TDesRing<'a> {
314 descriptors: &'a mut [InternalMemory<TDes>],
315 buffers: &'a mut [InternalMemory<[u8; MAX_FRAME_SIZE]>],
316 index: usize,
317}
318
319impl<'a> TDesRing<'a> {
320 pub fn new(
322 descriptors: &'a mut [InternalMemory<TDes>],
323 buffers: &'a mut [InternalMemory<[u8; MAX_FRAME_SIZE]>],
324 ) -> Self {
325 assert!(!descriptors.is_empty());
326 assert_eq!(descriptors.len(), buffers.len());
327
328 let mut ring = Self {
329 descriptors,
330 buffers,
331 index: 0,
332 };
333 ring.reset();
334 ring
335 }
336
337 pub(crate) fn len(&self) -> usize {
338 self.descriptors.len()
339 }
340
341 pub fn reset(&mut self) {
345 let n = self.descriptors.len();
346 for i in 0..n {
347 let next = self.descriptors[(i + 1) % n].as_ptr();
348 let buf_addr = self.buffers[i].as_ptr().cast::<u8>();
349
350 let mut desc = self.descriptors[i].get_mut();
351 desc.tdes0.set(0);
352 desc.tdes1.set(0);
353 desc.set_chained();
354 desc.set_buffer_addr(buf_addr);
355 desc.set_next_desc(next);
356 desc.set_owned_by(OwnedBy::Cpu);
357 #[cfg(soc_internal_memory_cached)]
358 self.descriptors[i].get_mut().writeback();
359 }
360 self.index = 0;
361 fence(Ordering::Release);
362 }
363
364 pub fn base_ptr(&self) -> *const TDes {
366 self.descriptors[0].as_ptr()
367 }
368
369 pub fn transmit(&mut self, frame: &[u8]) -> Result<(), TxError> {
374 if frame.len() > MAX_FRAME_SIZE {
375 return Err(TxError::FrameTooLarge);
376 }
377
378 if let Some(buf) = self.available_buf() {
379 buf[..frame.len()].copy_from_slice(frame);
380 self.commit(frame.len());
381 Ok(())
382 } else {
383 Err(TxError::RingFull)
384 }
385 }
386
387 pub fn has_capacity(&self) -> bool {
389 let desc = self.descriptors[self.index].get_ref();
390 #[cfg(soc_internal_memory_cached)]
391 desc.invalidate();
392 fence(Ordering::Acquire);
393 desc.owned_by() == OwnedBy::Cpu
394 }
395
396 pub fn available_buf(&mut self) -> Option<&mut [u8; MAX_FRAME_SIZE]> {
402 if self.has_capacity() {
403 let idx = self.index;
404 Some(self.buffers[idx].get_mut().into_inner())
405 } else {
406 None
407 }
408 }
409
410 pub fn commit(&mut self, len: usize) {
416 let idx = self.index;
417 let n = self.descriptors.len();
418
419 #[cfg(soc_internal_memory_cached)]
420 self.buffers[idx].get_mut().writeback();
421
422 let mut desc = self.descriptors[idx].get_mut();
423 desc.set_len_and_flags(len);
424 desc.set_owned_by(OwnedBy::Dma);
425
426 #[cfg(soc_internal_memory_cached)]
427 desc.writeback();
428
429 fence(Ordering::Release);
430 self.index = (idx + 1) % n;
431 }
432}
433
434#[derive(Clone, Copy, Debug, Eq, PartialEq)]
436pub enum TxError {
437 RingFull,
439 FrameTooLarge,
441}
442
443pub struct RDesRing<'a> {
447 descriptors: &'a mut [InternalMemory<RDes>],
448 buffers: &'a mut [InternalMemory<[u8; MAX_FRAME_SIZE]>],
449 index: usize,
450}
451
452impl<'a> RDesRing<'a> {
453 pub fn new(
455 descriptors: &'a mut [InternalMemory<RDes>],
456 buffers: &'a mut [InternalMemory<[u8; MAX_FRAME_SIZE]>],
457 ) -> Self {
458 assert!(!descriptors.is_empty());
459 assert_eq!(descriptors.len(), buffers.len());
460
461 let mut ring = Self {
462 descriptors,
463 buffers,
464 index: 0,
465 };
466 ring.reset();
467 ring
468 }
469
470 pub fn reset(&mut self) {
474 let n = self.descriptors.len();
475 for i in 0..n {
476 let next = self.descriptors[(i + 1) % n].as_ptr();
477 let buf_addr = self.buffers[i].as_ptr().cast::<u8>();
478
479 #[cfg(soc_internal_memory_cached)]
480 self.buffers[i].get_mut().invalidate();
481
482 let mut desc = self.descriptors[i].get_mut();
483 desc.rdes0.set(0);
484 desc.configure_buffer(MAX_FRAME_SIZE);
485 desc.set_buffer_addr(buf_addr);
486 desc.set_next_desc(next);
487 desc.set_owned_by(OwnedBy::Dma);
488 #[cfg(soc_internal_memory_cached)]
489 desc.writeback();
490 }
491 self.index = 0;
492 fence(Ordering::Release);
493 }
494
495 pub fn base_ptr(&self) -> *const RDes {
497 self.descriptors[0].as_ptr()
498 }
499
500 pub fn receive(&mut self) -> Option<&mut [u8]> {
507 loop {
508 let idx = self.index;
509
510 let len = {
514 let desc = self.descriptors[idx].get_ref();
515 #[cfg(soc_internal_memory_cached)]
516 desc.invalidate();
517 fence(Ordering::Acquire);
518 if desc.owned_by() != OwnedBy::Cpu {
519 return None;
520 }
521
522 let status = desc.rdes0.get();
523 let is_complete = desc.is_complete_frame();
524 let frame_len = desc.frame_len();
525
526 let checksum_bad = cfg_select! {
529 ethernet_rx_checksum_offload => desc.checksum_error(),
530 _ => false,
531 };
532
533 if status & RDES0_ES != 0 || !is_complete || checksum_bad {
534 None
535 } else {
536 let len = frame_len.saturating_sub(4);
538 if (MIN_RX_FRAME_SIZE..=MAX_FRAME_SIZE).contains(&len) {
539 Some(len)
540 } else {
541 None
542 }
543 }
544 };
545
546 let Some(len) = len else {
547 self.recycle_current();
548 continue;
549 };
550
551 #[cfg(soc_internal_memory_cached)]
552 self.buffers[idx].get_mut().invalidate();
553 fence(Ordering::Acquire);
554 return Some(&mut self.buffers[idx].get_mut().into_inner()[..len]);
555 }
556 }
557
558 pub fn pop(&mut self) {
562 self.recycle_current();
563 }
564
565 pub fn has_packet(&self) -> bool {
567 let desc = self.descriptors[self.index].get_ref();
568 #[cfg(soc_internal_memory_cached)]
569 desc.invalidate();
570 fence(Ordering::Acquire);
571 desc.owned_by() == OwnedBy::Cpu
572 }
573
574 fn recycle_current(&mut self) {
575 let idx = self.index;
576 let n = self.descriptors.len();
577 let mut desc = self.descriptors[idx].get_mut();
578 desc.set_rdes0(RDES0_OWN);
579 #[cfg(soc_internal_memory_cached)]
580 desc.writeback();
581 fence(Ordering::Release);
582 self.index = (idx + 1) % n;
583 }
584}