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