brintos

brintos / linux-shallow public Read only

0
0
Text · 31.1 KiB · 910ce86 Raw
918 lines · rust
1// SPDX-License-Identifier: GPL-2.02 3// Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com>4 5//! Network PHY device.6//!7//! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).8 9use crate::{error::*, prelude::*, types::Opaque};10use core::{marker::PhantomData, ptr::addr_of_mut};11 12pub mod reg;13 14/// PHY state machine states.15///16/// Corresponds to the kernel's [`enum phy_state`].17///18/// Some of PHY drivers access to the state of PHY's software state machine.19///20/// [`enum phy_state`]: srctree/include/linux/phy.h21#[derive(PartialEq, Eq)]22pub enum DeviceState {23    /// PHY device and driver are not ready for anything.24    Down,25    /// PHY is ready to send and receive packets.26    Ready,27    /// PHY is up, but no polling or interrupts are done.28    Halted,29    /// PHY is up, but is in an error state.30    Error,31    /// PHY and attached device are ready to do work.32    Up,33    /// PHY is currently running.34    Running,35    /// PHY is up, but not currently plugged in.36    NoLink,37    /// PHY is performing a cable test.38    CableTest,39}40 41/// A mode of Ethernet communication.42///43/// PHY drivers get duplex information from hardware and update the current state.44pub enum DuplexMode {45    /// PHY is in full-duplex mode.46    Full,47    /// PHY is in half-duplex mode.48    Half,49    /// PHY is in unknown duplex mode.50    Unknown,51}52 53/// An instance of a PHY device.54///55/// Wraps the kernel's [`struct phy_device`].56///57/// A [`Device`] instance is created when a callback in [`Driver`] is executed. A PHY driver58/// executes [`Driver`]'s methods during the callback.59///60/// # Invariants61///62/// - Referencing a `phy_device` using this struct asserts that you are in63///   a context where all methods defined on this struct are safe to call.64/// - This struct always has a valid `self.0.mdio.dev`.65///66/// [`struct phy_device`]: srctree/include/linux/phy.h67// During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is68// unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for69// [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with70// the lock held, thus guaranteeing that [`Driver::resume`] has exclusive access to the instance.71// [`Driver::resume`] and [`Driver::suspend`] also are called where only one thread can access72// to the instance.73#[repr(transparent)]74pub struct Device(Opaque<bindings::phy_device>);75 76impl Device {77    /// Creates a new [`Device`] instance from a raw pointer.78    ///79    /// # Safety80    ///81    /// For the duration of `'a`,82    /// - the pointer must point at a valid `phy_device`, and the caller83    ///   must be in a context where all methods defined on this struct84    ///   are safe to call.85    /// - `(*ptr).mdio.dev` must be a valid.86    unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {87        // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.88        let ptr = ptr.cast::<Self>();89        // SAFETY: by the function requirements the pointer is valid and we have unique access for90        // the duration of `'a`.91        unsafe { &mut *ptr }92    }93 94    /// Gets the id of the PHY.95    pub fn phy_id(&self) -> u32 {96        let phydev = self.0.get();97        // SAFETY: The struct invariant ensures that we may access98        // this field without additional synchronization.99        unsafe { (*phydev).phy_id }100    }101 102    /// Gets the state of PHY state machine states.103    pub fn state(&self) -> DeviceState {104        let phydev = self.0.get();105        // SAFETY: The struct invariant ensures that we may access106        // this field without additional synchronization.107        let state = unsafe { (*phydev).state };108        // TODO: this conversion code will be replaced with automatically generated code by bindgen109        // when it becomes possible.110        match state {111            bindings::phy_state_PHY_DOWN => DeviceState::Down,112            bindings::phy_state_PHY_READY => DeviceState::Ready,113            bindings::phy_state_PHY_HALTED => DeviceState::Halted,114            bindings::phy_state_PHY_ERROR => DeviceState::Error,115            bindings::phy_state_PHY_UP => DeviceState::Up,116            bindings::phy_state_PHY_RUNNING => DeviceState::Running,117            bindings::phy_state_PHY_NOLINK => DeviceState::NoLink,118            bindings::phy_state_PHY_CABLETEST => DeviceState::CableTest,119            _ => DeviceState::Error,120        }121    }122 123    /// Gets the current link state.124    ///125    /// It returns true if the link is up.126    pub fn is_link_up(&self) -> bool {127        const LINK_IS_UP: u64 = 1;128        // TODO: the code to access to the bit field will be replaced with automatically129        // generated code by bindgen when it becomes possible.130        // SAFETY: The struct invariant ensures that we may access131        // this field without additional synchronization.132        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };133        bit_field.get(14, 1) == LINK_IS_UP134    }135 136    /// Gets the current auto-negotiation configuration.137    ///138    /// It returns true if auto-negotiation is enabled.139    pub fn is_autoneg_enabled(&self) -> bool {140        // TODO: the code to access to the bit field will be replaced with automatically141        // generated code by bindgen when it becomes possible.142        // SAFETY: The struct invariant ensures that we may access143        // this field without additional synchronization.144        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };145        bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64146    }147 148    /// Gets the current auto-negotiation state.149    ///150    /// It returns true if auto-negotiation is completed.151    pub fn is_autoneg_completed(&self) -> bool {152        const AUTONEG_COMPLETED: u64 = 1;153        // TODO: the code to access to the bit field will be replaced with automatically154        // generated code by bindgen when it becomes possible.155        // SAFETY: The struct invariant ensures that we may access156        // this field without additional synchronization.157        let bit_field = unsafe { &(*self.0.get())._bitfield_1 };158        bit_field.get(15, 1) == AUTONEG_COMPLETED159    }160 161    /// Sets the speed of the PHY.162    pub fn set_speed(&mut self, speed: u32) {163        let phydev = self.0.get();164        // SAFETY: The struct invariant ensures that we may access165        // this field without additional synchronization.166        unsafe { (*phydev).speed = speed as i32 };167    }168 169    /// Sets duplex mode.170    pub fn set_duplex(&mut self, mode: DuplexMode) {171        let phydev = self.0.get();172        let v = match mode {173            DuplexMode::Full => bindings::DUPLEX_FULL as i32,174            DuplexMode::Half => bindings::DUPLEX_HALF as i32,175            DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN as i32,176        };177        // SAFETY: The struct invariant ensures that we may access178        // this field without additional synchronization.179        unsafe { (*phydev).duplex = v };180    }181 182    /// Reads a PHY register.183    // This function reads a hardware register and updates the stats so takes `&mut self`.184    pub fn read<R: reg::Register>(&mut self, reg: R) -> Result<u16> {185        reg.read(self)186    }187 188    /// Writes a PHY register.189    pub fn write<R: reg::Register>(&mut self, reg: R, val: u16) -> Result {190        reg.write(self, val)191    }192 193    /// Reads a paged register.194    pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> {195        let phydev = self.0.get();196        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.197        // So it's just an FFI call.198        let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) };199        if ret < 0 {200            Err(Error::from_errno(ret))201        } else {202            Ok(ret as u16)203        }204    }205 206    /// Resolves the advertisements into PHY settings.207    pub fn resolve_aneg_linkmode(&mut self) {208        let phydev = self.0.get();209        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.210        // So it's just an FFI call.211        unsafe { bindings::phy_resolve_aneg_linkmode(phydev) };212    }213 214    /// Executes software reset the PHY via `BMCR_RESET` bit.215    pub fn genphy_soft_reset(&mut self) -> Result {216        let phydev = self.0.get();217        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.218        // So it's just an FFI call.219        to_result(unsafe { bindings::genphy_soft_reset(phydev) })220    }221 222    /// Initializes the PHY.223    pub fn init_hw(&mut self) -> Result {224        let phydev = self.0.get();225        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.226        // So it's just an FFI call.227        to_result(unsafe { bindings::phy_init_hw(phydev) })228    }229 230    /// Starts auto-negotiation.231    pub fn start_aneg(&mut self) -> Result {232        let phydev = self.0.get();233        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.234        // So it's just an FFI call.235        to_result(unsafe { bindings::_phy_start_aneg(phydev) })236    }237 238    /// Resumes the PHY via `BMCR_PDOWN` bit.239    pub fn genphy_resume(&mut self) -> Result {240        let phydev = self.0.get();241        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.242        // So it's just an FFI call.243        to_result(unsafe { bindings::genphy_resume(phydev) })244    }245 246    /// Suspends the PHY via `BMCR_PDOWN` bit.247    pub fn genphy_suspend(&mut self) -> Result {248        let phydev = self.0.get();249        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.250        // So it's just an FFI call.251        to_result(unsafe { bindings::genphy_suspend(phydev) })252    }253 254    /// Checks the link status and updates current link state.255    pub fn genphy_read_status<R: reg::Register>(&mut self) -> Result<u16> {256        R::read_status(self)257    }258 259    /// Updates the link status.260    pub fn genphy_update_link(&mut self) -> Result {261        let phydev = self.0.get();262        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.263        // So it's just an FFI call.264        to_result(unsafe { bindings::genphy_update_link(phydev) })265    }266 267    /// Reads link partner ability.268    pub fn genphy_read_lpa(&mut self) -> Result {269        let phydev = self.0.get();270        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.271        // So it's just an FFI call.272        to_result(unsafe { bindings::genphy_read_lpa(phydev) })273    }274 275    /// Reads PHY abilities.276    pub fn genphy_read_abilities(&mut self) -> Result {277        let phydev = self.0.get();278        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.279        // So it's just an FFI call.280        to_result(unsafe { bindings::genphy_read_abilities(phydev) })281    }282}283 284impl AsRef<kernel::device::Device> for Device {285    fn as_ref(&self) -> &kernel::device::Device {286        let phydev = self.0.get();287        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.288        unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }289    }290}291 292/// Defines certain other features this PHY supports (like interrupts).293///294/// These flag values are used in [`Driver::FLAGS`].295pub mod flags {296    /// PHY is internal.297    pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL;298    /// PHY needs to be reset after the refclk is enabled.299    pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN;300    /// Polling is used to detect PHY status changes.301    pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST;302    /// Don't suspend.303    pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND;304}305 306/// An adapter for the registration of a PHY driver.307struct Adapter<T: Driver> {308    _p: PhantomData<T>,309}310 311impl<T: Driver> Adapter<T> {312    /// # Safety313    ///314    /// `phydev` must be passed by the corresponding callback in `phy_driver`.315    unsafe extern "C" fn soft_reset_callback(316        phydev: *mut bindings::phy_device,317    ) -> core::ffi::c_int {318        from_result(|| {319            // SAFETY: This callback is called only in contexts320            // where we hold `phy_device->lock`, so the accessors on321            // `Device` are okay to call.322            let dev = unsafe { Device::from_raw(phydev) };323            T::soft_reset(dev)?;324            Ok(0)325        })326    }327 328    /// # Safety329    ///330    /// `phydev` must be passed by the corresponding callback in `phy_driver`.331    unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {332        from_result(|| {333            // SAFETY: This callback is called only in contexts334            // where we can exclusively access `phy_device` because335            // it's not published yet, so the accessors on `Device` are okay336            // to call.337            let dev = unsafe { Device::from_raw(phydev) };338            T::probe(dev)?;339            Ok(0)340        })341    }342 343    /// # Safety344    ///345    /// `phydev` must be passed by the corresponding callback in `phy_driver`.346    unsafe extern "C" fn get_features_callback(347        phydev: *mut bindings::phy_device,348    ) -> core::ffi::c_int {349        from_result(|| {350            // SAFETY: This callback is called only in contexts351            // where we hold `phy_device->lock`, so the accessors on352            // `Device` are okay to call.353            let dev = unsafe { Device::from_raw(phydev) };354            T::get_features(dev)?;355            Ok(0)356        })357    }358 359    /// # Safety360    ///361    /// `phydev` must be passed by the corresponding callback in `phy_driver`.362    unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {363        from_result(|| {364            // SAFETY: The C core code ensures that the accessors on365            // `Device` are okay to call even though `phy_device->lock`366            // might not be held.367            let dev = unsafe { Device::from_raw(phydev) };368            T::suspend(dev)?;369            Ok(0)370        })371    }372 373    /// # Safety374    ///375    /// `phydev` must be passed by the corresponding callback in `phy_driver`.376    unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {377        from_result(|| {378            // SAFETY: The C core code ensures that the accessors on379            // `Device` are okay to call even though `phy_device->lock`380            // might not be held.381            let dev = unsafe { Device::from_raw(phydev) };382            T::resume(dev)?;383            Ok(0)384        })385    }386 387    /// # Safety388    ///389    /// `phydev` must be passed by the corresponding callback in `phy_driver`.390    unsafe extern "C" fn config_aneg_callback(391        phydev: *mut bindings::phy_device,392    ) -> core::ffi::c_int {393        from_result(|| {394            // SAFETY: This callback is called only in contexts395            // where we hold `phy_device->lock`, so the accessors on396            // `Device` are okay to call.397            let dev = unsafe { Device::from_raw(phydev) };398            T::config_aneg(dev)?;399            Ok(0)400        })401    }402 403    /// # Safety404    ///405    /// `phydev` must be passed by the corresponding callback in `phy_driver`.406    unsafe extern "C" fn read_status_callback(407        phydev: *mut bindings::phy_device,408    ) -> core::ffi::c_int {409        from_result(|| {410            // SAFETY: This callback is called only in contexts411            // where we hold `phy_device->lock`, so the accessors on412            // `Device` are okay to call.413            let dev = unsafe { Device::from_raw(phydev) };414            T::read_status(dev)?;415            Ok(0)416        })417    }418 419    /// # Safety420    ///421    /// `phydev` must be passed by the corresponding callback in `phy_driver`.422    unsafe extern "C" fn match_phy_device_callback(423        phydev: *mut bindings::phy_device,424    ) -> core::ffi::c_int {425        // SAFETY: This callback is called only in contexts426        // where we hold `phy_device->lock`, so the accessors on427        // `Device` are okay to call.428        let dev = unsafe { Device::from_raw(phydev) };429        T::match_phy_device(dev) as i32430    }431 432    /// # Safety433    ///434    /// `phydev` must be passed by the corresponding callback in `phy_driver`.435    unsafe extern "C" fn read_mmd_callback(436        phydev: *mut bindings::phy_device,437        devnum: i32,438        regnum: u16,439    ) -> i32 {440        from_result(|| {441            // SAFETY: This callback is called only in contexts442            // where we hold `phy_device->lock`, so the accessors on443            // `Device` are okay to call.444            let dev = unsafe { Device::from_raw(phydev) };445            // CAST: the C side verifies devnum < 32.446            let ret = T::read_mmd(dev, devnum as u8, regnum)?;447            Ok(ret.into())448        })449    }450 451    /// # Safety452    ///453    /// `phydev` must be passed by the corresponding callback in `phy_driver`.454    unsafe extern "C" fn write_mmd_callback(455        phydev: *mut bindings::phy_device,456        devnum: i32,457        regnum: u16,458        val: u16,459    ) -> i32 {460        from_result(|| {461            // SAFETY: This callback is called only in contexts462            // where we hold `phy_device->lock`, so the accessors on463            // `Device` are okay to call.464            let dev = unsafe { Device::from_raw(phydev) };465            T::write_mmd(dev, devnum as u8, regnum, val)?;466            Ok(0)467        })468    }469 470    /// # Safety471    ///472    /// `phydev` must be passed by the corresponding callback in `phy_driver`.473    unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) {474        // SAFETY: This callback is called only in contexts475        // where we hold `phy_device->lock`, so the accessors on476        // `Device` are okay to call.477        let dev = unsafe { Device::from_raw(phydev) };478        T::link_change_notify(dev);479    }480}481 482/// Driver structure for a particular PHY type.483///484/// Wraps the kernel's [`struct phy_driver`].485/// This is used to register a driver for a particular PHY type with the kernel.486///487/// # Invariants488///489/// `self.0` is always in a valid state.490///491/// [`struct phy_driver`]: srctree/include/linux/phy.h492#[repr(transparent)]493pub struct DriverVTable(Opaque<bindings::phy_driver>);494 495// SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to496// share `&DriverVTable` across execution context boundaries.497unsafe impl Sync for DriverVTable {}498 499/// Creates a [`DriverVTable`] instance from [`Driver`].500///501/// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`.502///503/// [`module_phy_driver`]: crate::module_phy_driver504pub const fn create_phy_driver<T: Driver>() -> DriverVTable {505    // INVARIANT: All the fields of `struct phy_driver` are initialized properly.506    DriverVTable(Opaque::new(bindings::phy_driver {507        name: T::NAME.as_char_ptr().cast_mut(),508        flags: T::FLAGS,509        phy_id: T::PHY_DEVICE_ID.id,510        phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),511        soft_reset: if T::HAS_SOFT_RESET {512            Some(Adapter::<T>::soft_reset_callback)513        } else {514            None515        },516        probe: if T::HAS_PROBE {517            Some(Adapter::<T>::probe_callback)518        } else {519            None520        },521        get_features: if T::HAS_GET_FEATURES {522            Some(Adapter::<T>::get_features_callback)523        } else {524            None525        },526        match_phy_device: if T::HAS_MATCH_PHY_DEVICE {527            Some(Adapter::<T>::match_phy_device_callback)528        } else {529            None530        },531        suspend: if T::HAS_SUSPEND {532            Some(Adapter::<T>::suspend_callback)533        } else {534            None535        },536        resume: if T::HAS_RESUME {537            Some(Adapter::<T>::resume_callback)538        } else {539            None540        },541        config_aneg: if T::HAS_CONFIG_ANEG {542            Some(Adapter::<T>::config_aneg_callback)543        } else {544            None545        },546        read_status: if T::HAS_READ_STATUS {547            Some(Adapter::<T>::read_status_callback)548        } else {549            None550        },551        read_mmd: if T::HAS_READ_MMD {552            Some(Adapter::<T>::read_mmd_callback)553        } else {554            None555        },556        write_mmd: if T::HAS_WRITE_MMD {557            Some(Adapter::<T>::write_mmd_callback)558        } else {559            None560        },561        link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY {562            Some(Adapter::<T>::link_change_notify_callback)563        } else {564            None565        },566        // SAFETY: The rest is zeroed out to initialize `struct phy_driver`,567        // sets `Option<&F>` to be `None`.568        ..unsafe { core::mem::MaybeUninit::<bindings::phy_driver>::zeroed().assume_init() }569    }))570}571 572/// Driver implementation for a particular PHY type.573///574/// This trait is used to create a [`DriverVTable`].575#[vtable]576pub trait Driver {577    /// Defines certain other features this PHY supports.578    /// It is a combination of the flags in the [`flags`] module.579    const FLAGS: u32 = 0;580 581    /// The friendly name of this PHY type.582    const NAME: &'static CStr;583 584    /// This driver only works for PHYs with IDs which match this field.585    /// The default id and mask are zero.586    const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);587 588    /// Issues a PHY software reset.589    fn soft_reset(_dev: &mut Device) -> Result {590        kernel::build_error(VTABLE_DEFAULT_ERROR)591    }592 593    /// Sets up device-specific structures during discovery.594    fn probe(_dev: &mut Device) -> Result {595        kernel::build_error(VTABLE_DEFAULT_ERROR)596    }597 598    /// Probes the hardware to determine what abilities it has.599    fn get_features(_dev: &mut Device) -> Result {600        kernel::build_error(VTABLE_DEFAULT_ERROR)601    }602 603    /// Returns true if this is a suitable driver for the given phydev.604    /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].605    fn match_phy_device(_dev: &Device) -> bool {606        false607    }608 609    /// Configures the advertisement and resets auto-negotiation610    /// if auto-negotiation is enabled.611    fn config_aneg(_dev: &mut Device) -> Result {612        kernel::build_error(VTABLE_DEFAULT_ERROR)613    }614 615    /// Determines the negotiated speed and duplex.616    fn read_status(_dev: &mut Device) -> Result<u16> {617        kernel::build_error(VTABLE_DEFAULT_ERROR)618    }619 620    /// Suspends the hardware, saving state if needed.621    fn suspend(_dev: &mut Device) -> Result {622        kernel::build_error(VTABLE_DEFAULT_ERROR)623    }624 625    /// Resumes the hardware, restoring state if needed.626    fn resume(_dev: &mut Device) -> Result {627        kernel::build_error(VTABLE_DEFAULT_ERROR)628    }629 630    /// Overrides the default MMD read function for reading a MMD register.631    fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> {632        kernel::build_error(VTABLE_DEFAULT_ERROR)633    }634 635    /// Overrides the default MMD write function for writing a MMD register.636    fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result {637        kernel::build_error(VTABLE_DEFAULT_ERROR)638    }639 640    /// Callback for notification of link change.641    fn link_change_notify(_dev: &mut Device) {}642}643 644/// Registration structure for PHY drivers.645///646/// Registers [`DriverVTable`] instances with the kernel. They will be unregistered when dropped.647///648/// # Invariants649///650/// The `drivers` slice are currently registered to the kernel via `phy_drivers_register`.651pub struct Registration {652    drivers: Pin<&'static mut [DriverVTable]>,653}654 655// SAFETY: The only action allowed in a `Registration` instance is dropping it, which is safe to do656// from any thread because `phy_drivers_unregister` can be called from any thread context.657unsafe impl Send for Registration {}658 659impl Registration {660    /// Registers a PHY driver.661    pub fn register(662        module: &'static crate::ThisModule,663        drivers: Pin<&'static mut [DriverVTable]>,664    ) -> Result<Self> {665        if drivers.is_empty() {666            return Err(code::EINVAL);667        }668        // SAFETY: The type invariants of [`DriverVTable`] ensure that all elements of669        // the `drivers` slice are initialized properly. `drivers` will not be moved.670        // So it's just an FFI call.671        to_result(unsafe {672            bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)673        })?;674        // INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.675        Ok(Registration { drivers })676    }677}678 679impl Drop for Registration {680    fn drop(&mut self) {681        // SAFETY: The type invariants guarantee that `self.drivers` is valid.682        // So it's just an FFI call.683        unsafe {684            bindings::phy_drivers_unregister(self.drivers[0].0.get(), self.drivers.len() as i32)685        };686    }687}688 689/// An identifier for PHY devices on an MDIO/MII bus.690///691/// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate692/// PHY driver.693pub struct DeviceId {694    id: u32,695    mask: DeviceMask,696}697 698impl DeviceId {699    /// Creates a new instance with the exact match mask.700    pub const fn new_with_exact_mask(id: u32) -> Self {701        DeviceId {702            id,703            mask: DeviceMask::Exact,704        }705    }706 707    /// Creates a new instance with the model match mask.708    pub const fn new_with_model_mask(id: u32) -> Self {709        DeviceId {710            id,711            mask: DeviceMask::Model,712        }713    }714 715    /// Creates a new instance with the vendor match mask.716    pub const fn new_with_vendor_mask(id: u32) -> Self {717        DeviceId {718            id,719            mask: DeviceMask::Vendor,720        }721    }722 723    /// Creates a new instance with a custom match mask.724    pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self {725        DeviceId {726            id,727            mask: DeviceMask::Custom(mask),728        }729    }730 731    /// Creates a new instance from [`Driver`].732    pub const fn new_with_driver<T: Driver>() -> Self {733        T::PHY_DEVICE_ID734    }735 736    /// Get a `mask` as u32.737    pub const fn mask_as_int(&self) -> u32 {738        self.mask.as_int()739    }740 741    // macro use only742    #[doc(hidden)]743    pub const fn mdio_device_id(&self) -> bindings::mdio_device_id {744        bindings::mdio_device_id {745            phy_id: self.id,746            phy_id_mask: self.mask.as_int(),747        }748    }749}750 751enum DeviceMask {752    Exact,753    Model,754    Vendor,755    Custom(u32),756}757 758impl DeviceMask {759    const MASK_EXACT: u32 = !0;760    const MASK_MODEL: u32 = !0 << 4;761    const MASK_VENDOR: u32 = !0 << 10;762 763    const fn as_int(&self) -> u32 {764        match self {765            DeviceMask::Exact => Self::MASK_EXACT,766            DeviceMask::Model => Self::MASK_MODEL,767            DeviceMask::Vendor => Self::MASK_VENDOR,768            DeviceMask::Custom(mask) => *mask,769        }770    }771}772 773/// Declares a kernel module for PHYs drivers.774///775/// This creates a static array of kernel's `struct phy_driver` and registers it.776/// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information777/// for module loading into the module binary file. Every driver needs an entry in `device_table`.778///779/// # Examples780///781/// ```782/// # mod module_phy_driver_sample {783/// use kernel::c_str;784/// use kernel::net::phy::{self, DeviceId};785/// use kernel::prelude::*;786///787/// kernel::module_phy_driver! {788///     drivers: [PhySample],789///     device_table: [790///         DeviceId::new_with_driver::<PhySample>()791///     ],792///     name: "rust_sample_phy",793///     author: "Rust for Linux Contributors",794///     description: "Rust sample PHYs driver",795///     license: "GPL",796/// }797///798/// struct PhySample;799///800/// #[vtable]801/// impl phy::Driver for PhySample {802///     const NAME: &'static CStr = c_str!("PhySample");803///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);804/// }805/// # }806/// ```807///808/// This expands to the following code:809///810/// ```ignore811/// use kernel::c_str;812/// use kernel::net::phy::{self, DeviceId};813/// use kernel::prelude::*;814///815/// struct Module {816///     _reg: ::kernel::net::phy::Registration,817/// }818///819/// module! {820///     type: Module,821///     name: "rust_sample_phy",822///     author: "Rust for Linux Contributors",823///     description: "Rust sample PHYs driver",824///     license: "GPL",825/// }826///827/// struct PhySample;828///829/// #[vtable]830/// impl phy::Driver for PhySample {831///     const NAME: &'static CStr = c_str!("PhySample");832///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);833/// }834///835/// const _: () = {836///     static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =837///         [::kernel::net::phy::create_phy_driver::<PhySample>()];838///839///     impl ::kernel::Module for Module {840///         fn init(module: &'static ThisModule) -> Result<Self> {841///             let drivers = unsafe { &mut DRIVERS };842///             let mut reg = ::kernel::net::phy::Registration::register(843///                 module,844///                 ::core::pin::Pin::static_mut(drivers),845///             )?;846///             Ok(Module { _reg: reg })847///         }848///     }849/// };850///851/// #[cfg(MODULE)]852/// #[no_mangle]853/// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [854///     ::kernel::bindings::mdio_device_id {855///         phy_id: 0x00000001,856///         phy_id_mask: 0xffffffff,857///     },858///     ::kernel::bindings::mdio_device_id {859///         phy_id: 0,860///         phy_id_mask: 0,861///     },862/// ];863/// ```864#[macro_export]865macro_rules! module_phy_driver {866    (@replace_expr $_t:tt $sub:expr) => {$sub};867 868    (@count_devices $($x:expr),*) => {869        0usize $(+ $crate::module_phy_driver!(@replace_expr $x 1usize))*870    };871 872    (@device_table [$($dev:expr),+]) => {873        // SAFETY: C will not read off the end of this constant since the last element is zero.874        #[cfg(MODULE)]875        #[no_mangle]876        static __mod_mdio__phydev_device_table: [$crate::bindings::mdio_device_id;877            $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [878            $($dev.mdio_device_id()),+,879            $crate::bindings::mdio_device_id {880                phy_id: 0,881                phy_id_mask: 0882            }883        ];884    };885 886    (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {887        struct Module {888            _reg: $crate::net::phy::Registration,889        }890 891        $crate::prelude::module! {892            type: Module,893            $($f)*894        }895 896        const _: () = {897            static mut DRIVERS: [$crate::net::phy::DriverVTable;898                $crate::module_phy_driver!(@count_devices $($driver),+)] =899                [$($crate::net::phy::create_phy_driver::<$driver>()),+];900 901            impl $crate::Module for Module {902                fn init(module: &'static ThisModule) -> Result<Self> {903                    // SAFETY: The anonymous constant guarantees that nobody else can access904                    // the `DRIVERS` static. The array is used only in the C side.905                    let drivers = unsafe { &mut DRIVERS };906                    let mut reg = $crate::net::phy::Registration::register(907                        module,908                        ::core::pin::Pin::static_mut(drivers),909                    )?;910                    Ok(Module { _reg: reg })911                }912            }913        };914 915        $crate::module_phy_driver!(@device_table [$($dev),+]);916    }917}918