diff --git a/artiq/firmware/Cargo.lock b/artiq/firmware/Cargo.lock index ba552e36a..4adc90bc3 100644 --- a/artiq/firmware/Cargo.lock +++ b/artiq/firmware/Cargo.lock @@ -1,7 +1,3 @@ -[root] -name = "std_artiq" -version = "0.0.0" - [[package]] name = "alloc_list" version = "0.0.0" @@ -17,10 +13,16 @@ dependencies = [ "board 0.0.0", ] +[[package]] +name = "bitflags" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "board" version = "0.0.0" dependencies = [ + "bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "build_artiq 0.0.0", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -129,7 +131,7 @@ dependencies = [ [[package]] name = "managed" version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" +source = "git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1#629a6786a1cf1692015f464ed16c04eafa5cb8d1" [[package]] name = "proto" @@ -158,7 +160,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "logger_artiq 0.0.0", "proto 0.0.0", - "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=1e18c03)", + "smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=9914616)", "std_artiq 0.0.0", ] @@ -184,13 +186,17 @@ dependencies = [ [[package]] name = "smoltcp" version = "0.4.0" -source = "git+https://github.com/m-labs/smoltcp?rev=1e18c03#1e18c03d3452daf63040924d01c3ce63865939bd" +source = "git+https://github.com/m-labs/smoltcp?rev=9914616#9914616893c373de3fb52fcd2f06e0fffb4c8904" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", - "managed 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)", ] +[[package]] +name = "std_artiq" +version = "0.0.0" + [[package]] name = "walkdir" version = "1.0.3" @@ -211,6 +217,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] +"checksum bitflags 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5cde24d1b2e2216a726368b2363a273739c91f4e3eb4e0dd12d672d396ad989" "checksum byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c40977b0ee6b9885c9013cd41d9feffdd22deb3bb4dc3a71d901cc7a77de18c8" "checksum compiler_builtins 0.1.0 (git+https://github.com/rust-lang-nursery/compiler-builtins?rev=631b568)" = "" "checksum cslice 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0f8cb7306107e4b10e64994de6d3274bd08996a7c1322a27b86482392f96be0a" @@ -220,9 +227,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum libc 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "a51822fc847e7a8101514d1d44e354ba2ffa7d4c194dcab48870740e327cac70" "checksum log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ab83497bf8bf4ed2a74259c1c802351fcd67a65baa86394b6ba73c36f4838054" "checksum log_buffer 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ec57723b84bbe7bdf76aa93169c9b59e67473317c6de3a83cb2a0f8ccb2aa493" -"checksum managed 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b5d48e8c30a4363e2981fe4db20527f6ab0f32a243bbc75379dea5a64f60dae4" +"checksum managed 0.4.0 (git+https://github.com/m-labs/rust-managed.git?rev=629a6786a1cf1692015f464ed16c04eafa5cb8d1)" = "" "checksum rustc-cfg 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "56a596b5718bf5e059d59a30af12f7f462a152de147aa462b70892849ee18704" -"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=1e18c03)" = "" +"checksum smoltcp 0.4.0 (git+https://github.com/m-labs/smoltcp?rev=9914616)" = "" "checksum walkdir 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "dd7c16466ecc507c7cb5988db03e6eab4aaeab89a5c37a29251fcfd3ac9b7afe" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" diff --git a/artiq/firmware/runtime/Cargo.toml b/artiq/firmware/runtime/Cargo.toml index 637fd4025..d376677d7 100644 --- a/artiq/firmware/runtime/Cargo.toml +++ b/artiq/firmware/runtime/Cargo.toml @@ -37,6 +37,6 @@ features = ["alloc"] [dependencies.smoltcp] git = "https://github.com/m-labs/smoltcp" -rev = "1e18c03" +rev = "9914616" default-features = false -features = ["alloc", "log", "proto-tcp"] +features = ["alloc", "log", "socket-tcp"] diff --git a/artiq/firmware/runtime/ethmac.rs b/artiq/firmware/runtime/ethmac.rs index 638bfda2e..a19a13933 100644 --- a/artiq/firmware/runtime/ethmac.rs +++ b/artiq/firmware/runtime/ethmac.rs @@ -1,88 +1,158 @@ -use core::slice; +use core::{slice, fmt}; +use smoltcp::Result; +use smoltcp::phy::{self, DeviceCapabilities, Device}; + use board::{csr, mem}; -use smoltcp::Error; -use smoltcp::phy::{DeviceCapabilities, Device}; -const RX0_BASE: usize = mem::ETHMAC_BASE + 0x0000; -const RX1_BASE: usize = mem::ETHMAC_BASE + 0x0800; -const RX2_BASE: usize = mem::ETHMAC_BASE + 0x1000; -const RX3_BASE: usize = mem::ETHMAC_BASE + 0x1800; -const TX0_BASE: usize = mem::ETHMAC_BASE + 0x2000; -const TX1_BASE: usize = mem::ETHMAC_BASE + 0x2800; -const TX2_BASE: usize = mem::ETHMAC_BASE + 0x3000; -const TX3_BASE: usize = mem::ETHMAC_BASE + 0x3800; +const RX_SLOTS: usize = csr::ETHMAC_RX_SLOTS as usize; +const TX_SLOTS: usize = csr::ETHMAC_TX_SLOTS as usize; +const SLOT_SIZE: usize = csr::ETHMAC_SLOT_SIZE as usize; -const RX_BUFFERS: [*mut u8; 4] = [RX0_BASE as *mut u8, RX1_BASE as *mut u8, - RX2_BASE as *mut u8, RX3_BASE as *mut u8]; -const TX_BUFFERS: [*mut u8; 4] = [TX0_BASE as *mut u8, TX1_BASE as *mut u8, - TX2_BASE as *mut u8, TX3_BASE as *mut u8]; +fn next_rx_slot() -> Option { + unsafe { + if csr::ethmac::sram_writer_ev_pending_read() == 0 { + None + } else { + Some(csr::ethmac::sram_writer_slot_read() as usize) + } + } +} -pub struct EthernetDevice; +fn next_tx_slot() -> Option { + unsafe { + if csr::ethmac::sram_reader_ready_read() == 0 { + None + } else { + Some((csr::ethmac::sram_reader_slot_read() as usize + 1) % TX_SLOTS) + } + } +} -impl Device for EthernetDevice { - type RxBuffer = RxBuffer; - type TxBuffer = TxBuffer; +fn rx_buffer(slot: usize) -> *const u8 { + debug_assert!(slot < RX_SLOTS); + (mem::ETHMAC_BASE + SLOT_SIZE * slot) as _ +} + +fn tx_buffer(slot: usize) -> *mut u8 { + debug_assert!(slot < TX_SLOTS); + (mem::ETHMAC_BASE + SLOT_SIZE * (RX_SLOTS + slot)) as _ +} + +pub struct EthernetDevice(()); + +impl EthernetDevice { + pub unsafe fn new() -> EthernetDevice { + EthernetDevice(()) + } +} + +impl<'a> Device<'a> for EthernetDevice { + type RxToken = EthernetRxSlot; + type TxToken = EthernetTxSlot; fn capabilities(&self) -> DeviceCapabilities { let mut caps = DeviceCapabilities::default(); caps.max_transmission_unit = 1514; - caps.max_burst_size = Some(RX_BUFFERS.len()); + caps.max_burst_size = Some(RX_SLOTS); caps } - fn receive(&mut self, _timestamp: u64) -> Result { - unsafe { - if csr::ethmac::sram_writer_ev_pending_read() != 0 { - let slot = csr::ethmac::sram_writer_slot_read(); - let length = csr::ethmac::sram_writer_length_read(); - Ok(RxBuffer(slice::from_raw_parts(RX_BUFFERS[slot as usize], - length as usize))) - } else { - Err(Error::Exhausted) - } + fn receive(&mut self) -> Option<(Self::RxToken, Self::TxToken)> { + if let (Some(rx_slot), Some(tx_slot)) = (next_rx_slot(), next_tx_slot()) { + Some((EthernetRxSlot(rx_slot), EthernetTxSlot(tx_slot))) + } else { + None } } - fn transmit(&mut self, _timestamp: u64, length: usize) -> Result { - unsafe { - if csr::ethmac::sram_reader_ready_read() != 0 { - let slot = csr::ethmac::sram_reader_slot_read(); - let slot = (slot + 1) % (TX_BUFFERS.len() as u8); - csr::ethmac::sram_reader_slot_write(slot); - csr::ethmac::sram_reader_length_write(length as u16); - Ok(TxBuffer(slice::from_raw_parts_mut(TX_BUFFERS[slot as usize], - length as usize))) - } else { - Err(Error::Exhausted) - } + fn transmit(&mut self) -> Option { + if let Some(tx_slot) = next_tx_slot() { + Some(EthernetTxSlot(tx_slot)) + } else { + None } } } -pub struct RxBuffer(&'static [u8]); +pub struct EthernetRxSlot(usize); -impl AsRef<[u8]> for RxBuffer { - fn as_ref(&self) -> &[u8] { self.0 } -} - -impl Drop for RxBuffer { - fn drop(&mut self) { - unsafe { csr::ethmac::sram_writer_ev_pending_write(1) } +impl phy::RxToken for EthernetRxSlot { + fn consume(self, _timestamp: u64, f: F) -> Result + where F: FnOnce(&[u8]) -> Result + { + unsafe { + let length = csr::ethmac::sram_writer_length_read() as usize; + let result = f(slice::from_raw_parts(rx_buffer(self.0), length)); + csr::ethmac::sram_writer_ev_pending_write(1); + result + } } } -pub struct TxBuffer(&'static mut [u8]); +pub struct EthernetTxSlot(usize); -impl AsRef<[u8]> for TxBuffer { - fn as_ref(&self) -> &[u8] { self.0 } -} +impl phy::TxToken for EthernetTxSlot { + fn consume(self, _timestamp: u64, length: usize, f: F) -> Result + where F: FnOnce(&mut [u8]) -> Result + { + debug_assert!(length < SLOT_SIZE); -impl AsMut<[u8]> for TxBuffer { - fn as_mut(&mut self) -> &mut [u8] { self.0 } -} - -impl Drop for TxBuffer { - fn drop(&mut self) { - unsafe { csr::ethmac::sram_reader_start_write(1) } + unsafe { + let result = f(slice::from_raw_parts_mut(tx_buffer(self.0), length))?; + csr::ethmac::sram_reader_slot_write(self.0 as u8); + csr::ethmac::sram_reader_length_write(length as u16); + csr::ethmac::sram_reader_start_write(1); + Ok(result) + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Default)] +pub struct EthernetStatistics { + rx_preamble_errors: u32, + rx_crc_errors: u32, + rx_dropped: u32, +} + +impl EthernetStatistics { + pub fn new() -> Self { + unsafe { + EthernetStatistics { + rx_preamble_errors: csr::ethmac::preamble_errors_read(), + rx_crc_errors: csr::ethmac::crc_errors_read(), + rx_dropped: csr::ethmac::sram_writer_errors_read(), + } + } + } + + pub fn update(&mut self) -> Option { + let old = self.clone(); + *self = Self::new(); + + let diff = EthernetStatistics { + rx_preamble_errors: self.rx_preamble_errors.wrapping_sub(old.rx_preamble_errors), + rx_crc_errors: self.rx_crc_errors.wrapping_sub(old.rx_crc_errors), + rx_dropped: self.rx_dropped.wrapping_sub(old.rx_dropped), + }; + if diff == EthernetStatistics::default() { + None + } else { + Some(diff) + } + } +} + +impl fmt::Display for EthernetStatistics { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + if self.rx_preamble_errors > 0 { + write!(f, " rx preamble errors: {}", self.rx_preamble_errors)? + } + if self.rx_crc_errors > 0 { + write!(f, " rx crc errors: {}", self.rx_crc_errors)? + } + if self.rx_dropped > 0 { + write!(f, " rx dropped: {}", self.rx_dropped)? + } + Ok(()) } } diff --git a/artiq/firmware/runtime/lib.rs b/artiq/firmware/runtime/lib.rs index 242f9f5b2..9fdbf95c4 100644 --- a/artiq/firmware/runtime/lib.rs +++ b/artiq/firmware/runtime/lib.rs @@ -21,7 +21,6 @@ extern crate amp; #[cfg(has_drtio)] extern crate drtioaux; -use std::boxed::Box; use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr}; use proto::{mgmt_proto, analyzer_proto, moninj_proto, rpc_proto, session_proto, kernel_proto}; use amp::{mailbox, rpc_queue}; @@ -112,12 +111,12 @@ fn startup() { // print!("\x1b[37m[{:6}.{:06}s]\n{}\x1b[0m", seconds, micros, printer) // } - let net_device = ethmac::EthernetDevice; + let net_device = unsafe { ethmac::EthernetDevice::new() }; // let net_device = smoltcp::phy::EthernetTracer::new(net_device, _net_trace_writer); - let arp_cache = smoltcp::iface::SliceArpCache::new([Default::default(); 8]); + let mut neighbor_cache_storage = [None; 8]; + let neighbor_cache = smoltcp::iface::NeighborCache::new(&mut neighbor_cache_storage[..]); let mut interface = smoltcp::iface::EthernetInterface::new( - Box::new(net_device), Box::new(arp_cache) as Box, - hardware_addr, [IpCidr::new(protocol_addr, 0)], None); + net_device, neighbor_cache, hardware_addr, [IpCidr::new(protocol_addr, 0)], None); let mut scheduler = sched::Scheduler::new(); let io = scheduler.io(); diff --git a/conda/artiq-dev/meta.yaml b/conda/artiq-dev/meta.yaml index 820fce1a4..d2f2276bb 100644 --- a/conda/artiq-dev/meta.yaml +++ b/conda/artiq-dev/meta.yaml @@ -15,7 +15,7 @@ requirements: - python >=3.5.3,<3.6 - setuptools 33.1.1 - migen 0.5 - - misoc 0.6 + - misoc 0.7 - jesd204b 0.3 - binutils-or1k-linux >=2.27 - llvm-or1k