diff --git a/Cargo.lock b/Cargo.lock index a7c9789b..512671c6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -187,9 +187,9 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.85" +version = "0.1.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f934833b4b7233644e5848f235df3f57ed8c80f1528a26c3dfa13d2147fa056" +checksum = "644dd749086bf3771a2fbc5f256fdb982d53f011c7d5d560304eafeecebce79d" dependencies = [ "proc-macro2", "quote", @@ -294,9 +294,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" @@ -326,9 +326,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.2.10" +version = "1.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" +checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda" dependencies = [ "jobserver", "libc", @@ -357,9 +357,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.27" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" +checksum = "8acebd8ad879283633b343856142139f2da2317c96b05b4dd6181c61e2480184" dependencies = [ "clap_builder", "clap_derive", @@ -367,9 +367,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.27" +version = "4.5.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" +checksum = "f6ba32cbda51c7e1dfd49acc1457ba1a7dec5b64fe360e828acb13ca8dc9c2f9" dependencies = [ "anstream", "anstyle", @@ -379,9 +379,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.24" +version = "4.5.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b755194d6389280185988721fffba69495eed5ee9feeee9a599b53db80318c" +checksum = "bf4ced95c6f4a675af3da73304b9ac4ed991640c36374e4b46795c49e17cf1ed" dependencies = [ "heck", "proc-macro2", @@ -409,9 +409,9 @@ checksum = "5b63caa9aa9397e2d9480a9b13673856c78d8ac123288526c37d7839f2a86990" [[package]] name = "compiler_builtins" -version = "0.1.144" +version = "0.1.146" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d18a7b7b5a56aa131e62314b4d862c9f6aa2860f615f3770094ec9064d7ec572" +checksum = "a97117b1434b79833f39a5fabdf82f890bd98c1988334dea1cb67f7e627fa311" dependencies = [ "rustc-std-workspace-core", ] @@ -761,7 +761,19 @@ checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a49c392881ce6d5c3b8cb70f98717b7c07aabbdff06687b9030dbfbe2725f8" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.13.3+wasi-0.2.2", + "windows-targets", ] [[package]] @@ -1040,9 +1052,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.9" +version = "0.17.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" +checksum = "183b3088984b400f4cfac3620d5e076c84da5364016b4f49473de574b2586235" dependencies = [ "console", "number_prefix", @@ -1332,9 +1344,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +checksum = "220e4f05ad4a218192533b300327f5150e809b54c4ec83b5a1d91833601811b9" dependencies = [ "cc", "libc", @@ -1457,9 +1469,9 @@ dependencies = [ [[package]] name = "miniz_oxide" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8402cab7aefae129c6977bb0ff1b8fd9a04eb5b51efc50a70bea51cda0c7924" +checksum = "b3b1c9bd4fe1f0f8b387f6eb9eb3b4a1aa26185e5750efb9140301703f62cd1b" dependencies = [ "adler2", ] @@ -1511,9 +1523,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.20.2" +version = "1.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" +checksum = "945462a4b81e43c4e3ba96bd7b49d834c6f61198356aa858733bc4acf3cbe62e" [[package]] name = "openssl-probe" @@ -1523,9 +1535,9 @@ checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" [[package]] name = "openssl-sys" -version = "0.9.104" +version = "0.9.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45abf306cbf99debc8195b66b7346498d7b10c210de50418b5ccd7ceba08c741" +checksum = "8b22d5b84be05a8d6947c7cb71f7c849aa0f112acd4bf51c2a7c1c988ac0a9dc" dependencies = [ "cc", "libc", @@ -1696,7 +1708,7 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom", + "getrandom 0.2.15", ] [[package]] @@ -1903,9 +1915,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -2031,13 +2043,13 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.15.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8a559c81686f576e8cd0290cd2a24a2a9ad80c98b3478856500fcbd7acd704" +checksum = "38c246215d7d24f48ae091a2902398798e05d978b24315d6efbc00ede9a8bb91" dependencies = [ "cfg-if", "fastrand", - "getrandom", + "getrandom 0.3.1", "once_cell", "rustix", "windows-sys", @@ -2135,9 +2147,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ed1f98e3fdc28d6d910e6737ae6ab1a93bf1985935a1193e68f93eeb68d24e" +checksum = "cd87a5cdd6ffab733b2f74bc4fd7ee5fff6634124999ac278c35fc78c6120148" dependencies = [ "serde", "serde_spanned", @@ -2156,9 +2168,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.22" +version = "0.22.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae48d6208a266e853d946088ed816055e556cc6028c5e8e2b84d9fa5dd7c7f5" +checksum = "17b4795ff5edd201c7cd6dca065ae59972ce77d1b80fa0a84d94950ece7d1474" dependencies = [ "indexmap", "serde", @@ -2270,9 +2282,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.12.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" +checksum = "ced87ca4be083373936a67f8de945faa23b6b42384bd5b64434850802c6dccd0" dependencies = [ "bytemuck", ] @@ -2307,9 +2319,9 @@ dependencies = [ [[package]] name = "wait-timeout" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +checksum = "09ac3b126d3914f9849036f826e054cbabdc8519970b8998ddaf3b5bd3c65f11" dependencies = [ "libc", ] @@ -2330,6 +2342,15 @@ version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +[[package]] +name = "wasi" +version = "0.13.3+wasi-0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26816d2e1a4a36a2940b96c5296ce403917633dff8f3440e9b236ed6f6bacad2" +dependencies = [ + "wit-bindgen-rt", +] + [[package]] name = "wasm-bindgen" version = "0.2.100" @@ -2525,9 +2546,9 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "winnow" -version = "0.6.25" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad699df48212c6cc6eb4435f35500ac6fd3b9913324f938aea302022ce19d310" +checksum = "59690dea168f2198d1a3b0cac23b8063efcd11012f10ae4698f284808c8ef603" dependencies = [ "memchr", ] @@ -2538,6 +2559,15 @@ version = "0.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d135d17ab770252ad95e9a872d365cf3090e3be864a34ab46f48555993efc904" +[[package]] +name = "wit-bindgen-rt" +version = "0.33.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3268f3d866458b787f390cf61f4bbb563b922d091359f9608842999eaee3943c" +dependencies = [ + "bitflags 2.8.0", +] + [[package]] name = "write16" version = "1.0.0" @@ -2733,6 +2763,22 @@ dependencies = [ "yggdrasil-abi", ] +[[package]] +name = "ygg_driver_net_stmmac" +version = "0.1.0" +dependencies = [ + "bytemuck", + "device-api", + "device-tree", + "libk", + "libk-mm", + "libk-util", + "log", + "tock-registers", + "ygg_driver_net_core", + "yggdrasil-abi", +] + [[package]] name = "ygg_driver_nvme" version = "0.1.0" @@ -2931,6 +2977,7 @@ dependencies = [ "ygg_driver_net_igbe", "ygg_driver_net_loopback", "ygg_driver_net_rtl81xx", + "ygg_driver_net_stmmac", "ygg_driver_nvme", "ygg_driver_pci", "ygg_driver_usb", diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index e2f4f206..055cd71b 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -60,6 +60,7 @@ kernel-arch-aarch64.workspace = true [target.'cfg(target_arch = "riscv64")'.dependencies] device-tree.workspace = true kernel-arch-riscv64.workspace = true +ygg_driver_net_stmmac.path = "driver/net/stmmac" [target.'cfg(target_arch = "x86_64")'.dependencies] yboot-proto.workspace = true @@ -91,6 +92,7 @@ kernel-arch-aarch64.workspace = true kernel-arch-riscv64.workspace = true ygg_driver_acpi.path = "driver/acpi" +ygg_driver_net_stmmac.path = "driver/net/stmmac" [features] default = ["fb_console"] diff --git a/kernel/driver/net/core/src/ethernet.rs b/kernel/driver/net/core/src/ethernet.rs index a926804a..fa3a8ceb 100644 --- a/kernel/driver/net/core/src/ethernet.rs +++ b/kernel/driver/net/core/src/ethernet.rs @@ -70,6 +70,7 @@ pub fn handle(packet: L2Packet) { match ty { EtherType::ARP => l3::arp::handle_packet(packet), EtherType::IPV4 => l3::ip::handle_v4_packet(packet), + EtherType(0x0027) => (), p => { log::debug!( "Unrecognized L2 protocol: {:#06x}", diff --git a/kernel/driver/net/stmmac/Cargo.toml b/kernel/driver/net/stmmac/Cargo.toml new file mode 100644 index 00000000..7bc316eb --- /dev/null +++ b/kernel/driver/net/stmmac/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "ygg_driver_net_stmmac" +version = "0.1.0" +edition = "2024" + +[dependencies] +device-tree.workspace = true +device-api.workspace = true +yggdrasil-abi.workspace = true +libk-mm.workspace = true +libk-util.workspace = true +libk.workspace = true +ygg_driver_net_core.path = "../core" + +tock-registers.workspace = true +log.workspace = true +bytemuck.workspace = true diff --git a/kernel/driver/net/stmmac/src/lib.rs b/kernel/driver/net/stmmac/src/lib.rs new file mode 100644 index 00000000..40780076 --- /dev/null +++ b/kernel/driver/net/stmmac/src/lib.rs @@ -0,0 +1,344 @@ +#![no_std] + +use core::mem::MaybeUninit; + +use alloc::{sync::Arc, vec::Vec}; +use device_api::{ + clock::{ClockHandle, ResetHandle}, + device::{Device, DeviceInitContext}, + dma::DmaAllocator, + interrupt::{FullIrq, InterruptHandler, IrqVector}, +}; +use device_tree::driver::{device_tree_driver, util::read_mac_address, Node, ProbeContext}; +use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error}; +use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; +use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; +use regs::{ + dma::{DMACiCR, DMACiIER, DMACiSR, DMACiTXCR, DMAC0RXCR, DMAMR, DMASBMR}, + mac::{ + MACAiHR, MACAiLR, MACCR, MACIER, MACISR, MACPFR, MACPHYCSR, MACQ0TXFCR, MACRXFCR, MACRXQC0R, + }, + mtl::{MTLRXQiOMR, MTLTXQiOMR, MTLOMR}, + Regs, +}; +use ring::{RxDescriptor, RxRing, TxDescriptor, TxRing}; +use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; +use ygg_driver_net_core::{ + interface::{NetworkDevice, NetworkInterfaceType}, + RxPacket, +}; +use yggdrasil_abi::net::{ + link::{EthernetLinkState, LinkState}, + MacAddress, +}; + +extern crate alloc; + +pub mod regs; +pub mod ring; + +struct Inner { + regs: IrqSafeSpinlock>, + + tx_ring: IrqSafeSpinlock, + rx_ring: IrqSafeSpinlock, +} + +struct Stmmac { + base: PhysicalAddress, + dma: OneTimeInit>, + mac: MacAddress, + resets: Vec, + clocks: Vec, + irq: FullIrq, + + inner: OneTimeInit, + iface_id: OneTimeInit, +} + +impl Stmmac { + pub fn start_xmit(&self, frame: DmaBuffer<[u8]>) -> Result<(), Error> { + let inner = self.inner.get(); + let regs = inner.regs.lock(); + + let mut tx_ring = inner.tx_ring.lock(); + let index = tx_ring.push_xmit(frame)?; + let ring_pos = tx_ring + .buffer_base() + .add(size_of::() * index) + .try_into_u32() + .unwrap(); + + regs.DMA.DMAC0TXDTPR.set(ring_pos); + + Ok(()) + } +} + +impl InterruptHandler for Stmmac { + fn handle_irq(self: Arc, _vector: IrqVector) -> bool { + let inner = self.inner.get(); + let regs = inner.regs.lock(); + let mac_isr = regs.MAC.MACISR.extract(); + let dma0_sr = regs.DMA.DMAC0SR.extract(); + + if mac_isr.matches_all(MACISR::RGSMIIIS::SET) { + let macphycsr = regs.MAC.MACPHYCSR.extract(); + let state = if macphycsr.matches_all(MACPHYCSR::LNKSTS::Up) { + "up" + } else { + "down" + }; + let mode = if macphycsr.matches_all(MACPHYCSR::LNKMOD::FullDuplex) { + "full-duplex" + } else { + "half-duplex" + }; + log::info!("RGMII link status update"); + log::info!("Link state: link={state}, mode={mode}"); + } + + if dma0_sr.matches_all(DMACiSR::TI::SET) { + regs.DMA.DMAC0SR.modify(DMACiSR::TI::SET); + inner.tx_ring.lock().consume().ok(); + } + if dma0_sr.matches_all(DMACiSR::RI::SET) { + let dma = self.dma.get(); + regs.DMA.DMAC0SR.modify(DMACiSR::RI::SET); + let iface = *self.iface_id.get(); + let mut rx_ring = inner.rx_ring.lock(); + rx_ring + .consume(dma.as_ref(), |packet| { + let packet = RxPacket::new(packet, 0, iface); + ygg_driver_net_core::receive_packet(packet).ok(); + }) + .ok(); + } + + true + } +} + +impl Device for Stmmac { + unsafe fn init(self: Arc, cx: DeviceInitContext) -> Result<(), Error> { + // TODO this is a dirty fix for the device tree double initialization problem + if self.dma.is_initialized() { + return Err(Error::AlreadyExists); + } + let dma = self.dma.init(cx.dma_allocator.clone()); + + let intc = external_interrupt_controller()?; + + intc.register_irq(self.irq.irq, self.irq.options, self.clone())?; + + let tx_ring_capacity = 32; + let rx_ring_capacity = 32; + + log::info!("dwmac: setup {:#x}, mac={}", self.base, self.mac); + + for clock in self.clocks.iter() { + clock.enable()?; + } + for reset in self.resets.iter() { + reset.deassert()?; + } + + let regs = unsafe { DeviceMemoryIo::::map(self.base, Default::default()) }?; + + // DMA initialization + + // Perform a software reset + regs.DMA.DMAMR.modify(DMAMR::SWR::SET); + + let mut timeout = 100000; + while timeout > 0 && regs.DMA.DMAMR.matches_all(DMAMR::SWR::SET) { + core::hint::spin_loop(); + timeout -= 1; + } + if timeout == 0 { + log::warn!("dwmac: reset timeout"); + return Err(Error::TimedOut); + } + + // Setup DMA parameters + // TODO get these params from device tree + regs.DMA.DMASBMR.write( + DMASBMR::FB::SET + + DMASBMR::AAL::SET + + DMASBMR::BLEN256::SET + + DMASBMR::BLEN128::SET + + DMASBMR::BLEN64::SET + + DMASBMR::BLEN32::SET + + DMASBMR::EN_LPI::SET + + DMASBMR::WR_OSR_LMT.val(3) + + DMASBMR::RD_OSR_LMT.val(3), + ); + + // Setup DMA Tx/Rx rings + let tx_ring = TxRing::with_capacity(dma.as_ref(), tx_ring_capacity)?; + let rx_ring = RxRing::with_capacity(dma.as_ref(), rx_ring_capacity)?; + let tx_ring_base = tx_ring.buffer_base().try_into_u32().unwrap(); + let rx_ring_base = rx_ring.buffer_base().try_into_u32().unwrap(); + + regs.DMA.DMAC0TXRLR.set(tx_ring_capacity as u32 - 1); + regs.DMA.DMAC0TXDLAR.set(tx_ring_base); + regs.DMA.DMAC0TXDTPR.set(tx_ring_base); + + regs.DMA.DMAC0RXRLR.set(rx_ring_capacity as u32 - 1); + regs.DMA.DMAC0RXDLAR.set(rx_ring_base); + regs.DMA + .DMAC0RXDTPR + .set(rx_ring_base + (rx_ring_capacity * size_of::()) as u32); + + // Setup DMA maximum segmen size, Rx buffer size + max burst len + regs.DMA + .DMAC0CR + .write(DMACiCR::PBLX8::CLEAR + DMACiCR::MSS.val(1024)); + regs.DMA.DMAC0TXCR.write(DMACiTXCR::TXPBL.val(256)); + regs.DMA + .DMAC0RXCR + .write(DMAC0RXCR::RBSZ.val(4096) + DMAC0RXCR::RXPBL.val(256)); + + // Enable DMA interrupts + // TODO enable abnormal interrupts to handle errors properly + regs.DMA.DMAC0IER.write( + DMACiIER::NIE::SET + + DMACiIER::RIE::SET + + DMACiIER::TIE::SET + + DMACiIER::RBUE::SET + + DMACiIER::RSE::SET, + ); + + // Start Tx/Rx DMAs + regs.DMA.DMAC0TXCR.modify(DMACiTXCR::ST::SET); + regs.DMA.DMAC0RXCR.modify(DMAC0RXCR::SR::SET); + + // MTL initialization + + regs.MTL + .MTLOMR + .write(MTLOMR::RAA::AlgStrictPrio + MTLOMR::SCHALG::AlgStrictPrio); + + // TODO get TQS, RQS from device tree + regs.MTL + .MTLTXQ0OMR + .write(MTLTXQiOMR::TSF::SET + MTLTXQiOMR::TQS.val(1) + MTLTXQiOMR::TXQEN::Enable); + regs.MTL.MTLRXQ0OMR.write( + MTLRXQiOMR::RQS.val(1) + + MTLRXQiOMR::DIS_TCP_EF::SET + + MTLRXQiOMR::RSF::SET + + MTLRXQiOMR::FEP::SET + + MTLRXQiOMR::FUP::SET, + ); + + // MAC initialization + + // Setup the MAC address + let mac_bytes: [u8; 6] = self.mac.into(); + regs.MAC.MACA0HR.write( + MACAiHR::AE::SET + + MACAiHR::ADDR4.val(mac_bytes[4] as u32) + + MACAiHR::ADDR5.val(mac_bytes[5] as u32), + ); + regs.MAC.MACA0LR.write( + MACAiLR::ADDR0.val(mac_bytes[0] as u32) + + MACAiLR::ADDR1.val(mac_bytes[1] as u32) + + MACAiLR::ADDR2.val(mac_bytes[2] as u32) + + MACAiLR::ADDR3.val(mac_bytes[3] as u32), + ); + + // TODO proper filtering, don't use promiscuous mode all the time + regs.MAC.MACPFR.write(MACPFR::PR::SET + MACPFR::RA::SET); + + // Setup Tx/Rx flow control, enable Rx queue 0 + regs.MAC.MACQ0TXFCR.write(MACQ0TXFCR::TFE::SET); + regs.MAC.MACRXFCR.write(MACRXFCR::RFE::SET); + regs.MAC.MACRXQC0R.write(MACRXQC0R::RXQ0EN::Enable); + + // Setup MAC-level interrupts + regs.MAC + .MACIER + .write(MACIER::TXSTSIE::SET + MACIER::RXSTSIE::SET + MACIER::RGSMIIIE::SET); + + // Setup link information + regs.MAC + .MACCR + .modify(MACCR::PS::Ps1000Mbps + MACCR::FES::Fes100Mbps + MACCR::DM::FullDuplex); + + // Start Tx/Rx + regs.MAC.MACCR.modify(MACCR::TE::SET + MACCR::RE::SET); + + // Apply PHY settings + regs.MAC + .MACPHYCSR + .modify(MACPHYCSR::LUD::SET + MACPHYCSR::TC::SET); + + self.inner.init(Inner { + regs: IrqSafeSpinlock::new(regs), + + tx_ring: IrqSafeSpinlock::new(tx_ring), + rx_ring: IrqSafeSpinlock::new(rx_ring), + }); + + let iface = + ygg_driver_net_core::register_interface(NetworkInterfaceType::Ethernet, self.clone()); + self.iface_id.init(iface.id()); + + intc.enable_irq(self.irq.irq)?; + + Ok(()) + } + + fn display_name(&self) -> &str { + "Synopsys DesignWare Ethernet MAC" + } +} + +impl NetworkDevice for Stmmac { + fn allocate_transmit_buffer(&self, len: usize) -> Result]>, Error> { + DmaBuffer::new_uninit_slice(&**self.dma.get(), len) + } + + fn transmit_buffer(&self, buffer: DmaBuffer<[u8]>) -> Result<(), Error> { + self.start_xmit(buffer) + } + + fn packet_prefix_size(&self) -> usize { + 0 + } + + fn read_hardware_address(&self) -> MacAddress { + self.mac + } + + fn link_state(&self) -> LinkState { + // TODO + LinkState::Ethernet(EthernetLinkState::Down) + } +} + +device_tree_driver! { + compatible: ["starfive,jh7110-dwmac"], + driver: { + fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + let base = node.map_base(context, 0)?; + let clocks = node.clocks()?.collect(); + let resets = node.resets()?.collect(); + let mac = read_mac_address(node)?; + // TODO named_interrupt() + let irq = node.interrupt(0)?; + + Some(Arc::new(Stmmac { + base, + clocks, + resets, + mac, + irq, + + dma: OneTimeInit::new(), + inner: OneTimeInit::new(), + iface_id: OneTimeInit::new(), + })) + } + } +} diff --git a/kernel/driver/net/stmmac/src/regs/dma.rs b/kernel/driver/net/stmmac/src/regs/dma.rs new file mode 100644 index 00000000..5d2d53eb --- /dev/null +++ b/kernel/driver/net/stmmac/src/regs/dma.rs @@ -0,0 +1,243 @@ +use tock_registers::{register_bitfields, register_structs, registers::ReadWrite}; + +register_bitfields! { + u32, + pub DMAMR [ + /// Interrupt mode + INTM OFFSET(16) NUMBITS(2) [], + /// Transmit priority + TXPR OFFSET(11) NUMBITS(1) [], + /// Descriptor posted write + DSPW OFFSET(8) NUMBITS(1) [], + /// Transmit arbitration algorithm + TAA OFFSET(2) NUMBITS(3) [], + /// Software reset + /// + /// When this bit is set, the MAC and the DMA controllers are reset. This bit is cleared + /// automatically when the MAC/DMA reset completes. + SWR OFFSET(0) NUMBITS(1) [], + ], + + pub DMASBMR [ + /// Enable Low Power interface + EN_LPI OFFSET(31) NUMBITS(1) [], + /// Unlock on Magic packet or Remote Wakeup packet + LPI_XIT_PKT OFFSET(30) NUMBITS(1) [], + /// AXI maximum write outstanding request limit + /// + /// Maximum outstanding requests = WR_OSR_LMT + 1 + WR_OSR_LMT OFFSET(24) NUMBITS(2) [], + /// AXI maximum reaad outstanding request limit + /// + /// Maximum outstanding requests = RD_OSR_LMT + 1 + RD_OSR_LMT OFFSET(16) NUMBITS(2) [], + /// 1 Kbyte boundary crossing enable for the AXI master + /// + /// If set, the burst transfers performed by the AXI master do not cross 1 Kbyte boundary + /// If not, the transfers do not cross 4 Kbyte boundary + ONEKBBE OFFSET(13) NUMBITS(1) [], + /// Address aligned bursts + /// + /// If set, the master performs addres-aligned burst transfers on read and write channels + AAL OFFSET(12) NUMBITS(1) [], + /// Automatic AXI LPI enable + /// + /// When set, enables AXI master to enter into LPI state when there is no activity on the + /// Ethernet peripheral for a number of clock cycles programmed in ETH_DMALPIEI register. + AALE OFFSET(10) NUMBITS(1) [], + /// AXI burst length 256 + BLEN256 OFFSET(7) NUMBITS(1) [], + /// AXI burst length 128 + BLEN128 OFFSET(6) NUMBITS(1) [], + /// AXI burst length 64 + BLEN64 OFFSET(5) NUMBITS(1) [], + /// AXI burst length 32 + BLEN32 OFFSET(4) NUMBITS(1) [], + /// AXI burst length 16 + BLEN16 OFFSET(3) NUMBITS(1) [], + /// AXI burst length 8 + BLEN8 OFFSET(2) NUMBITS(1) [], + /// AXI burst length 4 + BLEN4 OFFSET(1) NUMBITS(1) [], + /// Fixed burst length + FB OFFSET(0) NUMBITS(1) [], + ], + + pub DMACiCR [ + /// Descriptor skip length + DSL OFFSET(18) NUMBITS(1) [], + /// 8xPBL mode + PBLX8 OFFSET(16) NUMBITS(1) [], + /// Maximum segment size + MSS OFFSET(0) NUMBITS(14) [], + ], + + pub DMACiTXCR [ + /// Tx QOS + TQOS OFFSET(24) NUMBITS(4) [], + /// Transmit programmable burst length + TXPBL OFFSET(16) NUMBITS(6) [], + /// Ignore PBL requirement + IPBL OFFSET(15) NUMBITS(1) [], + /// TCP segmentation enabled + TSE OFFSET(12) NUMBITS(1) [], + /// Operate on second packet + OSF OFFSET(4) NUMBITS(1) [], + /// Tx channel weight + TCW OFFSET(1) NUMBITS(3) [], + /// Start or stop Tx command + /// + /// When set, the DMA checks the transmit list at current position for a packet to be + /// transmitted. If the DMA does not own the current descriptor, the transmission enters + /// the Suspended state with TBU bit in DMACiSR set. + ST OFFSET(0) NUMBITS(1) [], + ], + + pub DMAC0RXCR [ + /// DMA Rx channel 0 packet flush + /// + /// When set, the DMA automatically flushes the packet from the Rx queues destined to DMA + /// Rx channel 0 when the DMA Rx 0 is stopped after a system bus error. + RPF OFFSET(31) NUMBITS(1) [], + /// Rx QOS + RQOS OFFSET(24) NUMBITS(4) [], + /// Rx programmable burst length + RXPBL OFFSET(16) NUMBITS(6) [], + /// Receive buffer size + RBSZ OFFSET(1) NUMBITS(14) [], + /// Start or stop Rx + /// + /// When set, the DMA tries to acquire the descriptor from the receive list and process the + /// incoming packets. + SR OFFSET(0) NUMBITS(1) [], + ], + + pub DMACiIER [ + /// Normal interrupt summary enable + /// + /// When this bit is set, the following interrupts are enabled in the Channel i status + /// register: + /// + /// * Tx interrupt + /// * Tx buffer unavailable + /// * Rx interrupt + /// * Early Rx interrupt + NIE OFFSET(15) NUMBITS(1) [], + /// Abnormal interrupt summary enable + /// + /// When this bit is set, the following interrupt summary is enabled: + /// + /// * Tx process stopped + /// * Rx buffer unavailable + /// * Rx process stopped + /// * Rx watchdog timeout + /// * Early Tx interrupt + /// * Fatal bus error + AIE OFFSET(14) NUMBITS(1) [], + /// Context descriptor error enable (+AIE) + CDEE OFFSET(13) NUMBITS(1) [], + /// Fatal bus error enable (+AIE) + FBEE OFFSET(12) NUMBITS(1) [], + /// Early Rx interrupt enable + /// + /// When this bit is set along with the NIE bit, the Early Rx interrupt is enabled + ERIE OFFSET(11) NUMBITS(1) [], + /// Early Tx interrupt enable + /// + /// When this bit is set along with the AIE bit, the Early Tx interrupt is enabled + ETIE OFFSET(10) NUMBITS(1) [], + /// Receive watchdog timeout enable (+AIE) + RWTE OFFSET(9) NUMBITS(1) [], + /// Rx stopped enable (+AIE) + RSE OFFSET(8) NUMBITS(1) [], + /// Rx buffer unavailable enable (+AIE) + RBUE OFFSET(7) NUMBITS(1) [], + /// Rx interrupt enable (+NIE) + RIE OFFSET(6) NUMBITS(1) [], + /// Tx buffer unavailable enable (+NIE) + TBUE OFFSET(2) NUMBITS(1) [], + /// Tx stopped enable (+AIE) + TXSE OFFSET(1) NUMBITS(1) [], + /// Tx interrupt enable (+NIE) + TIE OFFSET(0) NUMBITS(1) [], + ], + + pub DMACiSR [ + /// Rx DMA error bits + REB OFFSET(19) NUMBITS(3) [], + /// Tx DMA error bits + TEB OFFSET(16) NUMBITS(3) [], + /// Normal interrupt summary + NIS OFFSET(15) NUMBITS(1) [], + /// Abnormal interrupt summary + AIS OFFSET(14) NUMBITS(1) [], + /// Context descriptor error + CDE OFFSET(13) NUMBITS(1) [], + /// Fatal bus error + FBE OFFSET(12) NUMBITS(1) [], + /// Early Rx interrupt + ERI OFFSET(11) NUMBITS(1) [], + /// Early Tx interrupt + ETI OFFSET(10) NUMBITS(1) [], + /// Rx watchdog timeout + RWT OFFSET(9) NUMBITS(1) [], + /// Rx process stopped + RPS OFFSET(8) NUMBITS(1) [], + /// Rx buffer unavailable. To resume processing Rx descriptors, the driver should change + /// the ownership of the descriptors and issue a Rx Poll Demand command. In ring mode, the + /// driver should advance the Rx descriptor tail pointer of a channel. + RBU OFFSET(7) NUMBITS(1) [], + /// Rx interrupt + RI OFFSET(6) NUMBITS(1) [], + /// Tx buffer unavailable (see RBU, but for Tx) + TBU OFFSET(2) NUMBITS(1) [], + /// Tx process stopped + TPS OFFSET(1) NUMBITS(1) [], + /// Tx interrupt + TI OFFSET(0) NUMBITS(1) [], + ], +} + +register_structs! { + pub DmaRegs { + (0x000 => pub DMAMR: ReadWrite), + (0x004 => pub DMASBMR: ReadWrite), + (0x008 => pub DMAISR: ReadWrite), + (0x00C => pub DMADSR: ReadWrite), + (0x010 => _0), + (0x020 => pub DMAA4TXACR: ReadWrite), + (0x024 => pub DMAA4RXACR: ReadWrite), + (0x028 => pub DMAA4DACR: ReadWrite), + (0x02C => _1), + (0x040 => pub DMALPIEI: ReadWrite), + (0x044 => _2), + (0x100 => pub DMAC0CR: ReadWrite), + (0x104 => pub DMAC0TXCR: ReadWrite), + (0x108 => pub DMAC0RXCR: ReadWrite), + (0x10C => _3), + (0x114 => pub DMAC0TXDLAR: ReadWrite), + (0x118 => _4), + (0x11C => pub DMAC0RXDLAR: ReadWrite), + (0x120 => pub DMAC0TXDTPR: ReadWrite), + (0x124 => _5), + (0x128 => pub DMAC0RXDTPR: ReadWrite), + (0x12C => pub DMAC0TXRLR: ReadWrite), + (0x130 => pub DMAC0RXRLR: ReadWrite), + (0x134 => pub DMAC0IER: ReadWrite), + (0x138 => pub DMAC0RXIWTR: ReadWrite), + (0x13C => pub DMAC0SFCSR: ReadWrite), + (0x140 => _6), + (0x144 => pub DMAC0CATXDR: ReadWrite), + (0x148 => _7), + (0x14C => pub DMAC0CARXDR: ReadWrite), + (0x150 => _8), + (0x154 => pub DMAC0CATXBR: ReadWrite), + (0x158 => _9), + (0x15C => pub DMAC0CARXBR: ReadWrite), + (0x160 => pub DMAC0SR: ReadWrite), + (0x164 => _10), + (0x16C => pub DMAC0MFCR: ReadWrite), + (0x170 => _11), + (0x200 => @END), + } +} diff --git a/kernel/driver/net/stmmac/src/regs/mac.rs b/kernel/driver/net/stmmac/src/regs/mac.rs new file mode 100644 index 00000000..7ad8a4e6 --- /dev/null +++ b/kernel/driver/net/stmmac/src/regs/mac.rs @@ -0,0 +1,500 @@ +use libk::error::Error; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_bitfields, register_structs, + registers::{ReadOnly, ReadWrite}, +}; + +register_bitfields! { + u32, + pub MACCR [ + /// * When set: MAC recognizes ARP requests, responds with ARP responses. + /// * When clear: no additional ARP logic, frames are indicates as Type + /// frame in the RxStatus. + ARPEN OFFSET(31) NUMBITS(1) [], + /// Source address insertion or replacement setting. + SARC OFFSET(28) NUMBITS(3) [], + /// IP checksum offload. + /// + /// When set, enables IPv4 header checksum checking, IPv4, IPv6 TCP+UDP and ICMP + /// payload checksum checking. + IPC OFFSET(27) NUMBITS(1) [], + /// Inter-packet gap setting. + IPG OFFSET(24) NUMBITS(1) [], + /// Giant packet size limit control enable. + GPSCLE OFFSET(23) NUMBITS(1) [], + /// IEEE 802.3as support for 2K packets. + S2KP OFFSET(22) NUMBITS(1) [], + /// CRC stripping for Type packets. + CST OFFSET(21) NUMBITS(1) [], + /// Automatic pad or CRC stripping. + ACS OFFSET(20) NUMBITS(1) [], + /// Watchdog disable. + /// + /// When set, disables the watchdog timer on the receiver. The MAC can receive packets + /// of up to 16383 bytes. + /// When clear, the MAC does not allow packets of more than 2048 bytes (or 10240 with + /// JE). + WD OFFSET(19) NUMBITS(1) [], + /// Packet burst enable. + BE OFFSET(18) NUMBITS(1) [], + /// Jabber disable. + /// + /// When set, disables the jabber timer on the transmitter. The MAC can send packets of + /// up to 16383 bytes. + JD OFFSET(17) NUMBITS(1) [], + /// Jumbo packet enable. + JE OFFSET(16) NUMBITS(1) [], + /// Port select + PS OFFSET(15) NUMBITS(1) [ + Ps1000Mbps = 0, + Ps10Or100Mbps = 1, + ], + /// MAC speed + FES OFFSET(14) NUMBITS(1) [ + Fes10Mbps = 0, + Fes100Mbps = 1, + ], + /// Duplex mode + DM OFFSET(13) NUMBITS(1) [ + HalfDuplex = 0, + FullDuplex = 1, + ], + /// Loopback mode. When set, GMII output is looped back into input. The GMII RX clock + /// input is required for the loopback to work, because the GMII TX clock is not + /// looped back internally. + LM OFFSET(12) NUMBITS(1) [], + /// Enable carrier-sense before transmission in Full-Duplex mode + ECRSFD OFFSET(11) NUMBITS(1) [], + /// Disable receive own + DO OFFSET(10) NUMBITS(1) [], + /// Disable carrier-sense during transmission + DCRS OFFSET(9) NUMBITS(1) [], + /// Disable retry + DR OFFSET(8) NUMBITS(1) [], + /// Backoff limit + BL OFFSET(5) NUMBITS(2) [ + /// k = min(n, 10) + BackoffMin10 = 0, + /// k = min(n, 8) + BackoffMin8 = 1, + /// k = min(n, 4) + BackoffMin4 = 2, + /// k = min(n, 1) + BackoffMin1 = 3, + ], + /// Deferral check + DC OFFSET(4) NUMBITS(1) [], + /// Preamble length + PRELEN OFFSET(2) NUMBITS(2) [ + Pre7b = 0, + Pre5b = 1, + Pre3b = 2, + ], + /// Transmitter enable + TE OFFSET(1) NUMBITS(1) [], + /// Receiver enable + RE OFFSET(0) NUMBITS(1) [], + ], + + pub MACPFR [ + /// Receive all. When set, the MAC receiver passes all received packets to the application, + /// whether they pass the address filter or not. + RA OFFSET(31) NUMBITS(1) [], + /// Drop Non-TCP/UDP over IP packets + DNTU OFFSET(21) NUMBITS(1) [], + /// Layer 3 and 4 filter enable + IPFE OFFSET(20) NUMBITS(1) [], + /// VLAN filter enable + VTFE OFFSET(16) NUMBITS(1) [], + /// Hash or perfect filter + HPF OFFSET(10) NUMBITS(1) [], + /// Source address filter + SAF OFFSET(9) NUMBITS(1) [], + /// SA inverse filtering + SAIF OFFSET(8) NUMBITS(1) [], + /// Pass control checks + PCF OFFSET(6) NUMBITS(2) [], + /// Disable broadcast packets + DBF OFFSET(5) NUMBITS(1) [], + /// Pass all multicast + PM OFFSET(4) NUMBITS(1) [], + /// DA inverse filtering + DAIF OFFSET(3) NUMBITS(1) [], + /// Hash multicast + HMC OFFSET(2) NUMBITS(1) [], + /// Hash unicast + HUC OFFSET(1) NUMBITS(1) [], + /// Promiscuous mode + PR OFFSET(0) NUMBITS(1) [], + ], + + pub MACQ0TXFCR [ + /// Pause time + PT OFFSET(16) NUMBITS(16) [], + /// Disable zero-quanta pause + DZPQ OFFSET(7) NUMBITS(1) [], + /// Pause low threshold + PLT OFFSET(4) NUMBITS(3) [], + /// Transmit flow control enable + TFE OFFSET(1) NUMBITS(1) [], + /// Flow control busy or backpressure activate + FCB_BPA OFFSET(0) NUMBITS(1) [], + ], + + pub MACRXFCR [ + /// Unicast packet detect + UP OFFSET(1) NUMBITS(1) [], + /// Rx flow control enable + RFE OFFSET(0) NUMBITS(1) [], + ], + + pub MACRXQC0R [ + /// Rx queue 1 enable + RXQ1EN OFFSET(2) NUMBITS(2) [ + Disable = 0b00, + EnableAV = 0b01, + Enable = 0b10, + ], + /// Rx queue 0 enable + RXQ0EN OFFSET(0) NUMBITS(2) [ + Disable = 0b00, + EnableAV = 0b01, + Enable = 0b10, + ], + ], + + pub MACISR [ + /// Rx status interrupt + RXSTSIS OFFSET(14) NUMBITS(1) [], + /// Tx status interrupt + TXSTSIS OFFSET(13) NUMBITS(1) [], + /// Timestamp interrupt + TSIS OFFSET(12) NUMBITS(1) [], + /// MMC Tx interrupt + MMCTXIS OFFSET(10) NUMBITS(1) [], + /// MMC Rx interrupt + MMCRXIS OFFSET(9) NUMBITS(1) [], + /// MMC interrupt + MMCIS OFFSET(8) NUMBITS(1) [], + /// LPI interrupt + LPIIS OFFSET(5) NUMBITS(1) [], + /// PMT interrupt + PMTIS OFFSET(4) NUMBITS(1) [], + /// PHY interrupt + PHYIS OFFSET(3) NUMBITS(1) [], + /// RGMII interrupt + RGSMIIIS OFFSET(0) NUMBITS(1) [], + ], + + pub MACIER [ + /// Rx status interrupt enable + RXSTSIE OFFSET(14) NUMBITS(1) [], + /// Tx status interrupt enable + TXSTSIE OFFSET(13) NUMBITS(1) [], + /// Timestamp interrupt enable + TSIE OFFSET(12) NUMBITS(1) [], + /// LPI interrupt enable + LPIIE OFFSET(5) NUMBITS(1) [], + /// PMT interrupt enable + PMTIE OFFSET(4) NUMBITS(1) [], + /// PHY interrupt enable + PHYIE OFFSET(3) NUMBITS(1) [], + /// RGMII interrupt enable + RGSMIIIE OFFSET(0) NUMBITS(1) [], + ], + + pub MACPHYCSR [ + /// Link status + LNKSTS OFFSET(19) NUMBITS(1) [ + Down = 0, + Up = 1, + ], + /// Link speed + LNKSPEED OFFSET(17) NUMBITS(2) [ + Speed2_5MHz = 0b00, + Speed25MHz = 0b01, + Speed125MHz = 0b10, + ], + /// Link mode + LNKMOD OFFSET(16) NUMBITS(1) [ + HalfDuplex = 0, + FullDuplex = 1, + ], + /// Link up or down + /// + /// This bit indicates whether the link is up or down during transmission of configuration + /// in the RGMII interface + LUD OFFSET(1) NUMBITS(1) [ + Down = 0, + Up = 1, + ], + /// Transmit configuration in RGMII + TC OFFSET(0) NUMBITS(1) [], + ], + + pub MACMDIOAR [ + /// Preamble suppress enable + /// + /// If set, SMA suppresses the 32-bit preamble and transmits MDIO frames with only 1 + /// preamble bit + PSE OFFSET(27) NUMBITS(1) [], + /// Back to back transactions + /// + /// If set and the NTC has value greater than 0, the MAC informs the completion of a read + /// or write command at the end of frame transfer. Must not be set with NTC=0. + BTB OFFSET(26) NUMBITS(1) [], + /// Physical layer address + /// + /// In Clause 22, indicates a PHY device the MAC is addressing. + PA OFFSET(21) NUMBITS(5) [], + /// Register/Device address + /// + /// In Clause 22, selects the PHY register + RDA OFFSET(16) NUMBITS(5) [], + /// Number of trailing clocks + NTC OFFSET(12) NUMBITS(3) [], + /// CSR clock range + CR OFFSET(8) NUMBITS(4) [ + CSR_20_TO_35_MHZ = 0b0010, + ], + /// Skip address packet + /// + /// If set, the SMA does not send the address packets before read, write or post-read + /// increment address packets. Only valid with C45E set. + SKAP OFFSET(4) NUMBITS(1) [], + /// GMII operation command + GOC OFFSET(2) NUMBITS(2) [ + Write = 0b01, + C45EPostReadIncrement = 0b10, + Read = 0b11 + ], + /// Clause 45 PHY enable + C45E OFFSET(1) NUMBITS(1) [], + /// GMII busy + GB OFFSET(0) NUMBITS(1) [], + ], + + pub MACMDIODR [ + /// Register address + /// + /// Specifies the PHY register when used with Clause 45 + RA OFFSET(16) NUMBITS(16) [], + /// GMII data + GD OFFSET(0) NUMBITS(16) [], + ], + + pub MACAiHR [ + /// MAC address enable bit. Should always be set to 1 for MAC address 0. + AE OFFSET(31) NUMBITS(1) [], + ADDR5 OFFSET(8) NUMBITS(8) [], + ADDR4 OFFSET(0) NUMBITS(8) [], + ], + pub MACAiLR [ + ADDR3 OFFSET(24) NUMBITS(8) [], + ADDR2 OFFSET(16) NUMBITS(8) [], + ADDR1 OFFSET(8) NUMBITS(8) [], + ADDR0 OFFSET(0) NUMBITS(8) [], + ], +} + +register_structs! { + pub MacRegs { + /// Operating mode configuration register + /// + /// Reset value: 0x0000 8000 + /// + /// Established the operating mode of the MAC. + (0x000 => pub MACCR: ReadWrite), + /// Extended operating mode configuration register + /// + /// XXX + (0x004 => pub MACECR: ReadWrite), + /// Packet filtering control register + (0x008 => pub MACPFR: ReadWrite), + /// Watchdog timeout register + (0x00C => pub MACWTR: ReadWrite), + /// Hash table 0 register + (0x010 => pub MACHT0R: ReadWrite), + /// Hash table 1 register + (0x014 => pub MACHT1R: ReadWrite), + (0x018 => _0), + /// VLAN tag register + (0x050 => pub MACVTR: ReadWrite), + (0x054 => _1), + /// VLAN hash table register + (0x058 => pub MACVHTR: ReadWrite), + (0x05C => _2), + /// VLAN inclusion register + (0x060 => pub MACVIR: ReadWrite), + /// Inner VLAN inclusion register + (0x064 => pub MACIVIR: ReadWrite), + (0x068 => _3), + /// Tx queue 0 flow control register + (0x070 => pub MACQ0TXFCR: ReadWrite), + (0x074 => _4), + /// Rx flow control register + (0x090 => pub MACRXFCR: ReadWrite), + /// Rx queue control register + (0x094 => pub MACRXQCR: ReadWrite), + (0x098 => _5), + /// Rx queue control 0 register + (0x0A0 => pub MACRXQC0R: ReadWrite), + /// Rx queue control 1 register + (0x0A4 => pub MACRXQC1R: ReadWrite), + /// Rx queue control 2 register + (0x0A8 => pub MACRXQC2R: ReadWrite), + (0x0AC => _6), + /// Interrupt status register + (0x0B0 => pub MACISR: ReadWrite), + /// Interrupt enable register + (0x0B4 => pub MACIER: ReadWrite), + /// Rx/Tx status register + (0x0B8 => pub MACRXTXSR: ReadWrite), + (0x0BC => _7), + /// PMT control status register + (0x0C0 => pub MACPCSR: ReadWrite), + /// Remote wakeup packet filter register + (0x0C4 => pub MACRWKPFR: ReadWrite), + (0x0C8 => _8), + /// LPI control and status register + (0x0D0 => pub MACLCSR: ReadWrite), + /// LPI timers control register + (0x0D4 => pub MACLTCR: ReadWrite), + /// Tx LPI entry timer + (0x0D8 => pub MACLETR: ReadWrite), + /// One-microsecond-tick counter register + (0x0DC => pub MAC1USTCR: ReadWrite), + (0x0E0 => _9), + /// PHYIF control and status register + (0x0F8 => pub MACPHYCSR: ReadWrite), + (0x0FC => _10), + /// Version register + (0x110 => pub MACVR: ReadOnly), + /// Debug register + (0x114 => pub MACDR: ReadOnly), + (0x118 => _11), + /// HW feature 0 register + (0x11C => pub MACHWF0R: ReadWrite), + /// HW feature 1 register + (0x120 => pub MACHWF1R: ReadWrite), + /// HW feature 2 register + (0x124 => pub MACHWF2R: ReadWrite), + /// HW feature 3 register + (0x128 => pub MACHWF3R: ReadWrite), + (0x12C => _12), + /// MDIO address register + (0x200 => pub MACMDIOAR: ReadWrite), + /// MDIO data register + (0x204 => pub MACMDIODR: ReadWrite), + (0x208 => _13), + /// ARP address register + (0x210 => pub MACARPAR: ReadWrite), + (0x214 => _14), + /// CSR software control register + (0x230 => pub MACCSRSWCR: ReadWrite), + (0x234 => _15), + /// MAC address 0 high register + (0x300 => pub MACA0HR: ReadWrite), + /// MAC address 0 low register + (0x304 => pub MACA0LR: ReadWrite), + /// MAC address 1 high register + (0x308 => pub MACA1HR: ReadWrite), + /// MAC address 1 low register + (0x30C => pub MACA1LR: ReadWrite), + /// MAC address 2 high register + (0x310 => pub MACA2HR: ReadWrite), + /// MAC address 2 low register + (0x314 => pub MACA2LR: ReadWrite), + /// MAC address 3 high register + (0x318 => pub MACA3HR: ReadWrite), + /// MAC address 3 low register + (0x31C => pub MACA3LR: ReadWrite), + (0x320 => _16), + /// MMC control register + (0x700 => pub MMC_CONTROL: ReadWrite), + /// MMC Rx interrupt register + (0x704 => pub MMC_RX_INTERRUPT: ReadWrite), + /// MMC Tx interrupt register + (0x708 => pub MMC_TX_INTERRUPT: ReadWrite), + /// MMC Rx interrupt mask register + (0x70C => pub MMC_RX_INTERRUPT_MASK: ReadWrite), + /// MMC Tx interrupt mask register + (0x710 => pub MMC_TX_INTERRUPT_MASK: ReadWrite), + (0x714 => _17), + (0xC00 => @END), + } +} + +impl MacRegs { + fn mdio_wait_busy(&self) -> Result<(), Error> { + let mut timeout = 10000; + while timeout > 0 && self.MACMDIOAR.matches_all(MACMDIOAR::GB::SET) { + core::hint::spin_loop(); + timeout -= 1; + } + if timeout == 0 { + Err(Error::TimedOut) + } else { + Ok(()) + } + } + + pub fn mdio_read_c45( + &self, + phy_addr: u8, + mmd_addr: u8, + mii_reg: u8, + csr_clk_range: u8, + ) -> Result { + self.mdio_wait_busy()?; + self.MACMDIODR.write(MACMDIODR::RA.val(mii_reg as u32)); + self.MACMDIOAR.write( + MACMDIOAR::CR.val(csr_clk_range as u32) + + MACMDIOAR::GOC::Read + + MACMDIOAR::PA.val(phy_addr as u32) + + MACMDIOAR::RDA.val(mmd_addr as u32) + + MACMDIOAR::C45E::SET + + MACMDIOAR::GB::SET, + ); + self.mdio_wait_busy()?; + Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16) + } + + pub fn mdio_read_c22( + &self, + mii_addr: u8, + mii_reg: u8, + csr_clk_range: u8, + ) -> Result { + self.mdio_wait_busy()?; + self.MACMDIOAR.write( + MACMDIOAR::GOC::Read + + MACMDIOAR::CR.val(csr_clk_range as u32) + + MACMDIOAR::PA.val(mii_addr as u32) + + MACMDIOAR::RDA.val(mii_reg as u32) + + MACMDIOAR::GB::SET, + ); + self.mdio_wait_busy()?; + Ok(self.MACMDIODR.read(MACMDIODR::GD) as u16) + } + + pub fn mdio_write_c22( + &self, + mii_addr: u8, + mii_reg: u8, + value: u16, + csr_clk_range: u8, + ) -> Result<(), Error> { + self.mdio_wait_busy()?; + self.MACMDIODR.write(MACMDIODR::GD.val(value as u32)); + self.MACMDIOAR.write( + MACMDIOAR::GOC::Write + + MACMDIOAR::CR.val(csr_clk_range as u32) + + MACMDIOAR::PA.val(mii_addr as u32) + + MACMDIOAR::RDA.val(mii_reg as u32) + + MACMDIOAR::GB::SET, + ); + self.mdio_wait_busy() + } +} diff --git a/kernel/driver/net/stmmac/src/regs/mod.rs b/kernel/driver/net/stmmac/src/regs/mod.rs new file mode 100644 index 00000000..25a4e89a --- /dev/null +++ b/kernel/driver/net/stmmac/src/regs/mod.rs @@ -0,0 +1,16 @@ +#![allow(non_snake_case)] + +use tock_registers::register_structs; + +pub mod dma; +pub mod mac; +pub mod mtl; + +register_structs! { + pub Regs { + (0x0000 => pub MAC: mac::MacRegs), + (0x0C00 => pub MTL: mtl::MtlRegs), + (0x1000 => pub DMA: dma::DmaRegs), + (0x1200 => @END), + } +} diff --git a/kernel/driver/net/stmmac/src/regs/mtl.rs b/kernel/driver/net/stmmac/src/regs/mtl.rs new file mode 100644 index 00000000..efbff5af --- /dev/null +++ b/kernel/driver/net/stmmac/src/regs/mtl.rs @@ -0,0 +1,132 @@ +use tock_registers::{register_bitfields, register_structs, registers::ReadWrite}; + +register_bitfields! { + u32, + pub MTLOMR [ + CNTCLR OFFSET(9) NUMBITS(1) [], + CNTPRST OFFSET(8) NUMBITS(1) [], + SCHALG OFFSET(5) NUMBITS(2) [ + AlgWeightedRR = 0b00, + AlgStrictPrio = 0b11, + ], + RAA OFFSET(2) NUMBITS(1) [ + AlgStrictPrio = 0, + AlgWeightedPrio = 1 + ], + DTXSTS OFFSET(1) NUMBITS(1) [], + ], + + pub MTLTXQiOMR [ + TQS OFFSET(16) NUMBITS(4) [], + TTC OFFSET(4) NUMBITS(3) [], + TXQEN OFFSET(2) NUMBITS(2) [ + Disable = 0b00, + EnableAv = 0b01, + Enable = 0b11, + ], + TSF OFFSET(1) NUMBITS(1) [], + FTQ OFFSET(0) NUMBITS(1) [], + ], + + pub MTLRXQiOMR [ + RQS OFFSET(20) NUMBITS(4) [], + /// Threshold for deactivating flow control + RFD OFFSET(14) NUMBITS(3) [ + FullMinus1K = 0, + FullMinus1_5K = 1, + FullMinus2K = 2, + FullMinus2_5K = 3, + FullMinus3K = 4, + FullMinus3_5K = 5 + ], + /// Threshold for activating flow control. See [RFD]. + RFA OFFSET(8) NUMBITS(3) [], + /// Enable hardware flow control. When set, the flow control signal operation, based on the + /// fill-level of the Rx queue, is enabled. + EHFC OFFSET(7) NUMBITS(1) [], + /// Disable dropping of TCP/IP checksum error packets + DIS_TCP_EF OFFSET(6) NUMBITS(1) [], + /// Receive queue store and forward. When set, the Ethernet peripheral reads a packet from + /// the Rx queue only after the complete packet has been written to it, ignoring the RTC + /// field. + RSF OFFSET(5) NUMBITS(1) [], + /// Forward error packets. When set, the Rx queue does not drop the packets with CRC + /// errors, watchdog timeouts, overflows and receive errors. + FEP OFFSET(4) NUMBITS(1) [], + /// Forward undersized good packets. When set, the Rx queue does not drop packets with no + /// errors, but with a length of less than 64 bytes. + FUP OFFSET(3) NUMBITS(1) [], + /// Rx threshold level + RTC OFFSET(0) NUMBITS(2) [ + Threshold64 = 0b00, + Threshold32 = 0b01, + Threshold96 = 0b10, + Threshold128 = 0b11, + ], + ], +} + +register_structs! { + pub MtlRegs { + /// MTL operating mode register + (0x000 => pub MTLOMR: ReadWrite), + (0x004 => _0), + /// Interrupt status register + (0x020 => pub MTLISR: ReadWrite), + (0x024 => _1), + /// Tx queue 0 operating mode register + (0x100 => pub MTLTXQ0OMR: ReadWrite), + /// Tx queue 0 underflow register + (0x104 => pub MTLTXQ0UR: ReadWrite), + /// Tx queue 0 debug register + (0x108 => pub MTLTXQ0DR: ReadWrite), + (0x10C => _2), + /// Tx queue 0 ETS status register + (0x114 => pub MTLTXQ0ESR: ReadWrite), + /// Tx queue 0 quantum weight register + (0x118 => pub MTLTXQ0QWR: ReadWrite), + (0x11C => _3), + /// Queue 0 interrupt control status register + (0x12C => pub MTLQ0ICSR: ReadWrite), + /// Rx queue 0 operating mode register + (0x130 => pub MTLRXQ0OMR: ReadWrite), + /// Rx queue 0 missed packet and overflow counter register + (0x134 => pub MTLRXQ0MPOCR: ReadWrite), + /// Rx queue 0 debug register + (0x138 => pub MTLRXQ0DR: ReadWrite), + /// Rx queue 0 control register + (0x13C => pub MTLRXQ0CR: ReadWrite), + /// Tx queue 1 operating mode register + (0x140 => pub MTLTXQ1OMR: ReadWrite), + /// Tx queue 1 underflow register + (0x144 => pub MTLTXQ1UR: ReadWrite), + /// Tx queue 1 debug register + (0x148 => pub MTLTXQ1DR: ReadWrite), + (0x14C => _4), + /// Tx queue 1 ETS control register + (0x150 => pub MTLTXQ1ECR: ReadWrite), + /// Tx queue 1 ETS status register + (0x154 => pub MTLTXQ1ESR: ReadWrite), + /// Tx queue 1 quantum weight register + (0x158 => pub MTLTXQ1QWR: ReadWrite), + /// Tx queue 1 send slope credit register + (0x15C => pub MTLTXQ1SSCR: ReadWrite), + /// Tx queue 1 hiCredit register + (0x160 => pub MTLTXQ1HCR: ReadWrite), + /// Tx queue 1 loCredit register + (0x164 => pub MTLTXQ1LCR: ReadWrite), + (0x168 => _5), + /// Queue 1 interrupt control status register + (0x16C => pub MTLQ1ICSR: ReadWrite), + /// Rx queue 1 operating mode register + (0x170 => pub MTLRXQ1OMR: ReadWrite), + /// Rx queue 1 missed packet and overflow counter register + (0x174 => pub MTLRXQ1MPOCR: ReadWrite), + /// Rx queue 1 debug register + (0x178 => pub MTLRXQ1DR: ReadWrite), + /// Rx queue 1 control register + (0x17C => pub MTLRXQ1CR: ReadWrite), + (0x180 => _6), + (0x400 => @END), + } +} diff --git a/kernel/driver/net/stmmac/src/ring.rs b/kernel/driver/net/stmmac/src/ring.rs new file mode 100644 index 00000000..ac792989 --- /dev/null +++ b/kernel/driver/net/stmmac/src/ring.rs @@ -0,0 +1,248 @@ +use core::mem::{self, MaybeUninit}; + +use alloc::vec::Vec; +use device_api::dma::DmaAllocator; +use libk::{ + dma::{BusAddress, DmaBuffer}, + error::Error, +}; + +pub struct TxRing { + entries: DmaBuffer<[TxDescriptor]>, + buffers: Vec>>, + + wr: usize, + rd: usize, +} + +pub struct RxRing { + entries: DmaBuffer<[RxDescriptor]>, + buffers: Vec]>>, + + rd: usize, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct TxDescriptor { + tdes0: u32, + tdes1: u32, + tdes2: u32, + tdes3: u32, +} + +#[derive(Clone, Copy, Debug)] +#[repr(C)] +pub struct RxDescriptor { + rdes0: u32, + rdes1: u32, + rdes2: u32, + rdes3: u32, +} + +impl TxRing { + pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result { + let entries = DmaBuffer::new_slice(dma, TxDescriptor::empty(), capacity)?; + let buffers = (0..capacity).map(|_| None).collect(); + Ok(Self { + entries, + buffers, + + wr: 0, + rd: 0, + }) + } + + pub fn buffer_base(&self) -> BusAddress { + self.entries.bus_address() + } + + pub fn capacity(&self) -> usize { + self.entries.len() + } + + pub fn can_xmit(&self) -> bool { + self.wr.wrapping_add(1) != self.rd + } + + pub fn outstanding_tx(&self) -> bool { + self.wr != self.rd + } + + pub fn push_xmit(&mut self, frame: DmaBuffer<[u8]>) -> Result { + if !self.can_xmit() { + return Err(Error::WouldBlock); + } + + let address = frame.bus_address(); + let frame_len = frame.len(); + + let capacity = self.entries.len(); + let index = self.wr % capacity; + assert!(self.buffers[index].is_none()); + + frame.cache_flush_all(true); + self.entries[index].setup_tx(address, frame_len, true)?; + self.entries.cache_flush_element(index, true); + + self.buffers[index] = Some(frame); + self.wr = self.wr.wrapping_add(1); + + Ok(self.wr % self.capacity()) + } + + pub fn consume(&mut self) -> Result { + let mut count = 0; + + loop { + let index = self.rd % self.entries.len(); + let entry = &self.entries[index]; + + if self.rd == self.wr { + break; + } + + if entry.tx_completed() { + // Drop the buffer + let _ = self.buffers[index].take().unwrap(); + self.rd = self.rd.wrapping_add(1); + count += 1; + } else { + break; + } + } + + Ok(count) + } +} + +impl TxDescriptor { + const TDES3_OWN: u32 = 1 << 31; + const TDES3_FD: u32 = 1 << 29; + const TDES3_LD: u32 = 1 << 28; + const TDES2_IOC: u32 = 1 << 31; + + pub const fn empty() -> Self { + Self { + tdes0: 0, + tdes1: 0, + tdes2: 0, + tdes3: 0, + } + } + + pub fn tx_completed(&self) -> bool { + self.tdes3 & Self::TDES3_OWN == 0 + } + + pub fn setup_tx( + &mut self, + frame: BusAddress, + frame_len: usize, + ioc: bool, + ) -> Result<(), Error> { + let tdes0 = frame.try_into_u32().map_err(|_| Error::InvalidArgument)?; + if frame_len & !0x3FFF != 0 { + return Err(Error::InvalidArgument); + } + let mut tdes2 = frame_len as u32; + if ioc { + tdes2 |= Self::TDES2_IOC; + } + let tdes3 = Self::TDES3_OWN | Self::TDES3_FD | Self::TDES3_LD; + + self.tdes0 = tdes0; + self.tdes1 = 0; + self.tdes2 = tdes2; + self.tdes3 = tdes3; + Ok(()) + } +} + +impl RxRing { + pub fn with_capacity(dma: &dyn DmaAllocator, capacity: usize) -> Result { + let mut entries = DmaBuffer::new_slice(dma, RxDescriptor::empty(), capacity)?; + let buffers = (0..capacity) + .map(|_| DmaBuffer::new_uninit_slice(dma, 4096)) + .collect::, _>>()?; + for i in 0..capacity { + entries[i].setup_rx(buffers[i].bus_address(), true)?; + } + Ok(Self { + buffers, + entries, + + rd: 0, + }) + } + + pub fn buffer_base(&self) -> BusAddress { + self.entries.bus_address() + } + + pub fn consume)>( + &mut self, + dma: &dyn DmaAllocator, + packet_handler: F, + ) -> Result { + let mut count = 0; + + loop { + let index = self.rd % self.entries.len(); + let entry = &mut self.entries[index]; + + if let Some(_) = entry.rx_completed() { + // Grab the current buffer (the one just written to by the DMA), replace it + // with the newly allocated one, and mark the descriptor as DMA-owned again + let new_buffer = DmaBuffer::new_uninit_slice(dma, 4096)?; + let new_buffer_address = new_buffer.bus_address(); + let buffer = mem::replace(&mut self.buffers[index], new_buffer); + let buffer = unsafe { DmaBuffer::assume_init_slice(buffer) }; + // TODO packet size hint + packet_handler(buffer); + entry.setup_rx(new_buffer_address, true)?; + self.rd = self.rd.wrapping_add(1); + count += 1; + } else { + break; + } + } + + Ok(count) + } +} + +impl RxDescriptor { + const RDES3_OWN: u32 = 1 << 31; + const RDES3_IOC: u32 = 1 << 30; + const RDES3_BUF1V: u32 = 1 << 24; + + pub const fn empty() -> Self { + Self { + rdes0: 0, + rdes1: 0, + rdes2: 0, + rdes3: 0, + } + } + + pub fn rx_completed(&self) -> Option { + if self.rdes3 & Self::RDES3_OWN == 0 { + Some((self.rdes3 & 0x7FFF) as usize) + } else { + None + } + } + + pub fn setup_rx(&mut self, buffer: BusAddress, ioc: bool) -> Result<(), Error> { + self.rdes0 = buffer.try_into_u32().map_err(|_| Error::InvalidArgument)?; + self.rdes1 = 0; + self.rdes2 = 0; + self.rdes3 = Self::RDES3_BUF1V; + if ioc { + self.rdes3 |= Self::RDES3_IOC; + } + self.rdes3 |= Self::RDES3_OWN; + Ok(()) + } +} diff --git a/kernel/lib/device-tree/src/driver/util.rs b/kernel/lib/device-tree/src/driver/util.rs index 6f9fb123..6519e433 100644 --- a/kernel/lib/device-tree/src/driver/util.rs +++ b/kernel/lib/device-tree/src/driver/util.rs @@ -2,6 +2,8 @@ use alloc::sync::Arc; use device_api::interrupt::{FullIrq, MessageInterruptController}; +use fdt_rs::prelude::PropReader; +use yggdrasil_abi::net::MacAddress; use crate::{ driver::{lookup_phandle, map_interrupt_at}, @@ -177,3 +179,19 @@ pub fn pcie_msi_map(node: &Arc) -> Option> { let msi_map = node.property("msi-map")?; Some(PcieMsiMapIter { msi_map, offset: 0 }) } + +/// Reads the configured MAC address from the node's fields in the following order: +/// +/// * "mac-address" +/// * "local-mac-address" +/// * "address" +/// +/// If none are present, [None] is returned. +pub fn read_mac_address(node: &Arc) -> Option { + let property = node + .property("mac-address") + .or_else(|| node.property("local-mac-address")) + .or_else(|| node.property("address"))?; + let mac_bytes: [u8; 6] = property.raw().try_into().ok()?; + Some(MacAddress::from(mac_bytes)) +} diff --git a/kernel/src/device/clock/jh7110_aoncrg.rs b/kernel/src/device/clock/jh7110_aoncrg.rs new file mode 100644 index 00000000..07a36b32 --- /dev/null +++ b/kernel/src/device/clock/jh7110_aoncrg.rs @@ -0,0 +1,163 @@ +//! Starfive JH7110 Always-on CRG +use abi::error::Error; +use alloc::sync::Arc; +use device_api::{ + clock::{ClockController, ClockHandle, ResetController, ResetHandle}, + device::{Device, DeviceInitContext}, +}; +use device_tree::{ + driver::{ + device_tree_driver, DeviceTreeClockController, DeviceTreeResetController, Node, + ProbeContext, + }, + DeviceTreePropertyRead, TProp, +}; +use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; +use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, + registers::ReadWrite, +}; + +register_structs! { + #[allow(non_snake_case)] + Regs { + (0x000 => CLOCKS: [ReadWrite; 14]), + (0x038 => RESETS: ReadWrite), + (0x03C => AONCRG_RESET_STATUS: ReadWrite), + (0x040 => @END), + } +} + +#[derive(Debug, Clone, Copy)] +enum ClockRegister { + Gate(u32), + Unimp, +} + +/// JH7110 AONCRG driver +pub struct Aoncrg { + base: PhysicalAddress, + mapping: OneTimeInit>>, +} + +impl Aoncrg { + fn ensure_init(&self) -> Result<&IrqSafeSpinlock>, Error> { + self.mapping.or_try_init_with(|| { + unsafe { DeviceMemoryIo::map(self.base, Default::default()) }.map(IrqSafeSpinlock::new) + }) + } + + fn map_clock_index(index: u32) -> Option<(usize, ClockRegister)> { + const CLOCK_MAP: &[(&'static str, usize, ClockRegister)] = &[ + ("clk_osc", 0, ClockRegister::Unimp), + ("aon_apb_func_clk", 1, ClockRegister::Unimp), + ("ahb_gmac5_clk", 2, ClockRegister::Gate(31)), + ("axi_gmac5_clk", 3, ClockRegister::Gate(31)), + ("axi_gmac0_rmii_rtx_clk", 4, ClockRegister::Unimp), + ("gmac5_axi64_tx_clk", 5, ClockRegister::Unimp), + ("gmac5_axi64_clk_tx_inv", 6, ClockRegister::Gate(30)), + ]; + let (_, offset, mode) = CLOCK_MAP.get(index as usize)?; + Some((*offset, *mode)) + } +} + +impl Device for Aoncrg { + unsafe fn init(self: Arc, _cx: DeviceInitContext) -> Result<(), Error> { + log::warn!("TODO: init jh7110-aoncrg @ {:#x}", self.base); + Ok(()) + } + + fn display_name(&self) -> &str { + "Starfive JH7110 AONCRG" + } +} + +impl ClockController for Aoncrg { + fn enable_clock(&self, clock: Option) -> Result<(), Error> { + let (offset, mode) = clock + .and_then(Self::map_clock_index) + .ok_or(Error::InvalidArgument) + .inspect_err(|_| log::warn!("jh7110-aoncrg: cannot map clock {clock:?}"))?; + + let mapping = self.ensure_init()?; + let regs = mapping.lock(); + match mode { + ClockRegister::Gate(shift) => { + log::info!("jh7110-aoncrg: enable clock {clock:?}: reg={offset}, bit={shift}"); + regs.CLOCKS[offset].set(1 << shift); + } + _ => (), + } + Ok(()) + } + + fn disable_clock(&self, clock: Option) -> Result<(), Error> { + log::warn!("jh7110: disable clock {clock:?}"); + Ok(()) + } +} + +impl ResetController for Aoncrg { + fn assert_reset(&self, reset: Option) -> Result<(), Error> { + let reset = reset.ok_or(Error::InvalidArgument)?; + let mapping = self.ensure_init()?; + let regs = mapping.lock(); + let val = regs.RESETS.get(); + regs.RESETS.set(val | (1 << reset)); + Ok(()) + } + + fn deassert_reset(&self, reset: Option) -> Result<(), Error> { + let reset = reset.ok_or(Error::InvalidArgument)?; + let mapping = self.ensure_init()?; + let regs = mapping.lock(); + let val = regs.RESETS.get(); + regs.RESETS.set(val & !(1 << reset)); + Ok(()) + } +} + +impl DeviceTreeClockController for Aoncrg { + fn map_clock(self: Arc, property: &TProp, offset: usize) -> Option<(ClockHandle, usize)> { + let cell = property.read_cell(offset, 1)? as u32; + Some(( + ClockHandle { + parent: self, + clock: Some(cell), + }, + 1, + )) + } +} + +impl DeviceTreeResetController for Aoncrg { + fn map_reset(self: Arc, property: &TProp, offset: usize) -> Option<(ResetHandle, usize)> { + let cell = property.read_cell(offset, 1)? as u32; + Some(( + ResetHandle { + parent: self, + reset: Some(cell), + }, + 1, + )) + } +} + +device_tree_driver! { + compatible: ["starfive,jh7110-aoncrg"], + driver: { + fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + let base = node.map_base(context, 0)?; + let aoncrg = Arc::new(Aoncrg { + base, + mapping: OneTimeInit::new() + }); + node.make_reset_controller(aoncrg.clone()); + node.make_clock_controller(aoncrg.clone()); + Some(aoncrg) + } + } +} diff --git a/kernel/src/device/clock/jh7110_syscrg.rs b/kernel/src/device/clock/jh7110_syscrg.rs index 657c6f5a..5c6df03b 100644 --- a/kernel/src/device/clock/jh7110_syscrg.rs +++ b/kernel/src/device/clock/jh7110_syscrg.rs @@ -18,6 +18,22 @@ use libk_util::{sync::IrqSafeSpinlock, OneTimeInit}; const CLK_OSC: usize = 0; +// gmac0; +// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(3) +// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(2) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(109) +// 1:kernel/src/device/clock/jh7110_aoncrg.rs:69: jh7110: enable clock Some(6) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(111) +// 1:kernel/src/device/clock/jh7110_aoncrg.rs:86: jh7110: deassert reset Some(0) +// 1:kernel/src/device/clock/jh7110_aoncrg.rs:86: jh7110: deassert reset Some(1) + +// gmac1: +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(98) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(97) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(102) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(106) +// 1:kernel/src/device/clock/jh7110_syscrg.rs:51: TODO: jh7110-syscrg: enable clock Some(107) + const CLK_UART0_CORE: u32 = 146; struct Syscrg { @@ -48,8 +64,18 @@ impl Device for Syscrg { impl ClockController for Syscrg { fn enable_clock(&self, clock: Option) -> Result<(), Error> { - log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}"); - Ok(()) + let regs = self.ensure_init()?; + match clock.ok_or(Error::InvalidArgument)? { + 109 => { + regs.lock()[109] |= 1 << 31; + Ok(()) + } + 111 => Ok(()), + _ => { + log::warn!("TODO: jh7110-syscrg: enable clock {clock:?}"); + Err(Error::NotImplemented) + } + } } fn disable_clock(&self, clock: Option) -> Result<(), Error> { diff --git a/kernel/src/device/clock/mod.rs b/kernel/src/device/clock/mod.rs index 5f267992..9126f7e0 100644 --- a/kernel/src/device/clock/mod.rs +++ b/kernel/src/device/clock/mod.rs @@ -3,6 +3,8 @@ #[cfg(any(target_arch = "aarch64", rust_analyzer))] pub mod bcm2835_aux; +#[cfg(any(target_arch = "riscv64", rust_analyzer))] +pub mod jh7110_aoncrg; #[cfg(any(target_arch = "riscv64", rust_analyzer))] pub mod jh7110_syscrg; diff --git a/kernel/src/main.rs b/kernel/src/main.rs index bcba46bf..a57e9d2a 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -78,6 +78,9 @@ cfg_if::cfg_if! { #[macro_use] pub mod arch; +#[cfg(any(target_arch = "riscv64", rust_analyzer))] +extern crate ygg_driver_net_stmmac; + pub mod device; pub mod fs; pub mod init; diff --git a/lib/abi/src/net/protocols.rs b/lib/abi/src/net/protocols.rs index 6b90e3b8..c8b9f57f 100644 --- a/lib/abi/src/net/protocols.rs +++ b/lib/abi/src/net/protocols.rs @@ -24,7 +24,7 @@ pub struct EthernetFrame { #[derive(Clone, Copy, PartialEq, Eq, Debug)] #[cfg_attr(feature = "bytemuck", derive(bytemuck::Pod, bytemuck::Zeroable))] #[repr(transparent)] -pub struct EtherType(u16); +pub struct EtherType(pub u16); impl EtherType { pub const ARP: Self = Self(0x0806); diff --git a/userspace/netutils/src/dhcp_client.rs b/userspace/netutils/src/dhcp_client.rs index 1c636f8e..aae1e3f7 100644 --- a/userspace/netutils/src/dhcp_client.rs +++ b/userspace/netutils/src/dhcp_client.rs @@ -73,10 +73,10 @@ struct DhcpMessage { #[derive(Debug)] struct DhcpOffer { - router_address: Ipv4Addr, + router_address: Option, server_address: Ipv4Addr, your_address: Ipv4Addr, - subnet_mask: u32, + subnet_mask: Option, } fn pad_to_align(buffer: &mut Vec) { @@ -242,7 +242,9 @@ impl DhcpMessage { } fn as_dhcp_acknowledge(&self, requested_address: Ipv4Addr) -> Option<()> { - let ty = self.message_type()?; + let Some(ty) = self.message_type() else { + return None; + }; if ty != DhcpMessageType::Acknowledge { return None; @@ -286,13 +288,11 @@ impl DhcpMessage { } } - let router_address = router?; let server_address = server?; - let subnet_mask = subnet_mask?; Some(DhcpOffer { server_address, - router_address, + router_address: router, your_address: Ipv4Addr::from(yiaddr), subnet_mask, }) @@ -467,6 +467,7 @@ fn attempt_request( op: 1, htype: 1, hlen: 6, + flags: (1u16 << 15).to_be(), xid: transaction_id.to_be(), chaddr: [0; 16], cookie: 0x63825363u32.to_be(), @@ -486,11 +487,11 @@ fn attempt_request( let offer = wait_for_dhcp_offer(poll, timer, socket)?; println!( - "Got DHCP offer: address={} router={} server={} mask={}", + "Got DHCP offer: address={} router={:?} server={} mask={:?}", offer.your_address, offer.router_address, offer.server_address, - Ipv4Addr::from(offer.subnet_mask) + offer.subnet_mask.map(Ipv4Addr::from) ); // Send DHCP request @@ -503,6 +504,7 @@ fn attempt_request( chaddr: [0; 16], siaddr: u32::from(offer.server_address).to_be(), cookie: 0x63825363u32.to_be(), + flags: (1u16 << 15).to_be(), ..DhcpMessageHeader::zeroed() }, options: vec![ @@ -548,11 +550,12 @@ fn request_address(interface: &str) -> Result { fn configure_address(interface: &str, offer: DhcpOffer) -> Result<(), Error> { let mut netconf = NetConfig::open()?; + let router_address = offer.router_address.unwrap_or(offer.server_address); netconf.set_interface_address(interface, IpAddr::V4(offer.your_address))?; netconf.add_route( interface, SubnetAddr::V4(SubnetV4Addr::UNSPECIFIED), - Some(IpAddr::V4(offer.router_address)), + Some(router_address.into()) )?; Ok(()) }