@@ -10,7 +10,9 @@ use defmt_rtt as _;
1010use panic_probe as _;
1111
1212use stm32_eth:: {
13+ dma:: { RxRingEntry , TxRingEntry } ,
1314 hal:: { gpio:: GpioExt , rcc:: Clocks } ,
15+ stm32:: MPU ,
1416 PartsIn ,
1517} ;
1618
@@ -25,12 +27,79 @@ use stm32_eth::hal::rcc::RccExt;
2527#[ allow( unused) ]
2628fn main ( ) { }
2729
30+ /// Mark RAM as non-cachable. Also validate that the RX ring
31+ /// and TX ring are within them.
32+ ///
33+ /// On cores without cache (e.g. M33), this function is a no-op. For cores
34+ /// with a cache (e.g. M7), this is necessary to ensure that the data read
35+ /// by the ethernet DMA is the data that the core actually wrote.
36+ fn mpu_mark_noncachable ( mpu : MPU , rx_ring : & [ RxRingEntry ] , tx_ring : & [ TxRingEntry ] ) {
37+ let start = 0x20000000u32 ;
38+ let len = 32u32 * 1024 ;
39+ let range = start as usize ..( start as usize + len as usize ) ;
40+
41+ let rx_start = rx_ring. as_ptr ( ) ;
42+ let rx_first_addr = rx_start. addr ( ) ;
43+ let rx_last_addr = unsafe { rx_start. add ( rx_ring. len ( ) + 1 ) } . addr ( ) - 1 ;
44+ assert ! (
45+ range. contains( & rx_first_addr) ,
46+ "RX ring starts before non-cacheable region"
47+ ) ;
48+
49+ assert ! (
50+ range. contains( & rx_last_addr) ,
51+ "RX ring ends after non-cacheable region"
52+ ) ;
53+
54+ let tx_start = tx_ring. as_ptr ( ) ;
55+ let tx_first_addr = tx_start. addr ( ) ;
56+ let tx_last_addr = unsafe { rx_start. add ( tx_ring. len ( ) + 1 ) } . addr ( ) - 1 ;
57+ assert ! (
58+ range. contains( & tx_first_addr) ,
59+ "TX ring starts before non-cacheable region"
60+ ) ;
61+
62+ assert ! (
63+ range. contains( & tx_last_addr) ,
64+ "TX ring ends after non-cacheable region"
65+ ) ;
66+
67+ let size_field = len. trailing_zeros ( ) - 1 ;
68+
69+ unsafe {
70+ mpu. ctrl . write ( 0 ) ;
71+ let region = 0 ;
72+ mpu. rnr . write ( region) ;
73+ mpu. rbar . write ( start | 1 << 4 | region) ;
74+
75+ mpu. rasr . write (
76+ ( 1 << 28 ) // XN
77+ | ( 0b011 << 24 ) // AP = full access
78+ | ( 0b001 << 19 ) // TEX = 001 \
79+ | ( 0 << 17 ) // C = 0 } -> Normal, Non-cacheable
80+ | ( 0 << 16 ) // B = 0 /
81+ | ( size_field << 1 ) // SIZE
82+ | ( 1 << 0 ) , // ENABLE
83+ ) ;
84+ }
85+
86+ cortex_m:: asm:: dsb ( ) ;
87+ cortex_m:: asm:: isb ( ) ;
88+ }
89+
2890/// Setup the clocks and return clocks and a GPIO struct that
2991/// can be used to set up all of the pins.
3092///
3193/// This configures HCLK to be at least 25 MHz, which is the minimum required
3294/// for ethernet operation to be valid.
33- pub fn setup_peripherals ( p : stm32_eth:: stm32:: Peripherals ) -> ( Clocks , Gpio , PartsIn ) {
95+ pub fn setup_peripherals_and_cache (
96+ p : stm32_eth:: stm32:: Peripherals ,
97+ mpu : MPU ,
98+ rx_ring : & [ RxRingEntry ] ,
99+ tx_ring : & [ TxRingEntry ] ,
100+ ) -> ( Clocks , Gpio , PartsIn ) {
101+ mpu_mark_noncachable ( mpu, rx_ring, tx_ring) ;
102+
34103 let ethernet = PartsIn {
35104 dma : p. ETHERNET_DMA ,
36105 mac : p. ETHERNET_MAC ,
0 commit comments