From 41944890b65a8314f5c14f4e73d3cd077584f056 Mon Sep 17 00:00:00 2001 From: Mark Poliakov Date: Fri, 14 Feb 2025 16:52:45 +0200 Subject: [PATCH] jh7110: get second ethernet kinda working --- kernel/driver/bus/pci/src/lib.rs | 4 +- kernel/driver/net/stmmac/src/lib.rs | 96 +++++++--- kernel/driver/net/stmmac/src/regs/mac.rs | 75 -------- kernel/driver/net/stmmac/src/regs/mod.rs | 47 ++++- kernel/lib/device-tree/src/driver/mod.rs | 15 +- kernel/lib/device-tree/src/driver/registry.rs | 2 +- kernel/lib/device-tree/src/driver/traits.rs | 6 +- kernel/lib/device-tree/src/driver/tree.rs | 166 ++++++++++-------- kernel/src/arch/riscv64/mod.rs | 9 +- .../src/device/bus/pci_host_ecam_generic.rs | 2 +- kernel/src/device/bus/simple_bus.rs | 2 +- kernel/src/device/clock/fixed.rs | 2 +- kernel/src/device/clock/jh7110_aoncrg.rs | 110 +++++++++--- kernel/src/device/clock/jh7110_syscrg.rs | 141 +++++++++------ kernel/src/device/interrupt/riscv_plic.rs | 4 +- kernel/src/device/serial/ns16550a.rs | 2 +- kernel/src/device/serial/snps_dw_apb_uart.rs | 2 +- kernel/src/init.rs | 23 +++ kernel/src/syscall/mod.rs | 17 +- 19 files changed, 447 insertions(+), 278 deletions(-) diff --git a/kernel/driver/bus/pci/src/lib.rs b/kernel/driver/bus/pci/src/lib.rs index ef0551c6..f83ede26 100644 --- a/kernel/driver/bus/pci/src/lib.rs +++ b/kernel/driver/bus/pci/src/lib.rs @@ -322,7 +322,9 @@ impl PciBusSegment { for i in 0..6 { if (1 << i) & bar_mask != 0 { - let orig_value = config.bar(i).unwrap(); + let Some(orig_value) = config.bar(i) else { + continue; + }; let size = unsafe { config.bar_size(i) }; if size != 0 { diff --git a/kernel/driver/net/stmmac/src/lib.rs b/kernel/driver/net/stmmac/src/lib.rs index 458b7a74..c2a1731b 100644 --- a/kernel/driver/net/stmmac/src/lib.rs +++ b/kernel/driver/net/stmmac/src/lib.rs @@ -1,17 +1,24 @@ #![no_std] -use core::mem::MaybeUninit; +use core::{mem::MaybeUninit, time::Duration}; -use alloc::{sync::Arc, vec::Vec}; +use alloc::sync::Arc; 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 device_tree::driver::{ + device_tree_driver, util::read_mac_address, InitSequence, Node, ProbeContext, +}; use futures_util::task::AtomicWaker; -use libk::{device::external_interrupt_controller, dma::DmaBuffer, error::Error, task::runtime}; +use libk::{ + device::external_interrupt_controller, + dma::DmaBuffer, + error::Error, + task::runtime::{self, psleep, pwait}, +}; use libk_mm::{address::PhysicalAddress, device::DeviceMemoryIo}; use libk_util::{event::BitmapEvent, sync::IrqSafeSpinlock, OneTimeInit}; use regs::{ @@ -25,6 +32,7 @@ use regs::{ use ring::{RxDescriptor, RxRing, TxDescriptor, TxRing}; use tock_registers::interfaces::{ReadWriteable, Readable, Writeable}; use ygg_driver_net_core::{ + ephy::{PhyAccess, GBESR}, interface::{NetworkDevice, NetworkInterfaceType}, RxPacket, }; @@ -49,8 +57,16 @@ struct Stmmac { base: PhysicalAddress, dma: OneTimeInit>, mac: MacAddress, - resets: Vec, - clocks: Vec, + + clk_stmmaceth: ClockHandle, + clk_pclk: ClockHandle, + clk_ptp_ref: ClockHandle, + clk_tx: ClockHandle, + clk_gtx: ClockHandle, + + rst_stmmaceth: ResetHandle, + rst_ahb: ResetHandle, + irq: FullIrq, softirq_events: BitmapEvent, @@ -176,12 +192,19 @@ impl Device for Stmmac { log::info!("stmmac: setup {:#x}, mac={}", self.base, self.mac); - for clock in self.clocks.iter() { - clock.enable()?; - } - for reset in self.resets.iter() { - reset.deassert()?; - } + self.clk_stmmaceth.enable()?; + self.clk_pclk.enable()?; + self.clk_ptp_ref.enable()?; + self.clk_gtx.enable()?; + self.clk_tx.enable()?; + + self.rst_ahb.deassert()?; + + self.rst_stmmaceth.assert()?; + psleep(Duration::from_millis(1)); + self.rst_stmmaceth.deassert()?; + + psleep(Duration::from_millis(20)); let regs = unsafe { DeviceMemoryIo::::map(self.base, Default::default()) }?; @@ -189,16 +212,11 @@ impl Device for Stmmac { // 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!("stmmac: reset timeout"); - return Err(Error::TimedOut); - } + pwait( + Duration::from_millis(100), + Duration::from_millis(10), + || regs.DMA.DMAMR.matches_all(DMAMR::SWR::CLEAR), + )?; // Setup DMA parameters // TODO get these params from device tree @@ -312,6 +330,14 @@ impl Device for Stmmac { .MACPHYCSR .modify(MACPHYCSR::LUD::SET + MACPHYCSR::TC::SET); + // Setup the PHY + // TODO autodiscover phy + let phy = PhyAccess::new(&*regs, 0x00); + let (id0, id1) = phy.id()?; + log::info!("stmmac: PHY {id0:04x}:{id1:04x}"); + phy.reset(Duration::from_millis(100))?; + phy.setup_link(true, GBESR::empty())?; + self.inner.init(Inner { regs: IrqSafeSpinlock::new(regs), @@ -361,21 +387,37 @@ impl NetworkDevice for Stmmac { device_tree_driver! { compatible: ["starfive,jh7110-dwmac"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; - let clocks = node.clocks()?.collect(); - let resets = node.resets()?.collect(); + + let clk_stmmaceth = node.named_clock("stmmaceth")?; + let clk_pclk = node.named_clock("pclk")?; + let clk_ptp_ref = node.named_clock("ptp_ref")?; + let clk_tx = node.named_clock("tx")?; + let clk_gtx = node.named_clock("gtx")?; + + let rst_stmmaceth = node.named_reset("stmmaceth")?; + let rst_ahb = node.named_reset("ahb")?; + let mac = read_mac_address(node)?; // TODO named_interrupt() let irq = node.interrupt(0)?; + context.sequence = Some(InitSequence::Late); + Some(Arc::new(Stmmac { base, - clocks, - resets, mac, irq, + clk_stmmaceth, + clk_pclk, + clk_ptp_ref, + clk_tx, + clk_gtx, + rst_stmmaceth, + rst_ahb, + softirq_events: BitmapEvent::new(AtomicWaker::new()), dma: OneTimeInit::new(), diff --git a/kernel/driver/net/stmmac/src/regs/mac.rs b/kernel/driver/net/stmmac/src/regs/mac.rs index 7ad8a4e6..0adebcce 100644 --- a/kernel/driver/net/stmmac/src/regs/mac.rs +++ b/kernel/driver/net/stmmac/src/regs/mac.rs @@ -1,6 +1,4 @@ -use libk::error::Error; use tock_registers::{ - interfaces::{Readable, Writeable}, register_bitfields, register_structs, registers::{ReadOnly, ReadWrite}, }; @@ -425,76 +423,3 @@ register_structs! { (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 index 25a4e89a..6639cc8d 100644 --- a/kernel/driver/net/stmmac/src/regs/mod.rs +++ b/kernel/driver/net/stmmac/src/regs/mod.rs @@ -1,6 +1,14 @@ #![allow(non_snake_case)] -use tock_registers::register_structs; +use core::time::Duration; + +use libk::{error::Error, task::runtime::pwait}; +use mac::{MACMDIOAR, MACMDIODR}; +use tock_registers::{ + interfaces::{Readable, Writeable}, + register_structs, +}; +use ygg_driver_net_core::ephy::MdioBus; pub mod dma; pub mod mac; @@ -14,3 +22,40 @@ register_structs! { (0x1200 => @END), } } + +impl Regs { + fn mdio_wait_busy(&self) -> Result<(), Error> { + pwait(Duration::from_millis(50), Duration::from_millis(1), || { + self.MAC.MACMDIOAR.matches_all(MACMDIOAR::GB::CLEAR) + }) + } +} + +impl MdioBus for Regs { + fn mii_read(&self, phyaddr: u8, regaddr: u8) -> Result { + self.mdio_wait_busy()?; + self.MAC.MACMDIOAR.write( + MACMDIOAR::GOC::Read + + MACMDIOAR::CR.val(1) + + MACMDIOAR::PA.val(phyaddr as u32) + + MACMDIOAR::RDA.val(regaddr as u32) + + MACMDIOAR::GB::SET, + ); + self.mdio_wait_busy()?; + Ok(self.MAC.MACMDIODR.read(MACMDIODR::GD) as u16) + } + + fn mii_write(&self, phyaddr: u8, regaddr: u8, value: u16) -> Result<(), Error> { + self.mdio_wait_busy()?; + self.MAC.MACMDIODR.write(MACMDIODR::GD.val(value as u32)); + self.MAC.MACMDIOAR.write( + MACMDIOAR::GOC::Write + + MACMDIOAR::CR.val(1) + + MACMDIOAR::PA.val(phyaddr as u32) + + MACMDIOAR::RDA.val(regaddr as u32) + + MACMDIOAR::GB::SET, + ); + self.mdio_wait_busy()?; + Ok(()) + } +} diff --git a/kernel/lib/device-tree/src/driver/mod.rs b/kernel/lib/device-tree/src/driver/mod.rs index 462d1337..ad1a3b84 100644 --- a/kernel/lib/device-tree/src/driver/mod.rs +++ b/kernel/lib/device-tree/src/driver/mod.rs @@ -20,6 +20,15 @@ pub use traits::{ }; pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node}; +/// Specifies initialization sequence requirement for a driver +#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum InitSequence { + /// Driver can be initialized during early boot + Early = 1, + /// Driver must be initialized when sleep function is available + Late = 2, +} + /// Performs a walk of the device tree and initializes nodes which haven't already been /// initialized/probed. /// @@ -28,9 +37,10 @@ pub use tree::{find_node, unflatten_device_tree, walk_device_tree, Node}; pub fn lazy_init), F: Fn(&Arc, Error)>( success_handler: S, error_handler: F, + sequence: InitSequence, ) { walk_device_tree::<(), _>(|node| { - match node.clone().lazy_init() { + match node.clone().lazy_init(sequence) { Some(Ok(())) => success_handler(node), Some(Err(error)) => error_handler(node, error), None => (), @@ -47,9 +57,10 @@ pub fn lazy_init), F: Fn(&Arc, Error)>( pub fn init_irqs), F: Fn(&Arc, Error)>( success_handler: S, error_handler: F, + sequence: InitSequence, ) { walk_device_tree::<(), _>(|node| { - match node.clone().init_irqs() { + match node.clone().init_irqs(sequence) { Some(Ok(())) => success_handler(node), Some(Err(error)) => error_handler(node, error), None => (), diff --git a/kernel/lib/device-tree/src/driver/registry.rs b/kernel/lib/device-tree/src/driver/registry.rs index 0a4f93cf..df23ddb3 100644 --- a/kernel/lib/device-tree/src/driver/registry.rs +++ b/kernel/lib/device-tree/src/driver/registry.rs @@ -43,7 +43,7 @@ pub fn lookup_phandle(phandle: Phandle, ensure_probed: bool) -> Option if let Some(node) = node.as_ref() && ensure_probed { - node.clone().probe()?; + node.probe()?; } node } diff --git a/kernel/lib/device-tree/src/driver/traits.rs b/kernel/lib/device-tree/src/driver/traits.rs index 5a06bfb5..146da7b1 100644 --- a/kernel/lib/device-tree/src/driver/traits.rs +++ b/kernel/lib/device-tree/src/driver/traits.rs @@ -11,12 +11,12 @@ use device_api::{ use crate::TProp; -use super::Node; +use super::{InitSequence, Node}; /// Device tree driver interface pub trait Driver: Sync { /// Constructs a [Device] for a given matching node - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option>; + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option>; } /// Device-tree based interrupt mapper/controller interface @@ -46,6 +46,8 @@ pub trait DeviceTreeResetController { /// Context passed to the driver's `probe` function pub struct ProbeContext { pub(crate) bus: Option>, + /// Can be used to set a specific initialization sequence for the device + pub sequence: Option, } impl ProbeContext { diff --git a/kernel/lib/device-tree/src/driver/tree.rs b/kernel/lib/device-tree/src/driver/tree.rs index 2eb47bd7..0ca2ddae 100644 --- a/kernel/lib/device-tree/src/driver/tree.rs +++ b/kernel/lib/device-tree/src/driver/tree.rs @@ -24,7 +24,7 @@ use super::{ lookup_phandle, map_interrupt, registry::{register_phandle, DEVICE_TREE, DRIVERS, ROOT}, DeviceTreeClockController, DeviceTreeInterruptController, DeviceTreeResetController, Driver, - ProbeContext, + InitSequence, ProbeContext, }; /// Represents a single node in the device tree, which may or may not: @@ -48,29 +48,27 @@ pub struct Node { // Driver/device info device: OneTimeInit, - init_token: OneTimeInit<()>, - pub(crate) interrupt_controller: OneTimeInit>, pub(crate) msi_controller: OneTimeInit>, pub(crate) clock_controler: OneTimeInit>, pub(crate) reset_controller: OneTimeInit>, } +pub(crate) struct ProbedDevice { + driver: &'static dyn Driver, + sequence: InitSequence, + init_token: OneTimeInit>, + irq_init_token: OneTimeInit>, + device: Arc, +} + enum NodeDevice { // Node probed, no device found Missing, // Node probed and driver found - Present { - driver: &'static dyn Driver, - device: Arc, - }, + Present(ProbedDevice), } -// struct NodeDevice { -// driver: &'static dyn Driver, -// device: Arc, -// } - struct EnumerationContext { address_cells: usize, size_cells: usize, @@ -79,23 +77,39 @@ struct EnumerationContext { } impl NodeDevice { - fn as_device(&self) -> Option> { + fn as_probed(&self) -> Option<&ProbedDevice> { match self { Self::Missing => None, - Self::Present { device, .. } => Some(device.clone()), - } - } - - fn driver(&self) -> Option<&'static dyn Driver> { - match self { - Self::Missing => None, - Self::Present { driver, .. } => Some(*driver), + Self::Present(probed) => Some(probed), } } } impl Node { - fn probe_upwards(self: Arc) -> (Option>, Option>) { + fn probe_single(node: &Arc, cx: &mut ProbeContext) -> Option { + let compatible = node.compatible?; + let drivers = DRIVERS.read(); + let driver = drivers.iter().find(|d| d.matches(compatible)); + if driver.is_none() { + // log::warn!("No driver for {compatible:?}"); + } + let driver = driver?; + + let device = driver.imp.probe(node, cx); + + // Move to early init unless driver wants to sleep + let sequence = cx.sequence.unwrap_or(InitSequence::Early); + + device.map(|device| ProbedDevice { + driver: driver.imp, + sequence, + device, + init_token: OneTimeInit::new(), + irq_init_token: OneTimeInit::new(), + }) + } + + fn probe_upwards(self: &Arc) -> (Option<&ProbedDevice>, Option>) { let mut parent_bus = None; if let Some(parent) = self.parent.as_ref().and_then(Weak::upgrade) { let (_, bus) = parent.probe_upwards(); @@ -110,47 +124,33 @@ impl Node { } } - let cx = ProbeContext { + let mut cx = ProbeContext { bus: parent_bus.clone(), + sequence: None, }; - let inner = self.device.or_init_with_opt(|| { - let compatible = self.compatible?; - let drivers = DRIVERS.read(); - let driver = drivers.iter().find(|d| d.matches(compatible)); - if driver.is_none() { - // log::warn!("No driver for {compatible:?}"); - } - let driver = driver?; - - let device = driver.imp.probe(&self, &cx); - - let slot = match device { - Some(device) => NodeDevice::Present { - driver: driver.imp, - device, - }, + let inner = self + .device + .or_init_with(|| match Self::probe_single(&self, &mut cx) { + Some(probed) => NodeDevice::Present(probed), None => NodeDevice::Missing, - }; - Some(slot) - }); + }); + let probed = inner.as_probed(); - let device = inner.and_then(|d| d.as_device()); - - let bus = if let Some(device) = device.as_ref() { - device.clone().as_bus().as_ref().map(Arc::downgrade) + let bus = if let Some(probed) = probed.as_ref() { + probed.device.clone().as_bus().as_ref().map(Arc::downgrade) } else { parent_bus }; - (device, bus) + (probed, bus) } /// Performs a "probe" of the node by looking up a matching driver. If the node /// has a parent, its parent is probed first. /// /// If the node has already been probed, the device reference is just returned instead. - pub fn probe(self: Arc) -> Option> { + pub(crate) fn probe(self: &Arc) -> Option<&ProbedDevice> { let (device, _) = self.probe_upwards(); device } @@ -189,7 +189,8 @@ impl Node { /// Returns the device driver associated with this node, if any was probed. pub fn driver(&self) -> Option<&'static dyn Driver> { - self.device.try_get()?.driver() + let probed = self.device.try_get()?.as_probed()?; + Some(probed.driver) } /// Performs a lazy initialization of the node: @@ -203,17 +204,20 @@ impl Node { /// * `Some(Ok(()))` - device was probed and initialized (now or before). /// * `Some(Err(...))` - device was probed, but initialization failed. /// * `None` - no driver matched the device. - pub fn lazy_init(self: Arc) -> Option> { - let device = self.clone().probe()?; - let result = self.init_token.or_try_init_with(|| { - let cx = self.make_init_context(); - unsafe { device.init(cx) }?; - Ok(()) - }); - match result { - Ok(()) => Some(Ok(())), - Err(error) => Some(Err(error)), + pub fn lazy_init(self: Arc, sequence: InitSequence) -> Option> { + let probed = self.probe()?; + + // Needs to be initialized later + if probed.sequence > sequence { + return None; } + + let state = probed.init_token.or_init_with(|| { + let cx = self.make_init_context(); + unsafe { probed.device.clone().init(cx) } + }); + + Some(*state) } /// Performs an IRQ initialization for the node's device: @@ -222,15 +226,20 @@ impl Node { /// 2. If [Node::lazy_init] succeeds and a device exists, calls [Device::init_irq]. /// /// Return value is the same as in [Node::lazy_init]. - pub fn init_irqs(self: Arc) -> Option> { - match self.clone().lazy_init() { + pub fn init_irqs(self: Arc, sequence: InitSequence) -> Option> { + let probed = match self.clone().lazy_init(sequence) { Some(Ok(())) => { let device = self.device.get(); - let status = unsafe { device.as_device()?.init_irq() }; - Some(status) + device.as_probed()? } - Some(Err(_)) | None => None, - } + Some(Err(_)) | None => return None, + }; + + let state = probed + .irq_init_token + .or_init_with(|| unsafe { probed.device.clone().init_irq() }); + + Some(*state) } /// "Forces" an initialization of the device. This is a stricter version of [Node::lazy_init] @@ -244,19 +253,20 @@ impl Node { /// * `Ok(())` - if probe/init succeeded. /// * `Err(Error::DoesNotExist)` - couldn't find a device/driver for this node. /// * `Err(other)` - initialization failed. - pub fn force_init(self: Arc) -> Result<(), Error> { - let device = self - .clone() - .probe() - .ok_or(Error::DoesNotExist) - .inspect_err(|_| log::error!("Does not exist: probe({:?})", self.name))?; + pub fn force_init(self: Arc, sequence: InitSequence) -> Result<(), Error> { + let probed = self.probe().ok_or(Error::DoesNotExist)?; - self.init_token.try_init_with_opt(|| { + // Needs to be initialized later + if probed.sequence > sequence { + return Ok(()); + } + + let state = probed.init_token.try_init_with(|| { let cx = self.make_init_context(); - unsafe { device.init(cx) }?; - Ok(()) + unsafe { probed.device.clone().init(cx) } })?; - Ok(()) + + *state } fn make_init_context(&self) -> DeviceInitContext { @@ -364,8 +374,9 @@ impl Node { /// Attempts to get a clock controller represented by this node, if any pub fn as_clock_controller(&self) -> Option> { - let device = self.device.try_get()?; - device.as_device()?.as_clock_controller() + todo!() + // let device = self.device.try_get()?; + // device.as_device()?.as_clock_controller() } /// Attempts to get an interrupt controller represented by this node, if any @@ -456,7 +467,6 @@ fn unflatten_node( parent, device: OneTimeInit::new(), - init_token: OneTimeInit::new(), interrupt_controller: OneTimeInit::new(), msi_controller: OneTimeInit::new(), diff --git a/kernel/src/arch/riscv64/mod.rs b/kernel/src/arch/riscv64/mod.rs index 60b996c3..a920802b 100644 --- a/kernel/src/arch/riscv64/mod.rs +++ b/kernel/src/arch/riscv64/mod.rs @@ -7,7 +7,10 @@ use device_api::{ interrupt::{IpiDeliveryTarget, IpiMessage}, ResetDevice, }; -use device_tree::{driver::unflatten_device_tree, DeviceTree, DeviceTreeNodeExt}; +use device_tree::{ + driver::{unflatten_device_tree, InitSequence}, + DeviceTree, DeviceTreeNodeExt, +}; use kernel_arch::Architecture; use kernel_arch_riscv64::{ mem::{self, KERNEL_VIRT_OFFSET}, @@ -225,6 +228,7 @@ impl Riscv64 { |node, error| { log::error!("{}: {error:?}", node.name().unwrap_or("")); }, + InitSequence::Early, ); device_tree::driver::init_irqs( |_| (), @@ -234,6 +238,7 @@ impl Riscv64 { node.name().unwrap_or("") ); }, + InitSequence::Early, ); PciBusManager::probe_bus_devices()?; @@ -283,7 +288,7 @@ impl Riscv64 { if let Some(node) = node { log::info!("Probe chosen stdout: {:?}", node.name()); - node.force_init()?; + node.force_init(InitSequence::Early)?; } // No stdout diff --git a/kernel/src/device/bus/pci_host_ecam_generic.rs b/kernel/src/device/bus/pci_host_ecam_generic.rs index 7ca99614..bf458d43 100644 --- a/kernel/src/device/bus/pci_host_ecam_generic.rs +++ b/kernel/src/device/bus/pci_host_ecam_generic.rs @@ -121,7 +121,7 @@ fn make_msi_map(node: &Arc) -> Option { device_tree_driver! { compatible: ["pci-host-ecam-generic"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let ecam_base = node.map_base(context, 0)?; let ranges = node.property("ranges")?; diff --git a/kernel/src/device/bus/simple_bus.rs b/kernel/src/device/bus/simple_bus.rs index b97e8a2e..f2d7aff4 100644 --- a/kernel/src/device/bus/simple_bus.rs +++ b/kernel/src/device/bus/simple_bus.rs @@ -58,7 +58,7 @@ impl Bus for SimpleBus { device_tree_driver! { compatible: ["simple-bus"], driver: { - fn probe(&self, node: &Arc, _context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, _context: &mut ProbeContext) -> Option> { // Format per DT spec: (child-bus-address, parent-bus-address, length) // Where: // child-bus-address: #address-cells of this node diff --git a/kernel/src/device/clock/fixed.rs b/kernel/src/device/clock/fixed.rs index fa88d106..0e6b80d3 100644 --- a/kernel/src/device/clock/fixed.rs +++ b/kernel/src/device/clock/fixed.rs @@ -63,7 +63,7 @@ impl DeviceTreeClockController for FixedClock { device_tree_driver! { compatible: ["fixed-clock"], driver: { - fn probe(&self, node: &Arc, _context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, _context: &mut ProbeContext) -> Option> { let name = node.name()?; let frequency = node.property("clock-frequency")?.read_cell(0, 1)?; log::info!("fixed-clock {name}: {frequency}"); diff --git a/kernel/src/device/clock/jh7110_aoncrg.rs b/kernel/src/device/clock/jh7110_aoncrg.rs index 07a36b32..49941204 100644 --- a/kernel/src/device/clock/jh7110_aoncrg.rs +++ b/kernel/src/device/clock/jh7110_aoncrg.rs @@ -20,6 +20,14 @@ use tock_registers::{ registers::ReadWrite, }; +const PARENT_OSC: usize = 0; +// const PARENT_GMAC0_RMII_REFIN: usize = 1; +// const PARENT_GMAC0_RGMII_RXIN: usize = 2; +const PARENT_STG_AXIAHB: usize = 3; +// const PARENT_APB_BUS: usize = 4; +// const PARENT_GMAC0_GTXCLK: usize = 5; +// const PARENT_RTC_OSC: usize = 6; + register_structs! { #[allow(non_snake_case)] Regs { @@ -32,13 +40,24 @@ register_structs! { #[derive(Debug, Clone, Copy)] enum ClockRegister { - Gate(u32), + Gate(u32, ClockParent), + #[allow(unused)] + FixedDiv(u32, ClockParent), + // TODO + Fixed, Unimp, } +#[derive(Debug, Clone, Copy)] +enum ClockParent { + Int(u32), + Ext(usize), +} + /// JH7110 AONCRG driver pub struct Aoncrg { base: PhysicalAddress, + clock_parents: [ClockHandle; 7], mapping: OneTimeInit>>, } @@ -49,18 +68,54 @@ impl Aoncrg { }) } - 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)), + fn clk_enable_int(&self, index: u32) -> Result<(), Error> { + let (name, reg) = Self::map_clock_index(index) + .ok_or(Error::InvalidArgument) + .inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?; + let regs = self.ensure_init()?; + + match reg { + ClockRegister::Fixed => Ok(()), + ClockRegister::Gate(bit, parent) => { + self.clk_enable_parent(parent)?; + log::info!("jh7110-aoncrg: enable {name:?} @ {index}"); + let lock = regs.lock(); + lock.CLOCKS[index as usize].set(lock.CLOCKS[index as usize].get() | (1 << bit)); + Ok(()) + } + ClockRegister::Unimp => { + log::warn!("jh7110-aoncrg: unimplemented clock {name:?}"); + Err(Error::NotImplemented) + } + ClockRegister::FixedDiv(_, parent) => { + self.clk_enable_parent(parent)?; + Ok(()) + } + } + } + + fn clk_enable_parent(&self, parent: ClockParent) -> Result<(), Error> { + match parent { + ClockParent::Int(index) => self.clk_enable_int(index), + ClockParent::Ext(clock) => self.clock_parents[clock].enable(), + } + } + + fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> { + use ClockParent::*; + use ClockRegister::*; + + const CLOCK_MAP: &[(&'static str, ClockRegister)] = &[ + /* 0 */ ("clk_osc", FixedDiv(4, Ext(PARENT_OSC))), + /* 1 */ ("clk_aon_apb_func", Unimp), + /* 2 */ ("clk_gmac5_ahb", Gate(31, Ext(PARENT_STG_AXIAHB))), + /* 3 */ ("clk_gmac5_axi", Gate(31, Ext(PARENT_STG_AXIAHB))), + /* 4 */ ("clk_gmac5_rmii_rtx", Unimp), + /* 5 */ ("clk_gmac5_axi64_tx", Fixed), + /* 6 */ ("clk_gmac5_axi64_tx_inv", Gate(30, Int(5))), ]; - let (_, offset, mode) = CLOCK_MAP.get(index as usize)?; - Some((*offset, *mode)) + + CLOCK_MAP.get(index as usize).copied() } } @@ -77,21 +132,8 @@ impl Device for 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(()) + let index = clock.ok_or(Error::InvalidArgument)?; + self.clk_enable_int(index) } fn disable_clock(&self, clock: Option) -> Result<(), Error> { @@ -149,10 +191,22 @@ impl DeviceTreeResetController for Aoncrg { device_tree_driver! { compatible: ["starfive,jh7110-aoncrg"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; + + let clock_parents = [ + node.named_clock("osc")?, + node.named_clock("gmac0_rmii_refin")?, + node.named_clock("gmac0_rgmii_rxin")?, + node.named_clock("stg_axiahb")?, + node.named_clock("apb_bus")?, + node.named_clock("gmac0_gtxclk")?, + node.named_clock("rtc_osc")?, + ]; + let aoncrg = Arc::new(Aoncrg { base, + clock_parents, mapping: OneTimeInit::new() }); node.make_reset_controller(aoncrg.clone()); diff --git a/kernel/src/device/clock/jh7110_syscrg.rs b/kernel/src/device/clock/jh7110_syscrg.rs index 42355416..3359d195 100644 --- a/kernel/src/device/clock/jh7110_syscrg.rs +++ b/kernel/src/device/clock/jh7110_syscrg.rs @@ -26,7 +26,6 @@ struct Syscrg { #[derive(Debug, Clone, Copy)] enum ClockParent { - #[allow(unused)] Int(u32), Ext(usize), None, @@ -37,9 +36,9 @@ enum ClockRegister { // Clock gate Gate(u32, ClockParent), // Clock inverter - Inv(u32), - // Clock delay selector (TODO) - Delay, + Inv(u32, ClockParent), + // Clock divider (TODO) + Div(ClockParent), Unimp, } @@ -51,27 +50,69 @@ impl Syscrg { }) } + fn clk_enable_int(&self, index: u32, depth: u32) -> Result<(), Error> { + let (name, reg) = Self::map_clock_index(index) + .ok_or(Error::InvalidArgument) + .inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", index))?; + let regs = self.ensure_init()?; + + match reg { + ClockRegister::Gate(bit, parent) => { + log::info!("jh7110-syscrg: enable {name:?} @ {index} /{depth}"); + self.clk_enable_parent(parent, depth)?; + let mut lock = regs.lock(); + lock[index as usize] |= 1 << bit; + Ok(()) + } + ClockRegister::Inv(bit, parent) => { + log::info!("jh7110-syscrg: enable clk inv {name:?} @ {index}"); + self.clk_enable_parent(parent, depth)?; + let mut lock = regs.lock(); + lock[index as usize] |= 1 << bit; + Ok(()) + } + ClockRegister::Div(parent) => self.clk_enable_parent(parent, depth), + ClockRegister::Unimp => { + log::warn!("jh7110-syscrg: clock not implemented: {name:?}"); + Err(Error::NotImplemented) + } + } + } + + fn clk_enable_parent(&self, parent: ClockParent, depth: u32) -> Result<(), Error> { + match parent { + ClockParent::Int(index) => self.clk_enable_int(index, depth + 1), + ClockParent::Ext(clock) => self.parents.get(clock).ok_or(Error::DoesNotExist)?.enable(), + ClockParent::None => Ok(()), + } + } + fn map_clock_index(index: u32) -> Option<(&'static str, ClockRegister)> { const CLOCKS: &[(&'static str, ClockRegister)] = &const { use ClockParent::*; use ClockRegister::*; let mut t = [("", Unimp); 256]; - t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, None)); - t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, None)); - t[0x18C / 4] = ("clk_gmac_source", Unimp); - t[0x190 / 4] = ("clk_gmac1_gtx", Unimp); + + t[0x01C / 4] = ("clk_axi_cfg0", Div(None)); + t[0x020 / 4] = ("clk_stg_axiahb", Div(Int(0x01C / 4))); + t[0x024 / 4] = ("clk_ahb0", Gate(31, Int(0x020 / 4))); + + t[0x184 / 4] = ("clk_gmac5_axi64_ahb", Gate(31, Int(0x024 / 4))); + t[0x188 / 4] = ("clk_gmac5_axi64_axi", Gate(31, Int(0x020 / 4))); + t[0x18C / 4] = ("clk_gmac_source", Div(None)); + t[0x190 / 4] = ("clk_gmac1_gtx", Gate(31, None)); t[0x194 / 4] = ("clk_gmac1_rmii_rtx", Unimp); - t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, None)); + t[0x198 / 4] = ("clk_gmac5_axi64_ptp", Gate(31, Int(0x18C / 4))); t[0x19C / 4] = ("clk_gmac5_axi64_rx", Unimp); - t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30)); + t[0x1A0 / 4] = ("clk_gmac5_axi64_rx_inv", Inv(30, Int(0x19C / 4))); t[0x1A4 / 4] = ("clk_gmac5_axi64_tx", Gate(31, None)); - t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30)); - t[0x1AC / 4] = ("clk_gmac1_gtxc", Delay); + t[0x1A8 / 4] = ("clk_gmac5_axi64_tx_inv", Inv(30, Int(0x1A4 / 4))); + t[0x1AC / 4] = ("clk_gmac1_gtxc", Gate(31, Int(0x190 / 4))); t[0x1B0 / 4] = ("clk_gmac0_gtx", Gate(31, None)); - t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, None)); + t[0x1B4 / 4] = ("clk_gmac0_ptp", Gate(31, Int(0x18C / 4))); t[0x1B8 / 4] = ("clk_gmac_phy", Gate(31, None)); - t[0x1BC / 4] = ("clk_gmac0_gtxc", Delay); + t[0x1BC / 4] = ("clk_gmac0_gtxc", Gate(31, Int(0x1B0 / 4))); t[0x244 / 4] = ("clk_u0_uart_apb", Gate(31, None)); t[0x248 / 4] = ("clk_u0_uart_core", Gate(31, Ext(PARENT_CLK_OSC))); @@ -98,29 +139,7 @@ impl Device for Syscrg { impl ClockController for Syscrg { fn enable_clock(&self, clock: Option) -> Result<(), Error> { let index = clock.ok_or(Error::InvalidArgument)?; - let (name, reg) = Self::map_clock_index(index) - .ok_or(Error::InvalidArgument) - .inspect_err(|_| log::warn!("jh7110-syscrg: undefined clock {:?}", clock))?; - let regs = self.ensure_init()?; - let mut lock = regs.lock(); - - match reg { - ClockRegister::Gate(bit, _) => { - log::info!("jh7110-syscrg: enable {name:?}"); - lock[index as usize] |= 1 << bit; - Ok(()) - } - ClockRegister::Inv(bit) => { - log::info!("jh7110-syscrg: enable clk inv {name:?}"); - lock[index as usize] |= 1 << bit; - Ok(()) - } - ClockRegister::Delay => Ok(()), - ClockRegister::Unimp => { - log::warn!("jh7110-syscrg: clock not implemented: {name:?}"); - Err(Error::NotImplemented) - } - } + self.clk_enable_int(index, 0) } fn disable_clock(&self, clock: Option) -> Result<(), Error> { @@ -146,7 +165,7 @@ impl ClockController for Syscrg { Err(Error::NotImplemented) } }, - ClockRegister::Unimp | ClockRegister::Delay | ClockRegister::Inv(_) => { + ClockRegister::Unimp | ClockRegister::Div(_) | ClockRegister::Inv(_, _) => { log::warn!("jh7110-syscrg: unimplemented clock {:?}", name); Err(Error::NotImplemented) } @@ -159,25 +178,45 @@ impl ClockController for Syscrg { } } +impl Syscrg { + fn rst_trigger(&self, reset: u32, assert: bool) -> Result<(), Error> { + let reg = (190 + reset / 32) as usize; + let bit = reset % 32; + let regs = self.ensure_init()?; + let mut regs = regs.lock(); + + let expect = if assert { + regs[reg] |= 1 << bit; + 1 << bit + } else { + regs[reg] &= !(1 << bit); + 0 + }; + + let mut timeout = 1 << 20; + while timeout > 0 && regs[reg] & (1 << bit) != expect { + core::hint::spin_loop(); + timeout -= 1; + } + + if timeout > 0 { + Ok(()) + } else { + log::warn!("jh7110-syscrg: reset timeout {reset}"); + Err(Error::TimedOut) + } + } +} + impl ResetController for Syscrg { fn assert_reset(&self, reset: Option) -> Result<(), Error> { let reset = reset.ok_or(Error::InvalidArgument)?; - let reg = reset / 32; - let bit = reset % 32; - let regs = self.ensure_init()?; - - regs.lock()[190 + reg as usize] |= 1 << bit; - Ok(()) + self.rst_trigger(reset, true) } fn deassert_reset(&self, reset: Option) -> Result<(), Error> { let reset = reset.ok_or(Error::InvalidArgument)?; - let reg = reset / 32; - let bit = reset % 32; - let regs = self.ensure_init()?; - - regs.lock()[190 + reg as usize] &= !(1 << bit); - Ok(()) + self.rst_trigger(reset, false) } } @@ -210,7 +249,7 @@ impl DeviceTreeResetController for Syscrg { device_tree_driver! { compatible: ["starfive,jh7110-syscrg"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; let osc = node.named_clock("osc")?; diff --git a/kernel/src/device/interrupt/riscv_plic.rs b/kernel/src/device/interrupt/riscv_plic.rs index 4e84b552..7c5ebadb 100644 --- a/kernel/src/device/interrupt/riscv_plic.rs +++ b/kernel/src/device/interrupt/riscv_plic.rs @@ -82,7 +82,7 @@ struct Context { enable: IrqSafeRwLock>, control: IrqSafeRwLock>, // TODO scale the table depending on effective MAX_IRQS value - table: IrqSafeRwLock>, + table: IrqSafeRwLock>, } struct Inner { @@ -288,7 +288,7 @@ fn map_context_to_hart(target: u32) -> Option { device_tree_driver! { compatible: ["starfive,jh7110-plic", "sifive,plic-1.0.0", "riscv,plic0"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; let ndev = node.prop_usize("riscv,ndev")?; let iext = node.property("interrupts-extended")?; diff --git a/kernel/src/device/serial/ns16550a.rs b/kernel/src/device/serial/ns16550a.rs index aa3d9042..240ee2f2 100644 --- a/kernel/src/device/serial/ns16550a.rs +++ b/kernel/src/device/serial/ns16550a.rs @@ -190,7 +190,7 @@ impl DebugSink for Ns16550a { device_tree_driver!( compatible: ["ns16550a"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; log::debug!("ns16550a base = {base:#x}"); let irq = node.interrupt(0)?; diff --git a/kernel/src/device/serial/snps_dw_apb_uart.rs b/kernel/src/device/serial/snps_dw_apb_uart.rs index 7febbdbb..ea889916 100644 --- a/kernel/src/device/serial/snps_dw_apb_uart.rs +++ b/kernel/src/device/serial/snps_dw_apb_uart.rs @@ -284,7 +284,7 @@ impl TerminalOutput for Inner { device_tree_driver! { compatible: ["snps,dw-apb-uart"], driver: { - fn probe(&self, node: &Arc, context: &ProbeContext) -> Option> { + fn probe(&self, node: &Arc, context: &mut ProbeContext) -> Option> { let base = node.map_base(context, 0)?; let irq = node.interrupt(0)?; let clk_baud = node.named_clock("baudclk")?; diff --git a/kernel/src/init.rs b/kernel/src/init.rs index c2ae958c..7f02ec50 100644 --- a/kernel/src/init.rs +++ b/kernel/src/init.rs @@ -33,6 +33,29 @@ pub fn kinit() -> Result<(), Error> { assert!(!ArchitectureImpl::interrupt_mask()); log::info!("In main"); + // Initialize late device tree devices + #[cfg(any(rust_analyzer, target_arch = "riscv64", target_arch = "aarch64"))] + { + use device_tree::driver::InitSequence; + + device_tree::driver::lazy_init( + |_| (), + |node, error| { + log::error!("{}: {error:?}", node.name().unwrap_or("")); + }, + InitSequence::Late, + ); + device_tree::driver::init_irqs( + |_| (), + |node, error| { + log::error!( + "{}: irq init error: {error:?}", + node.name().unwrap_or("") + ); + }, + InitSequence::Late, + ); + } // Initialize PCI devices if let Err(error) = PciBusManager::setup_bus_devices(false) { log::error!("pci bus setup error: {error:?}"); diff --git a/kernel/src/syscall/mod.rs b/kernel/src/syscall/mod.rs index f1e1ebce..1532470a 100644 --- a/kernel/src/syscall/mod.rs +++ b/kernel/src/syscall/mod.rs @@ -1,9 +1,17 @@ //! System function call handlers -use abi::{error::Error, io::RawFd, process::SignalEntryData, SyscallFunction}; +use abi::{ + error::Error, + io::RawFd, + process::{ExitCode, Signal, SignalEntryData}, + SyscallFunction, +}; use kernel_arch::task::TaskFrame; use libk::{ - task::process::{Process, ProcessIo}, + task::{ + process::{Process, ProcessIo}, + thread::Thread, + }, vfs::NodeRef, }; use libk_util::sync::IrqSafeSpinlockGuard; @@ -53,7 +61,10 @@ pub unsafe fn handle_signal_exit(frame: &mut F) { let saved_data: &SignalEntryData = match arg::ref_const(frame.argument() as _) { Ok(r) => r, Err(err) => { - todo!("Invalid SignalEntryData pointer: {:?}", err) + let thread = Thread::current(); + let process = thread.process(); + log::warn!("#{}: invalid SignalEntryData struct: {err:?}", process.id); + thread.exit_process(ExitCode::BySignal(Ok(Signal::MemoryAccessViolation))); } };