905 lines · 30.9 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com> //! Network PHY device.//!//! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h). use crate::{bindings, error::*, prelude::*, str::CStr, types::Opaque}; use core::marker::PhantomData; /// PHY state machine states.////// Corresponds to the kernel's [`enum phy_state`].////// Some of PHY drivers access to the state of PHY's software state machine.////// [`enum phy_state`]: srctree/include/linux/phy.h#[derive(PartialEq, Eq)]pub enum DeviceState {    /// PHY device and driver are not ready for anything.    Down,    /// PHY is ready to send and receive packets.    Ready,    /// PHY is up, but no polling or interrupts are done.    Halted,    /// PHY is up, but is in an error state.    Error,    /// PHY and attached device are ready to do work.    Up,    /// PHY is currently running.    Running,    /// PHY is up, but not currently plugged in.    NoLink,    /// PHY is performing a cable test.    CableTest,} /// A mode of Ethernet communication.////// PHY drivers get duplex information from hardware and update the current state.pub enum DuplexMode {    /// PHY is in full-duplex mode.    Full,    /// PHY is in half-duplex mode.    Half,    /// PHY is in unknown duplex mode.    Unknown,} /// An instance of a PHY device.////// Wraps the kernel's [`struct phy_device`].////// A [`Device`] instance is created when a callback in [`Driver`] is executed. A PHY driver/// executes [`Driver`]'s methods during the callback.////// # Invariants////// Referencing a `phy_device` using this struct asserts that you are in/// a context where all methods defined on this struct are safe to call.////// [`struct phy_device`]: srctree/include/linux/phy.h// During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is// unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for// [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with// the lock held, thus guaranteeing that [`Driver::resume`] has exclusive access to the instance.// [`Driver::resume`] and [`Driver::suspend`] also are called where only one thread can access// to the instance.#[repr(transparent)]pub struct Device(Opaque<bindings::phy_device>); impl Device {    /// Creates a new [`Device`] instance from a raw pointer.    ///    /// # Safety    ///    /// For the duration of 'a, the pointer must point at a valid `phy_device`,    /// and the caller must be in a context where all methods defined on this struct    /// are safe to call.    unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.        let ptr = ptr.cast::<Self>();        // SAFETY: by the function requirements the pointer is valid and we have unique access for        // the duration of `'a`.        unsafe { &mut *ptr }    }     /// Gets the id of the PHY.    pub fn phy_id(&self) -> u32 {        let phydev = self.0.get();        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        unsafe { (*phydev).phy_id }    }     /// Gets the state of PHY state machine states.    pub fn state(&self) -> DeviceState {        let phydev = self.0.get();        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        let state = unsafe { (*phydev).state };        // TODO: this conversion code will be replaced with automatically generated code by bindgen        // when it becomes possible.        match state {            bindings::phy_state_PHY_DOWN => DeviceState::Down,            bindings::phy_state_PHY_READY => DeviceState::Ready,            bindings::phy_state_PHY_HALTED => DeviceState::Halted,            bindings::phy_state_PHY_ERROR => DeviceState::Error,            bindings::phy_state_PHY_UP => DeviceState::Up,            bindings::phy_state_PHY_RUNNING => DeviceState::Running,            bindings::phy_state_PHY_NOLINK => DeviceState::NoLink,            bindings::phy_state_PHY_CABLETEST => DeviceState::CableTest,            _ => DeviceState::Error,        }    }     /// Gets the current link state.    ///    /// It returns true if the link is up.    pub fn is_link_up(&self) -> bool {        const LINK_IS_UP: u64 = 1;        // TODO: the code to access to the bit field will be replaced with automatically        // generated code by bindgen when it becomes possible.        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };        bit_field.get(14, 1) == LINK_IS_UP    }     /// Gets the current auto-negotiation configuration.    ///    /// It returns true if auto-negotiation is enabled.    pub fn is_autoneg_enabled(&self) -> bool {        // TODO: the code to access to the bit field will be replaced with automatically        // generated code by bindgen when it becomes possible.        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };        bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64    }     /// Gets the current auto-negotiation state.    ///    /// It returns true if auto-negotiation is completed.    pub fn is_autoneg_completed(&self) -> bool {        const AUTONEG_COMPLETED: u64 = 1;        // TODO: the code to access to the bit field will be replaced with automatically        // generated code by bindgen when it becomes possible.        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };        bit_field.get(15, 1) == AUTONEG_COMPLETED    }     /// Sets the speed of the PHY.    pub fn set_speed(&mut self, speed: u32) {        let phydev = self.0.get();        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        unsafe { (*phydev).speed = speed as i32 };    }     /// Sets duplex mode.    pub fn set_duplex(&mut self, mode: DuplexMode) {        let phydev = self.0.get();        let v = match mode {            DuplexMode::Full => bindings::DUPLEX_FULL as i32,            DuplexMode::Half => bindings::DUPLEX_HALF as i32,            DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN as i32,        };        // SAFETY: The struct invariant ensures that we may access        // this field without additional synchronization.        unsafe { (*phydev).duplex = v };    }     /// Reads a given C22 PHY register.    // This function reads a hardware register and updates the stats so takes `&mut self`.    pub fn read(&mut self, regnum: u16) -> Result<u16> {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call, open code of `phy_read()` with a valid `phy_device` pointer        // `phydev`.        let ret = unsafe {            bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into())        };        if ret < 0 {            Err(Error::from_errno(ret))        } else {            Ok(ret as u16)        }    }     /// Writes a given C22 PHY register.    pub fn write(&mut self, regnum: u16, val: u16) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call, open code of `phy_write()` with a valid `phy_device` pointer        // `phydev`.        to_result(unsafe {            bindings::mdiobus_write((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into(), val)        })    }     /// Reads a paged register.    pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) };        if ret < 0 {            Err(Error::from_errno(ret))        } else {            Ok(ret as u16)        }    }     /// Resolves the advertisements into PHY settings.    pub fn resolve_aneg_linkmode(&mut self) {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        unsafe { bindings::phy_resolve_aneg_linkmode(phydev) };    }     /// Executes software reset the PHY via `BMCR_RESET` bit.    pub fn genphy_soft_reset(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_soft_reset(phydev) })    }     /// Initializes the PHY.    pub fn init_hw(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::phy_init_hw(phydev) })    }     /// Starts auto-negotiation.    pub fn start_aneg(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::_phy_start_aneg(phydev) })    }     /// Resumes the PHY via `BMCR_PDOWN` bit.    pub fn genphy_resume(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_resume(phydev) })    }     /// Suspends the PHY via `BMCR_PDOWN` bit.    pub fn genphy_suspend(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_suspend(phydev) })    }     /// Checks the link status and updates current link state.    pub fn genphy_read_status(&mut self) -> Result<u16> {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        let ret = unsafe { bindings::genphy_read_status(phydev) };        if ret < 0 {            Err(Error::from_errno(ret))        } else {            Ok(ret as u16)        }    }     /// Updates the link status.    pub fn genphy_update_link(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_update_link(phydev) })    }     /// Reads link partner ability.    pub fn genphy_read_lpa(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_read_lpa(phydev) })    }     /// Reads PHY abilities.    pub fn genphy_read_abilities(&mut self) -> Result {        let phydev = self.0.get();        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.        // So it's just an FFI call.        to_result(unsafe { bindings::genphy_read_abilities(phydev) })    }} /// Defines certain other features this PHY supports (like interrupts).////// These flag values are used in [`Driver::FLAGS`].pub mod flags {    /// PHY is internal.    pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL;    /// PHY needs to be reset after the refclk is enabled.    pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN;    /// Polling is used to detect PHY status changes.    pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST;    /// Don't suspend.    pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND;} /// An adapter for the registration of a PHY driver.struct Adapter<T: Driver> {    _p: PhantomData<T>,} impl<T: Driver> Adapter<T> {    /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn soft_reset_callback(        phydev: *mut bindings::phy_device,    ) -> core::ffi::c_int {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            T::soft_reset(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn get_features_callback(        phydev: *mut bindings::phy_device,    ) -> core::ffi::c_int {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            T::get_features(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {        from_result(|| {            // SAFETY: The C core code ensures that the accessors on            // `Device` are okay to call even though `phy_device->lock`            // might not be held.            let dev = unsafe { Device::from_raw(phydev) };            T::suspend(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {        from_result(|| {            // SAFETY: The C core code ensures that the accessors on            // `Device` are okay to call even though `phy_device->lock`            // might not be held.            let dev = unsafe { Device::from_raw(phydev) };            T::resume(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn config_aneg_callback(        phydev: *mut bindings::phy_device,    ) -> core::ffi::c_int {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            T::config_aneg(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn read_status_callback(        phydev: *mut bindings::phy_device,    ) -> core::ffi::c_int {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            T::read_status(dev)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn match_phy_device_callback(        phydev: *mut bindings::phy_device,    ) -> core::ffi::c_int {        // SAFETY: This callback is called only in contexts        // where we hold `phy_device->lock`, so the accessors on        // `Device` are okay to call.        let dev = unsafe { Device::from_raw(phydev) };        T::match_phy_device(dev) as i32    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn read_mmd_callback(        phydev: *mut bindings::phy_device,        devnum: i32,        regnum: u16,    ) -> i32 {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            // CAST: the C side verifies devnum < 32.            let ret = T::read_mmd(dev, devnum as u8, regnum)?;            Ok(ret.into())        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn write_mmd_callback(        phydev: *mut bindings::phy_device,        devnum: i32,        regnum: u16,        val: u16,    ) -> i32 {        from_result(|| {            // SAFETY: This callback is called only in contexts            // where we hold `phy_device->lock`, so the accessors on            // `Device` are okay to call.            let dev = unsafe { Device::from_raw(phydev) };            T::write_mmd(dev, devnum as u8, regnum, val)?;            Ok(0)        })    }     /// # Safety    ///    /// `phydev` must be passed by the corresponding callback in `phy_driver`.    unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) {        // SAFETY: This callback is called only in contexts        // where we hold `phy_device->lock`, so the accessors on        // `Device` are okay to call.        let dev = unsafe { Device::from_raw(phydev) };        T::link_change_notify(dev);    }} /// Driver structure for a particular PHY type.////// Wraps the kernel's [`struct phy_driver`]./// This is used to register a driver for a particular PHY type with the kernel.////// # Invariants////// `self.0` is always in a valid state.////// [`struct phy_driver`]: srctree/include/linux/phy.h#[repr(transparent)]pub struct DriverVTable(Opaque<bindings::phy_driver>); // SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to// share `&DriverVTable` across execution context boundries.unsafe impl Sync for DriverVTable {} /// Creates a [`DriverVTable`] instance from [`Driver`].////// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`.///

Lines 1–500 of 905.