diff --git a/src/eth/rx.rs b/src/eth/rx.rs index 9022ff9f..940f28b9 100644 --- a/src/eth/rx.rs +++ b/src/eth/rx.rs @@ -2,6 +2,8 @@ use core::ops::Deref; use crate::{register, register_bit, register_bits, regs::*}; use super::MTU; +use crate::cortex_a9::asm; + #[derive(Debug)] pub enum Error { HrespNotOk, @@ -67,6 +69,8 @@ impl<'a> DescList<'a> { DescWord1::zeroed() ); } + // Ensure descriptors get written before they are read. + asm::dmb(); DescList { // Shorten the list of descriptors to the required number. @@ -86,6 +90,7 @@ impl<'a> DescList<'a> { if entry.word0.read().used() { let word1 = entry.word1.read(); let len = word1.frame_length_lsbs().into(); + asm::dmb(); let buffer = &mut self.buffers[self.next][0..len]; self.next += 1; @@ -113,6 +118,9 @@ pub struct PktRef<'a> { impl<'a> Drop for PktRef<'a> { fn drop(&mut self) { + // Ensure that any buffer reads have finished before we + // release the buffer to the hardware. + asm::dmb(); self.entry.word0.modify(|_, w| w.used(false)); } } diff --git a/src/eth/tx.rs b/src/eth/tx.rs index 4bf0185c..56853403 100644 --- a/src/eth/tx.rs +++ b/src/eth/tx.rs @@ -1,5 +1,6 @@ use core::ops::{Deref, DerefMut}; use crate::{register, register_bit, register_bits, regs::*}; +use crate::cortex_a9::asm; use super::{MTU, regs}; /// Descriptor entry @@ -62,6 +63,8 @@ impl<'a> DescList<'a> { .last_buffer(true) ); } + // Ensure the descriptor words get written before they are read. + asm::dsb(); DescList { // Shorten the list of descriptors to the required number. @@ -79,8 +82,8 @@ impl<'a> DescList<'a> { let list_len = self.list.len(); let entry = &mut self.list[self.next]; if entry.word1.read().used() { - entry.word1.modify(|_, w| w.length(length as u16)); let buffer = &mut self.buffers[self.next][0..length]; + entry.word1.modify(|_, w| w.length(length as u16)); self.next += 1; if self.next >= list_len { @@ -105,7 +108,14 @@ pub struct PktRef<'a> { impl<'a> Drop for PktRef<'a> { fn drop(&mut self) { + // Ensure that all writes to the buffer have finished before + // they are read again. + asm::dmb(); self.entry.word1.modify(|_, w| w.used(false)); + // Ensure that the descriptor write has finished before it is + // read again, and (by DSB, not just DMB) that it has been + // written before the register access. + asm::dsb(); if ! self.regs.tx_status.read().tx_go() { self.regs.net_ctrl.modify(|_, w| w.start_tx(true)