Skip to main content

kernel/net/
phy.rs

1// SPDX-License-Identifier: GPL-2.0
2
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::{device_id::RawDeviceId, 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.h
21#[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 driver
58/// executes [`Driver`]'s methods during the callback.
59///
60/// # Invariants
61///
62/// - Referencing a `phy_device` using this struct asserts that you are in
63///   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.h
67// During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
68// unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for
69// [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with
70// 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 access
72// 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    /// # Safety
80    ///
81    /// For the duration of `'a`,
82    /// - the pointer must point at a valid `phy_device`, and the caller
83    ///   must be in a context where all methods defined on this struct
84    ///   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 for
90        // 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 access
98        // 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 access
106        // this field without additional synchronization.
107        let state = unsafe { (*phydev).state };
108        // TODO: this conversion code will be replaced with automatically generated code by bindgen
109        // 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    #[inline]
127    pub fn is_link_up(&self) -> bool {
128        let phydev = self.0.get().cast_const();
129        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
130        // `struct phy_device`, and there is no concurrent write to this field.
131        let link = unsafe { bindings::phy_device::link_raw(phydev) };
132        link == 1
133    }
134
135    /// Gets the current auto-negotiation configuration.
136    ///
137    /// It returns true if auto-negotiation is enabled.
138    #[inline]
139    pub fn is_autoneg_enabled(&self) -> bool {
140        let phydev = self.0.get().cast_const();
141        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
142        // `struct phy_device`, and there is no concurrent write to this field.
143        let autoneg = unsafe { bindings::phy_device::autoneg_raw(phydev) };
144        autoneg == bindings::AUTONEG_ENABLE
145    }
146
147    /// Gets the current auto-negotiation state.
148    ///
149    /// It returns true if auto-negotiation is completed.
150    #[inline]
151    pub fn is_autoneg_completed(&self) -> bool {
152        let phydev = self.0.get().cast_const();
153        // SAFETY: By the type invariant of `Device`, `phydev` points to a valid
154        // `struct phy_device`, and there is no concurrent write to this field.
155        let completed = unsafe { bindings::phy_device::autoneg_complete_raw(phydev) };
156        completed == 1
157    }
158
159    /// Sets the speed of the PHY.
160    pub fn set_speed(&mut self, speed: u32) {
161        let phydev = self.0.get();
162        // SAFETY: The struct invariant ensures that we may access
163        // this field without additional synchronization.
164        unsafe { (*phydev).speed = speed as c_int };
165    }
166
167    /// Sets duplex mode.
168    pub fn set_duplex(&mut self, mode: DuplexMode) {
169        let phydev = self.0.get();
170        let v = match mode {
171            DuplexMode::Full => bindings::DUPLEX_FULL,
172            DuplexMode::Half => bindings::DUPLEX_HALF,
173            DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN,
174        };
175        // SAFETY: The struct invariant ensures that we may access
176        // this field without additional synchronization.
177        unsafe { (*phydev).duplex = v as c_int };
178    }
179
180    /// Reads a PHY register.
181    // This function reads a hardware register and updates the stats so takes `&mut self`.
182    pub fn read<R: reg::Register>(&mut self, reg: R) -> Result<u16> {
183        reg.read(self)
184    }
185
186    /// Writes a PHY register.
187    pub fn write<R: reg::Register>(&mut self, reg: R, val: u16) -> Result {
188        reg.write(self, val)
189    }
190
191    /// Reads a paged register.
192    pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> {
193        let phydev = self.0.get();
194        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
195        // So it's just an FFI call.
196        let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) };
197
198        to_result(ret).map(|()| ret as u16)
199    }
200
201    /// Resolves the advertisements into PHY settings.
202    pub fn resolve_aneg_linkmode(&mut self) {
203        let phydev = self.0.get();
204        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
205        // So it's just an FFI call.
206        unsafe { bindings::phy_resolve_aneg_linkmode(phydev) };
207    }
208
209    /// Executes software reset the PHY via `BMCR_RESET` bit.
210    pub fn genphy_soft_reset(&mut self) -> Result {
211        let phydev = self.0.get();
212        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
213        // So it's just an FFI call.
214        to_result(unsafe { bindings::genphy_soft_reset(phydev) })
215    }
216
217    /// Initializes the PHY.
218    pub fn init_hw(&mut self) -> Result {
219        let phydev = self.0.get();
220        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
221        // So it's just an FFI call.
222        to_result(unsafe { bindings::phy_init_hw(phydev) })
223    }
224
225    /// Starts auto-negotiation.
226    pub fn start_aneg(&mut self) -> Result {
227        let phydev = self.0.get();
228        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
229        // So it's just an FFI call.
230        to_result(unsafe { bindings::_phy_start_aneg(phydev) })
231    }
232
233    /// Resumes the PHY via `BMCR_PDOWN` bit.
234    pub fn genphy_resume(&mut self) -> Result {
235        let phydev = self.0.get();
236        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
237        // So it's just an FFI call.
238        to_result(unsafe { bindings::genphy_resume(phydev) })
239    }
240
241    /// Suspends the PHY via `BMCR_PDOWN` bit.
242    pub fn genphy_suspend(&mut self) -> Result {
243        let phydev = self.0.get();
244        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
245        // So it's just an FFI call.
246        to_result(unsafe { bindings::genphy_suspend(phydev) })
247    }
248
249    /// Checks the link status and updates current link state.
250    pub fn genphy_read_status<R: reg::Register>(&mut self) -> Result<u16> {
251        R::read_status(self)
252    }
253
254    /// Updates the link status.
255    pub fn genphy_update_link(&mut self) -> Result {
256        let phydev = self.0.get();
257        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
258        // So it's just an FFI call.
259        to_result(unsafe { bindings::genphy_update_link(phydev) })
260    }
261
262    /// Reads link partner ability.
263    pub fn genphy_read_lpa(&mut self) -> Result {
264        let phydev = self.0.get();
265        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
266        // So it's just an FFI call.
267        to_result(unsafe { bindings::genphy_read_lpa(phydev) })
268    }
269
270    /// Reads PHY abilities.
271    pub fn genphy_read_abilities(&mut self) -> Result {
272        let phydev = self.0.get();
273        // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
274        // So it's just an FFI call.
275        to_result(unsafe { bindings::genphy_read_abilities(phydev) })
276    }
277}
278
279impl AsRef<kernel::device::Device> for Device {
280    fn as_ref(&self) -> &kernel::device::Device {
281        let phydev = self.0.get();
282        // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
283        unsafe { kernel::device::Device::from_raw(addr_of_mut!((*phydev).mdio.dev)) }
284    }
285}
286
287/// Defines certain other features this PHY supports (like interrupts).
288///
289/// These flag values are used in [`Driver::FLAGS`].
290pub mod flags {
291    /// PHY is internal.
292    pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL;
293    /// PHY needs to be reset after the refclk is enabled.
294    pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN;
295    /// Polling is used to detect PHY status changes.
296    pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST;
297    /// Don't suspend.
298    pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND;
299}
300
301/// An adapter for the registration of a PHY driver.
302struct Adapter<T: Driver> {
303    _p: PhantomData<T>,
304}
305
306impl<T: Driver> Adapter<T> {
307    /// # Safety
308    ///
309    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
310    unsafe extern "C" fn soft_reset_callback(phydev: *mut bindings::phy_device) -> c_int {
311        from_result(|| {
312            // SAFETY: This callback is called only in contexts
313            // where we hold `phy_device->lock`, so the accessors on
314            // `Device` are okay to call.
315            let dev = unsafe { Device::from_raw(phydev) };
316            T::soft_reset(dev)?;
317            Ok(0)
318        })
319    }
320
321    /// # Safety
322    ///
323    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
324    unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> c_int {
325        from_result(|| {
326            // SAFETY: This callback is called only in contexts
327            // where we can exclusively access `phy_device` because
328            // it's not published yet, so the accessors on `Device` are okay
329            // to call.
330            let dev = unsafe { Device::from_raw(phydev) };
331            T::probe(dev)?;
332            Ok(0)
333        })
334    }
335
336    /// # Safety
337    ///
338    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
339    unsafe extern "C" fn get_features_callback(phydev: *mut bindings::phy_device) -> c_int {
340        from_result(|| {
341            // SAFETY: This callback is called only in contexts
342            // where we hold `phy_device->lock`, so the accessors on
343            // `Device` are okay to call.
344            let dev = unsafe { Device::from_raw(phydev) };
345            T::get_features(dev)?;
346            Ok(0)
347        })
348    }
349
350    /// # Safety
351    ///
352    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
353    unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> c_int {
354        from_result(|| {
355            // SAFETY: The C core code ensures that the accessors on
356            // `Device` are okay to call even though `phy_device->lock`
357            // might not be held.
358            let dev = unsafe { Device::from_raw(phydev) };
359            T::suspend(dev)?;
360            Ok(0)
361        })
362    }
363
364    /// # Safety
365    ///
366    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
367    unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> c_int {
368        from_result(|| {
369            // SAFETY: The C core code ensures that the accessors on
370            // `Device` are okay to call even though `phy_device->lock`
371            // might not be held.
372            let dev = unsafe { Device::from_raw(phydev) };
373            T::resume(dev)?;
374            Ok(0)
375        })
376    }
377
378    /// # Safety
379    ///
380    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
381    unsafe extern "C" fn config_aneg_callback(phydev: *mut bindings::phy_device) -> c_int {
382        from_result(|| {
383            // SAFETY: This callback is called only in contexts
384            // where we hold `phy_device->lock`, so the accessors on
385            // `Device` are okay to call.
386            let dev = unsafe { Device::from_raw(phydev) };
387            T::config_aneg(dev)?;
388            Ok(0)
389        })
390    }
391
392    /// # Safety
393    ///
394    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
395    unsafe extern "C" fn read_status_callback(phydev: *mut bindings::phy_device) -> c_int {
396        from_result(|| {
397            // SAFETY: This callback is called only in contexts
398            // where we hold `phy_device->lock`, so the accessors on
399            // `Device` are okay to call.
400            let dev = unsafe { Device::from_raw(phydev) };
401            T::read_status(dev)?;
402            Ok(0)
403        })
404    }
405
406    /// # Safety
407    ///
408    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
409    unsafe extern "C" fn match_phy_device_callback(
410        phydev: *mut bindings::phy_device,
411        _phydrv: *const bindings::phy_driver,
412    ) -> c_int {
413        // SAFETY: This callback is called only in contexts
414        // where we hold `phy_device->lock`, so the accessors on
415        // `Device` are okay to call.
416        let dev = unsafe { Device::from_raw(phydev) };
417        T::match_phy_device(dev).into()
418    }
419
420    /// # Safety
421    ///
422    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
423    unsafe extern "C" fn read_mmd_callback(
424        phydev: *mut bindings::phy_device,
425        devnum: i32,
426        regnum: u16,
427    ) -> i32 {
428        from_result(|| {
429            // SAFETY: This callback is called only in contexts
430            // where we hold `phy_device->lock`, so the accessors on
431            // `Device` are okay to call.
432            let dev = unsafe { Device::from_raw(phydev) };
433            // CAST: the C side verifies devnum < 32.
434            let ret = T::read_mmd(dev, devnum as u8, regnum)?;
435            Ok(ret.into())
436        })
437    }
438
439    /// # Safety
440    ///
441    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
442    unsafe extern "C" fn write_mmd_callback(
443        phydev: *mut bindings::phy_device,
444        devnum: i32,
445        regnum: u16,
446        val: u16,
447    ) -> i32 {
448        from_result(|| {
449            // SAFETY: This callback is called only in contexts
450            // where we hold `phy_device->lock`, so the accessors on
451            // `Device` are okay to call.
452            let dev = unsafe { Device::from_raw(phydev) };
453            T::write_mmd(dev, devnum as u8, regnum, val)?;
454            Ok(0)
455        })
456    }
457
458    /// # Safety
459    ///
460    /// `phydev` must be passed by the corresponding callback in `phy_driver`.
461    unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) {
462        // SAFETY: This callback is called only in contexts
463        // where we hold `phy_device->lock`, so the accessors on
464        // `Device` are okay to call.
465        let dev = unsafe { Device::from_raw(phydev) };
466        T::link_change_notify(dev);
467    }
468}
469
470/// Driver structure for a particular PHY type.
471///
472/// Wraps the kernel's [`struct phy_driver`].
473/// This is used to register a driver for a particular PHY type with the kernel.
474///
475/// # Invariants
476///
477/// `self.0` is always in a valid state.
478///
479/// [`struct phy_driver`]: srctree/include/linux/phy.h
480#[repr(transparent)]
481pub struct DriverVTable(Opaque<bindings::phy_driver>);
482
483// SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to
484// share `&DriverVTable` across execution context boundaries.
485unsafe impl Sync for DriverVTable {}
486
487/// Creates a [`DriverVTable`] instance from [`Driver`].
488///
489/// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`.
490///
491/// [`module_phy_driver`]: crate::module_phy_driver
492pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
493    // INVARIANT: All the fields of `struct phy_driver` are initialized properly.
494    DriverVTable(Opaque::new(bindings::phy_driver {
495        name: crate::str::as_char_ptr_in_const_context(T::NAME).cast_mut(),
496        flags: T::FLAGS,
497        phy_id: T::PHY_DEVICE_ID.id(),
498        phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
499        soft_reset: if T::HAS_SOFT_RESET {
500            Some(Adapter::<T>::soft_reset_callback)
501        } else {
502            None
503        },
504        probe: if T::HAS_PROBE {
505            Some(Adapter::<T>::probe_callback)
506        } else {
507            None
508        },
509        get_features: if T::HAS_GET_FEATURES {
510            Some(Adapter::<T>::get_features_callback)
511        } else {
512            None
513        },
514        match_phy_device: if T::HAS_MATCH_PHY_DEVICE {
515            Some(Adapter::<T>::match_phy_device_callback)
516        } else {
517            None
518        },
519        suspend: if T::HAS_SUSPEND {
520            Some(Adapter::<T>::suspend_callback)
521        } else {
522            None
523        },
524        resume: if T::HAS_RESUME {
525            Some(Adapter::<T>::resume_callback)
526        } else {
527            None
528        },
529        config_aneg: if T::HAS_CONFIG_ANEG {
530            Some(Adapter::<T>::config_aneg_callback)
531        } else {
532            None
533        },
534        read_status: if T::HAS_READ_STATUS {
535            Some(Adapter::<T>::read_status_callback)
536        } else {
537            None
538        },
539        read_mmd: if T::HAS_READ_MMD {
540            Some(Adapter::<T>::read_mmd_callback)
541        } else {
542            None
543        },
544        write_mmd: if T::HAS_WRITE_MMD {
545            Some(Adapter::<T>::write_mmd_callback)
546        } else {
547            None
548        },
549        link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY {
550            Some(Adapter::<T>::link_change_notify_callback)
551        } else {
552            None
553        },
554        // SAFETY: The rest is zeroed out to initialize `struct phy_driver`,
555        // sets `Option<&F>` to be `None`.
556        ..unsafe { core::mem::MaybeUninit::<bindings::phy_driver>::zeroed().assume_init() }
557    }))
558}
559
560/// Driver implementation for a particular PHY type.
561///
562/// This trait is used to create a [`DriverVTable`].
563#[vtable]
564pub trait Driver {
565    /// Defines certain other features this PHY supports.
566    /// It is a combination of the flags in the [`flags`] module.
567    const FLAGS: u32 = 0;
568
569    /// The friendly name of this PHY type.
570    const NAME: &'static CStr;
571
572    /// This driver only works for PHYs with IDs which match this field.
573    /// The default id and mask are zero.
574    const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);
575
576    /// Issues a PHY software reset.
577    fn soft_reset(_dev: &mut Device) -> Result {
578        build_error!(VTABLE_DEFAULT_ERROR)
579    }
580
581    /// Sets up device-specific structures during discovery.
582    fn probe(_dev: &mut Device) -> Result {
583        build_error!(VTABLE_DEFAULT_ERROR)
584    }
585
586    /// Probes the hardware to determine what abilities it has.
587    fn get_features(_dev: &mut Device) -> Result {
588        build_error!(VTABLE_DEFAULT_ERROR)
589    }
590
591    /// Returns true if this is a suitable driver for the given phydev.
592    /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
593    fn match_phy_device(_dev: &Device) -> bool {
594        false
595    }
596
597    /// Configures the advertisement and resets auto-negotiation
598    /// if auto-negotiation is enabled.
599    fn config_aneg(_dev: &mut Device) -> Result {
600        build_error!(VTABLE_DEFAULT_ERROR)
601    }
602
603    /// Determines the negotiated speed and duplex.
604    fn read_status(_dev: &mut Device) -> Result<u16> {
605        build_error!(VTABLE_DEFAULT_ERROR)
606    }
607
608    /// Suspends the hardware, saving state if needed.
609    fn suspend(_dev: &mut Device) -> Result {
610        build_error!(VTABLE_DEFAULT_ERROR)
611    }
612
613    /// Resumes the hardware, restoring state if needed.
614    fn resume(_dev: &mut Device) -> Result {
615        build_error!(VTABLE_DEFAULT_ERROR)
616    }
617
618    /// Overrides the default MMD read function for reading a MMD register.
619    fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> {
620        build_error!(VTABLE_DEFAULT_ERROR)
621    }
622
623    /// Overrides the default MMD write function for writing a MMD register.
624    fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result {
625        build_error!(VTABLE_DEFAULT_ERROR)
626    }
627
628    /// Callback for notification of link change.
629    fn link_change_notify(_dev: &mut Device) {}
630}
631
632/// Registration structure for PHY drivers.
633///
634/// Registers [`DriverVTable`] instances with the kernel. They will be unregistered when dropped.
635///
636/// # Invariants
637///
638/// The `drivers` slice are currently registered to the kernel via `phy_drivers_register`.
639pub struct Registration {
640    drivers: Pin<&'static mut [DriverVTable]>,
641}
642
643// SAFETY: The only action allowed in a `Registration` instance is dropping it, which is safe to do
644// from any thread because `phy_drivers_unregister` can be called from any thread context.
645unsafe impl Send for Registration {}
646
647impl Registration {
648    /// Registers a PHY driver.
649    pub fn register(
650        module: &'static crate::ThisModule,
651        drivers: Pin<&'static mut [DriverVTable]>,
652    ) -> Result<Self> {
653        if drivers.is_empty() {
654            return Err(code::EINVAL);
655        }
656        // SAFETY: The type invariants of [`DriverVTable`] ensure that all elements of
657        // the `drivers` slice are initialized properly. `drivers` will not be moved.
658        // So it's just an FFI call.
659        to_result(unsafe {
660            bindings::phy_drivers_register(
661                drivers[0].0.get(),
662                drivers.len().try_into()?,
663                module.as_ptr(),
664            )
665        })?;
666        // INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.
667        Ok(Registration { drivers })
668    }
669}
670
671impl Drop for Registration {
672    fn drop(&mut self) {
673        // SAFETY: The type invariants guarantee that `self.drivers` is valid.
674        // So it's just an FFI call.
675        unsafe {
676            bindings::phy_drivers_unregister(self.drivers[0].0.get(), self.drivers.len() as i32)
677        };
678    }
679}
680
681/// An identifier for PHY devices on an MDIO/MII bus.
682///
683/// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate
684/// PHY driver.
685#[repr(transparent)]
686#[derive(Clone, Copy)]
687pub struct DeviceId(bindings::mdio_device_id);
688
689impl DeviceId {
690    /// Creates a new instance with the exact match mask.
691    pub const fn new_with_exact_mask(id: u32) -> Self {
692        Self(bindings::mdio_device_id {
693            phy_id: id,
694            phy_id_mask: DeviceMask::Exact.as_int(),
695        })
696    }
697
698    /// Creates a new instance with the model match mask.
699    pub const fn new_with_model_mask(id: u32) -> Self {
700        Self(bindings::mdio_device_id {
701            phy_id: id,
702            phy_id_mask: DeviceMask::Model.as_int(),
703        })
704    }
705
706    /// Creates a new instance with the vendor match mask.
707    pub const fn new_with_vendor_mask(id: u32) -> Self {
708        Self(bindings::mdio_device_id {
709            phy_id: id,
710            phy_id_mask: DeviceMask::Vendor.as_int(),
711        })
712    }
713
714    /// Creates a new instance with a custom match mask.
715    pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self {
716        Self(bindings::mdio_device_id {
717            phy_id: id,
718            phy_id_mask: DeviceMask::Custom(mask).as_int(),
719        })
720    }
721
722    /// Creates a new instance from [`Driver`].
723    pub const fn new_with_driver<T: Driver>() -> Self {
724        T::PHY_DEVICE_ID
725    }
726
727    /// Get the MDIO device's PHY ID.
728    pub const fn id(&self) -> u32 {
729        self.0.phy_id
730    }
731
732    /// Get the MDIO device's match mask.
733    pub const fn mask_as_int(&self) -> u32 {
734        self.0.phy_id_mask
735    }
736
737    // macro use only
738    #[doc(hidden)]
739    pub const fn mdio_device_id(&self) -> bindings::mdio_device_id {
740        self.0
741    }
742}
743
744// SAFETY: `DeviceId` is a `#[repr(transparent)]` wrapper of `struct mdio_device_id`
745// and does not add additional invariants, so it's safe to transmute to `RawType`.
746unsafe impl RawDeviceId for DeviceId {
747    type RawType = bindings::mdio_device_id;
748}
749
750enum DeviceMask {
751    Exact,
752    Model,
753    Vendor,
754    Custom(u32),
755}
756
757impl DeviceMask {
758    const MASK_EXACT: u32 = !0;
759    const MASK_MODEL: u32 = !0 << 4;
760    const MASK_VENDOR: u32 = !0 << 10;
761
762    const fn as_int(&self) -> u32 {
763        match self {
764            DeviceMask::Exact => Self::MASK_EXACT,
765            DeviceMask::Model => Self::MASK_MODEL,
766            DeviceMask::Vendor => Self::MASK_VENDOR,
767            DeviceMask::Custom(mask) => *mask,
768        }
769    }
770}
771
772/// Declares a kernel module for PHYs drivers.
773///
774/// This creates a static array of kernel's `struct phy_driver` and registers it.
775/// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information
776/// for module loading into the module binary file. Every driver needs an entry in `device_table`.
777///
778/// # Examples
779///
780/// ```
781/// # mod module_phy_driver_sample {
782/// use kernel::net::phy::{self, DeviceId};
783/// use kernel::prelude::*;
784///
785/// kernel::module_phy_driver! {
786///     drivers: [PhySample],
787///     device_table: [
788///         DeviceId::new_with_driver::<PhySample>()
789///     ],
790///     name: "rust_sample_phy",
791///     authors: ["Rust for Linux Contributors"],
792///     description: "Rust sample PHYs driver",
793///     license: "GPL",
794/// }
795///
796/// struct PhySample;
797///
798/// #[vtable]
799/// impl phy::Driver for PhySample {
800///     const NAME: &'static CStr = c"PhySample";
801///     const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
802/// }
803/// # }
804/// ```
805#[macro_export]
806macro_rules! module_phy_driver {
807    (@replace_expr $_t:tt $sub:expr) => {$sub};
808
809    (@count_devices $($x:expr),*) => {
810        0usize $(+ $crate::module_phy_driver!(@replace_expr $x 1usize))*
811    };
812
813    (@device_table [$($dev:expr),+]) => {
814        $crate::module_device_table!(
815            "mdio", $crate::net::phy::DeviceId,
816            TABLE, @none, [$($dev),+]
817        );
818    };
819
820    (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {
821        struct Module {
822            _reg: $crate::net::phy::Registration,
823        }
824
825        $crate::prelude::module! {
826            type: Module,
827            $($f)*
828        }
829
830        const _: () = {
831            static mut DRIVERS: [$crate::net::phy::DriverVTable;
832                $crate::module_phy_driver!(@count_devices $($driver),+)] =
833                [$($crate::net::phy::create_phy_driver::<$driver>()),+];
834
835            impl $crate::Module for Module {
836                fn init(module: &'static $crate::ThisModule) -> Result<Self> {
837                    // SAFETY: The anonymous constant guarantees that nobody else can access
838                    // the `DRIVERS` static. The array is used only in the C side.
839                    let drivers = unsafe { &mut DRIVERS };
840                    let mut reg = $crate::net::phy::Registration::register(
841                        module,
842                        ::core::pin::Pin::static_mut(drivers),
843                    )?;
844                    Ok(Module { _reg: reg })
845                }
846            }
847        };
848
849        $crate::module_phy_driver!(@device_table [$($dev),+]);
850    }
851}