Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'net-phy-rust'

FUJITA Tomonori says:

====================
Rust abstractions for network PHY drivers

No functional change since v10; only comment and commit log updates.

This patchset adds Rust abstractions for phylib. It doesn't fully
cover the C APIs yet but I think that it's already useful. I implement
two PHY drivers (Asix AX88772A PHYs and Realtek Generic FE-GE). Seems
they work well with real hardware.

The first patch introduces Rust bindings for phylib.

The second patch adds a macro to declare a kernel module for PHYs
drivers.

The third adds the Rust ETHERNET PHY LIBRARY entry to MAINTAINERS
file; adds the binding file and me as a maintainer (as Andrew Lunn
suggested) with Trevor Gross as a reviewer.

The last patch introduces the Rust version of Asix PHY driver,
drivers/net/phy/ax88796b.c. The features are equivalent to the C
version. You can choose C (by default) or Rust version on kernel
configuration.

v11:
- adds Andrew, Alice, and Trevor's Reviewed-by
- comment update
v10: https://lore.kernel.org/netdev/20231210234924.1453917-1-fujita.tomonori@gmail.com/T/
- adds Trevor's SoB to the third patch
- adds Benno's Reviewed-by to the second patch
v9: https://lore.kernel.org/netdev/20231205.124531.842372711631366729.fujita.tomonori@gmail.com/T/
- adds a workaround to access to a bit field in phy_device
- fixes a comment typo
v8: https://lore.kernel.org/netdev/20231123050412.1012252-1-fujita.tomonori@gmail.com/
- updates the safety comments on Device and its related code
- uses _phy_start_aneg instead of phy_start_aneg
- drops the patch for enum synchronization
- moves Sync From Registration to DriverVTable
- fixes doctest errors
- minor cleanups
v7: https://lore.kernel.org/netdev/20231026001050.1720612-1-fujita.tomonori@gmail.com/T/
- renames get_link() to is_link_up()
- improves the macro format
- improves the commit log in the third patch
- improves comments
v6: https://lore.kernel.org/netdev/20231025.090243.1437967503809186729.fujita.tomonori@gmail.com/T/
- improves comments
- makes the requirement of phy_drivers_register clear
- fixes Makefile of the third patch
v5: https://lore.kernel.org/all/20231019.094147.1808345526469629486.fujita.tomonori@gmail.com/T/
- drops the rustified-enum option, writes match by hand; no *risk* of UB
- adds Miguel's patch for enum checking
- moves CONFIG_RUST_PHYLIB_ABSTRACTIONS to drivers/net/phy/Kconfig
- adds a new entry for this abstractions in MAINTAINERS
- changes some of Device's methods to take &mut self
- comment improvment
v4: https://lore.kernel.org/netdev/20231012125349.2702474-1-fujita.tomonori@gmail.com/T/
- split the core patch
- making Device::from_raw() private
- comment improvement with code update
- commit message improvement
- avoiding using bindings::phy_driver in public functions
- using an anonymous constant in module_phy_driver macro
v3: https://lore.kernel.org/netdev/20231011.231607.1747074555988728415.fujita.tomonori@gmail.com/T/
- changes the base tree to net-next from rust-next
- makes this feature optional; only enabled with CONFIG_RUST_PHYLIB_BINDINGS=y
- cosmetic code and comment improvement
- adds copyright
v2: https://lore.kernel.org/netdev/20231006094911.3305152-2-fujita.tomonori@gmail.com/T/
- build failure fix
- function renaming
v1: https://lore.kernel.org/netdev/20231002085302.2274260-3-fujita.tomonori@gmail.com/T/
====================

Signed-off-by: David S. Miller <davem@davemloft.net>

+1087 -1
+16
MAINTAINERS
··· 3072 3072 F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml 3073 3073 F: drivers/net/ethernet/asix/ax88796c_* 3074 3074 3075 + ASIX PHY DRIVER [RUST] 3076 + M: FUJITA Tomonori <fujita.tomonori@gmail.com> 3077 + R: Trevor Gross <tmgross@umich.edu> 3078 + L: netdev@vger.kernel.org 3079 + L: rust-for-linux@vger.kernel.org 3080 + S: Maintained 3081 + F: drivers/net/phy/ax88796b_rust.rs 3082 + 3075 3083 ASPEED CRYPTO DRIVER 3076 3084 M: Neal Liu <neal_liu@aspeedtech.com> 3077 3085 L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers) ··· 7880 7872 F: include/uapi/linux/mdio.h 7881 7873 F: include/uapi/linux/mii.h 7882 7874 F: net/core/of_net.c 7875 + 7876 + ETHERNET PHY LIBRARY [RUST] 7877 + M: FUJITA Tomonori <fujita.tomonori@gmail.com> 7878 + R: Trevor Gross <tmgross@umich.edu> 7879 + L: netdev@vger.kernel.org 7880 + L: rust-for-linux@vger.kernel.org 7881 + S: Maintained 7882 + F: rust/kernel/net/phy.rs 7883 7883 7884 7884 EXEC & BINFMT API 7885 7885 R: Eric Biederman <ebiederm@xmission.com>
+16
drivers/net/phy/Kconfig
··· 60 60 61 61 Currently tested with mpc866ads and mpc8349e-mitx. 62 62 63 + config RUST_PHYLIB_ABSTRACTIONS 64 + bool "Rust PHYLIB abstractions support" 65 + depends on RUST 66 + depends on PHYLIB=y 67 + help 68 + Adds support needed for PHY drivers written in Rust. It provides 69 + a wrapper around the C phylib core. 70 + 63 71 config SFP 64 72 tristate "SFP cage support" 65 73 depends on I2C && PHYLINK ··· 111 103 help 112 104 Currently supports the Asix Electronics PHY found in the X-Surf 100 113 105 AX88796B package. 106 + 107 + config AX88796B_RUST_PHY 108 + bool "Rust reference driver for Asix PHYs" 109 + depends on RUST_PHYLIB_ABSTRACTIONS && AX88796B_PHY 110 + help 111 + Uses the Rust reference driver for Asix PHYs (ax88796b_rust.ko). 112 + The features are equivalent. It supports the Asix Electronics PHY 113 + found in the X-Surf 100 AX88796B package. 114 114 115 115 config BROADCOM_PHY 116 116 tristate "Broadcom 54XX PHYs"
+5 -1
drivers/net/phy/Makefile
··· 37 37 obj-$(CONFIG_AMD_PHY) += amd.o 38 38 obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ 39 39 obj-$(CONFIG_AT803X_PHY) += at803x.o 40 - obj-$(CONFIG_AX88796B_PHY) += ax88796b.o 40 + ifdef CONFIG_AX88796B_RUST_PHY 41 + obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o 42 + else 43 + obj-$(CONFIG_AX88796B_PHY) += ax88796b.o 44 + endif 41 45 obj-$(CONFIG_BCM54140_PHY) += bcm54140.o 42 46 obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o 43 47 obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
+135
drivers/net/phy/ax88796b_rust.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com> 3 + 4 + //! Rust Asix PHYs driver 5 + //! 6 + //! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c) 7 + use kernel::{ 8 + c_str, 9 + net::phy::{self, DeviceId, Driver}, 10 + prelude::*, 11 + uapi, 12 + }; 13 + 14 + kernel::module_phy_driver! { 15 + drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B], 16 + device_table: [ 17 + DeviceId::new_with_driver::<PhyAX88772A>(), 18 + DeviceId::new_with_driver::<PhyAX88772C>(), 19 + DeviceId::new_with_driver::<PhyAX88796B>() 20 + ], 21 + name: "rust_asix_phy", 22 + author: "FUJITA Tomonori <fujita.tomonori@gmail.com>", 23 + description: "Rust Asix PHYs driver", 24 + license: "GPL", 25 + } 26 + 27 + const MII_BMCR: u16 = uapi::MII_BMCR as u16; 28 + const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16; 29 + const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16; 30 + 31 + // Performs a software PHY reset using the standard 32 + // BMCR_RESET bit and poll for the reset bit to be cleared. 33 + // Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation 34 + // such as used on the Individual Computers' X-Surf 100 Zorro card. 35 + fn asix_soft_reset(dev: &mut phy::Device) -> Result { 36 + dev.write(uapi::MII_BMCR as u16, 0)?; 37 + dev.genphy_soft_reset() 38 + } 39 + 40 + struct PhyAX88772A; 41 + 42 + #[vtable] 43 + impl Driver for PhyAX88772A { 44 + const FLAGS: u32 = phy::flags::IS_INTERNAL; 45 + const NAME: &'static CStr = c_str!("Asix Electronics AX88772A"); 46 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861); 47 + 48 + // AX88772A is not working properly with some old switches (NETGEAR EN 108TP): 49 + // after autoneg is done and the link status is reported as active, the MII_LPA 50 + // register is 0. This issue is not reproducible on AX88772C. 51 + fn read_status(dev: &mut phy::Device) -> Result<u16> { 52 + dev.genphy_update_link()?; 53 + if !dev.is_link_up() { 54 + return Ok(0); 55 + } 56 + // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve 57 + // linkmode so use MII_BMCR as default values. 58 + let ret = dev.read(MII_BMCR)?; 59 + 60 + if ret & BMCR_SPEED100 != 0 { 61 + dev.set_speed(uapi::SPEED_100); 62 + } else { 63 + dev.set_speed(uapi::SPEED_10); 64 + } 65 + 66 + let duplex = if ret & BMCR_FULLDPLX != 0 { 67 + phy::DuplexMode::Full 68 + } else { 69 + phy::DuplexMode::Half 70 + }; 71 + dev.set_duplex(duplex); 72 + 73 + dev.genphy_read_lpa()?; 74 + 75 + if dev.is_autoneg_enabled() && dev.is_autoneg_completed() { 76 + dev.resolve_aneg_linkmode(); 77 + } 78 + 79 + Ok(0) 80 + } 81 + 82 + fn suspend(dev: &mut phy::Device) -> Result { 83 + dev.genphy_suspend() 84 + } 85 + 86 + fn resume(dev: &mut phy::Device) -> Result { 87 + dev.genphy_resume() 88 + } 89 + 90 + fn soft_reset(dev: &mut phy::Device) -> Result { 91 + asix_soft_reset(dev) 92 + } 93 + 94 + fn link_change_notify(dev: &mut phy::Device) { 95 + // Reset PHY, otherwise MII_LPA will provide outdated information. 96 + // This issue is reproducible only with some link partner PHYs. 97 + if dev.state() == phy::DeviceState::NoLink { 98 + let _ = dev.init_hw(); 99 + let _ = dev.start_aneg(); 100 + } 101 + } 102 + } 103 + 104 + struct PhyAX88772C; 105 + 106 + #[vtable] 107 + impl Driver for PhyAX88772C { 108 + const FLAGS: u32 = phy::flags::IS_INTERNAL; 109 + const NAME: &'static CStr = c_str!("Asix Electronics AX88772C"); 110 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881); 111 + 112 + fn suspend(dev: &mut phy::Device) -> Result { 113 + dev.genphy_suspend() 114 + } 115 + 116 + fn resume(dev: &mut phy::Device) -> Result { 117 + dev.genphy_resume() 118 + } 119 + 120 + fn soft_reset(dev: &mut phy::Device) -> Result { 121 + asix_soft_reset(dev) 122 + } 123 + } 124 + 125 + struct PhyAX88796B; 126 + 127 + #[vtable] 128 + impl Driver for PhyAX88796B { 129 + const NAME: &'static CStr = c_str!("Asix Electronics AX88796B"); 130 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841); 131 + 132 + fn soft_reset(dev: &mut phy::Device) -> Result { 133 + asix_soft_reset(dev) 134 + } 135 + }
+3
rust/bindings/bindings_helper.h
··· 8 8 9 9 #include <kunit/test.h> 10 10 #include <linux/errname.h> 11 + #include <linux/ethtool.h> 12 + #include <linux/mdio.h> 13 + #include <linux/phy.h> 11 14 #include <linux/slab.h> 12 15 #include <linux/refcount.h> 13 16 #include <linux/wait.h>
+3
rust/kernel/lib.rs
··· 14 14 #![no_std] 15 15 #![feature(allocator_api)] 16 16 #![feature(coerce_unsized)] 17 + #![feature(const_maybe_uninit_zeroed)] 17 18 #![feature(dispatch_from_dyn)] 18 19 #![feature(new_uninit)] 19 20 #![feature(offset_of)] ··· 39 38 pub mod ioctl; 40 39 #[cfg(CONFIG_KUNIT)] 41 40 pub mod kunit; 41 + #[cfg(CONFIG_NET)] 42 + pub mod net; 42 43 pub mod prelude; 43 44 pub mod print; 44 45 mod static_assert;
+6
rust/kernel/net.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + 3 + //! Networking. 4 + 5 + #[cfg(CONFIG_RUST_PHYLIB_ABSTRACTIONS)] 6 + pub mod phy;
+901
rust/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`](../../../../../../../include/linux/phy.h). 8 + 9 + use crate::{bindings, error::*, prelude::*, str::CStr, types::Opaque}; 10 + 11 + use core::marker::PhantomData; 12 + 13 + /// PHY state machine states. 14 + /// 15 + /// Corresponds to the kernel's [`enum phy_state`]. 16 + /// 17 + /// Some of PHY drivers access to the state of PHY's software state machine. 18 + /// 19 + /// [`enum phy_state`]: ../../../../../../../include/linux/phy.h 20 + #[derive(PartialEq, Eq)] 21 + pub enum DeviceState { 22 + /// PHY device and driver are not ready for anything. 23 + Down, 24 + /// PHY is ready to send and receive packets. 25 + Ready, 26 + /// PHY is up, but no polling or interrupts are done. 27 + Halted, 28 + /// PHY is up, but is in an error state. 29 + Error, 30 + /// PHY and attached device are ready to do work. 31 + Up, 32 + /// PHY is currently running. 33 + Running, 34 + /// PHY is up, but not currently plugged in. 35 + NoLink, 36 + /// PHY is performing a cable test. 37 + CableTest, 38 + } 39 + 40 + /// A mode of Ethernet communication. 41 + /// 42 + /// PHY drivers get duplex information from hardware and update the current state. 43 + pub enum DuplexMode { 44 + /// PHY is in full-duplex mode. 45 + Full, 46 + /// PHY is in half-duplex mode. 47 + Half, 48 + /// PHY is in unknown duplex mode. 49 + Unknown, 50 + } 51 + 52 + /// An instance of a PHY device. 53 + /// 54 + /// Wraps the kernel's [`struct phy_device`]. 55 + /// 56 + /// A [`Device`] instance is created when a callback in [`Driver`] is executed. A PHY driver 57 + /// executes [`Driver`]'s methods during the callback. 58 + /// 59 + /// # Invariants 60 + /// 61 + /// Referencing a `phy_device` using this struct asserts that you are in 62 + /// a context where all methods defined on this struct are safe to call. 63 + /// 64 + /// [`struct phy_device`]: ../../../../../../../include/linux/phy.h 65 + // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is 66 + // unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for 67 + // [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with 68 + // the lock held, thus guaranteeing that [`Driver::resume`] has exclusive access to the instance. 69 + // [`Driver::resume`] and [`Driver::suspend`] also are called where only one thread can access 70 + // to the instance. 71 + #[repr(transparent)] 72 + pub struct Device(Opaque<bindings::phy_device>); 73 + 74 + impl Device { 75 + /// Creates a new [`Device`] instance from a raw pointer. 76 + /// 77 + /// # Safety 78 + /// 79 + /// For the duration of 'a, the pointer must point at a valid `phy_device`, 80 + /// and the caller must be in a context where all methods defined on this struct 81 + /// are safe to call. 82 + unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self { 83 + // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`. 84 + let ptr = ptr.cast::<Self>(); 85 + // SAFETY: by the function requirements the pointer is valid and we have unique access for 86 + // the duration of `'a`. 87 + unsafe { &mut *ptr } 88 + } 89 + 90 + /// Gets the id of the PHY. 91 + pub fn phy_id(&self) -> u32 { 92 + let phydev = self.0.get(); 93 + // SAFETY: The struct invariant ensures that we may access 94 + // this field without additional synchronization. 95 + unsafe { (*phydev).phy_id } 96 + } 97 + 98 + /// Gets the state of PHY state machine states. 99 + pub fn state(&self) -> DeviceState { 100 + let phydev = self.0.get(); 101 + // SAFETY: The struct invariant ensures that we may access 102 + // this field without additional synchronization. 103 + let state = unsafe { (*phydev).state }; 104 + // TODO: this conversion code will be replaced with automatically generated code by bindgen 105 + // when it becomes possible. 106 + match state { 107 + bindings::phy_state_PHY_DOWN => DeviceState::Down, 108 + bindings::phy_state_PHY_READY => DeviceState::Ready, 109 + bindings::phy_state_PHY_HALTED => DeviceState::Halted, 110 + bindings::phy_state_PHY_ERROR => DeviceState::Error, 111 + bindings::phy_state_PHY_UP => DeviceState::Up, 112 + bindings::phy_state_PHY_RUNNING => DeviceState::Running, 113 + bindings::phy_state_PHY_NOLINK => DeviceState::NoLink, 114 + bindings::phy_state_PHY_CABLETEST => DeviceState::CableTest, 115 + _ => DeviceState::Error, 116 + } 117 + } 118 + 119 + /// Gets the current link state. 120 + /// 121 + /// It returns true if the link is up. 122 + pub fn is_link_up(&self) -> bool { 123 + const LINK_IS_UP: u64 = 1; 124 + // TODO: the code to access to the bit field will be replaced with automatically 125 + // generated code by bindgen when it becomes possible. 126 + // SAFETY: The struct invariant ensures that we may access 127 + // this field without additional synchronization. 128 + let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; 129 + bit_field.get(14, 1) == LINK_IS_UP 130 + } 131 + 132 + /// Gets the current auto-negotiation configuration. 133 + /// 134 + /// It returns true if auto-negotiation is enabled. 135 + pub fn is_autoneg_enabled(&self) -> bool { 136 + // TODO: the code to access to the bit field will be replaced with automatically 137 + // generated code by bindgen when it becomes possible. 138 + // SAFETY: The struct invariant ensures that we may access 139 + // this field without additional synchronization. 140 + let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; 141 + bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64 142 + } 143 + 144 + /// Gets the current auto-negotiation state. 145 + /// 146 + /// It returns true if auto-negotiation is completed. 147 + pub fn is_autoneg_completed(&self) -> bool { 148 + const AUTONEG_COMPLETED: u64 = 1; 149 + // TODO: the code to access to the bit field will be replaced with automatically 150 + // generated code by bindgen when it becomes possible. 151 + // SAFETY: The struct invariant ensures that we may access 152 + // this field without additional synchronization. 153 + let bit_field = unsafe { &(*self.0.get())._bitfield_1 }; 154 + bit_field.get(15, 1) == AUTONEG_COMPLETED 155 + } 156 + 157 + /// Sets the speed of the PHY. 158 + pub fn set_speed(&mut self, speed: u32) { 159 + let phydev = self.0.get(); 160 + // SAFETY: The struct invariant ensures that we may access 161 + // this field without additional synchronization. 162 + unsafe { (*phydev).speed = speed as i32 }; 163 + } 164 + 165 + /// Sets duplex mode. 166 + pub fn set_duplex(&mut self, mode: DuplexMode) { 167 + let phydev = self.0.get(); 168 + let v = match mode { 169 + DuplexMode::Full => bindings::DUPLEX_FULL as i32, 170 + DuplexMode::Half => bindings::DUPLEX_HALF as i32, 171 + DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN as i32, 172 + }; 173 + // SAFETY: The struct invariant ensures that we may access 174 + // this field without additional synchronization. 175 + unsafe { (*phydev).duplex = v }; 176 + } 177 + 178 + /// Reads a given C22 PHY register. 179 + // This function reads a hardware register and updates the stats so takes `&mut self`. 180 + pub fn read(&mut self, regnum: u16) -> Result<u16> { 181 + let phydev = self.0.get(); 182 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 183 + // So it's just an FFI call, open code of `phy_read()` with a valid `phy_device` pointer 184 + // `phydev`. 185 + let ret = unsafe { 186 + bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into()) 187 + }; 188 + if ret < 0 { 189 + Err(Error::from_errno(ret)) 190 + } else { 191 + Ok(ret as u16) 192 + } 193 + } 194 + 195 + /// Writes a given C22 PHY register. 196 + pub fn write(&mut self, regnum: u16, val: u16) -> Result { 197 + let phydev = self.0.get(); 198 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 199 + // So it's just an FFI call, open code of `phy_write()` with a valid `phy_device` pointer 200 + // `phydev`. 201 + to_result(unsafe { 202 + bindings::mdiobus_write((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into(), val) 203 + }) 204 + } 205 + 206 + /// Reads a paged register. 207 + pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> { 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 + let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) }; 212 + if ret < 0 { 213 + Err(Error::from_errno(ret)) 214 + } else { 215 + Ok(ret as u16) 216 + } 217 + } 218 + 219 + /// Resolves the advertisements into PHY settings. 220 + pub fn resolve_aneg_linkmode(&mut self) { 221 + let phydev = self.0.get(); 222 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 223 + // So it's just an FFI call. 224 + unsafe { bindings::phy_resolve_aneg_linkmode(phydev) }; 225 + } 226 + 227 + /// Executes software reset the PHY via `BMCR_RESET` bit. 228 + pub fn genphy_soft_reset(&mut self) -> Result { 229 + let phydev = self.0.get(); 230 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 231 + // So it's just an FFI call. 232 + to_result(unsafe { bindings::genphy_soft_reset(phydev) }) 233 + } 234 + 235 + /// Initializes the PHY. 236 + pub fn init_hw(&mut self) -> Result { 237 + let phydev = self.0.get(); 238 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 239 + // So it's just an FFI call. 240 + to_result(unsafe { bindings::phy_init_hw(phydev) }) 241 + } 242 + 243 + /// Starts auto-negotiation. 244 + pub fn start_aneg(&mut self) -> Result { 245 + let phydev = self.0.get(); 246 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 247 + // So it's just an FFI call. 248 + to_result(unsafe { bindings::_phy_start_aneg(phydev) }) 249 + } 250 + 251 + /// Resumes the PHY via `BMCR_PDOWN` bit. 252 + pub fn genphy_resume(&mut self) -> Result { 253 + let phydev = self.0.get(); 254 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 255 + // So it's just an FFI call. 256 + to_result(unsafe { bindings::genphy_resume(phydev) }) 257 + } 258 + 259 + /// Suspends the PHY via `BMCR_PDOWN` bit. 260 + pub fn genphy_suspend(&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_suspend(phydev) }) 265 + } 266 + 267 + /// Checks the link status and updates current link state. 268 + pub fn genphy_read_status(&mut self) -> Result<u16> { 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 + let ret = unsafe { bindings::genphy_read_status(phydev) }; 273 + if ret < 0 { 274 + Err(Error::from_errno(ret)) 275 + } else { 276 + Ok(ret as u16) 277 + } 278 + } 279 + 280 + /// Updates the link status. 281 + pub fn genphy_update_link(&mut self) -> Result { 282 + let phydev = self.0.get(); 283 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 284 + // So it's just an FFI call. 285 + to_result(unsafe { bindings::genphy_update_link(phydev) }) 286 + } 287 + 288 + /// Reads link partner ability. 289 + pub fn genphy_read_lpa(&mut self) -> Result { 290 + let phydev = self.0.get(); 291 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 292 + // So it's just an FFI call. 293 + to_result(unsafe { bindings::genphy_read_lpa(phydev) }) 294 + } 295 + 296 + /// Reads PHY abilities. 297 + pub fn genphy_read_abilities(&mut self) -> Result { 298 + let phydev = self.0.get(); 299 + // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`. 300 + // So it's just an FFI call. 301 + to_result(unsafe { bindings::genphy_read_abilities(phydev) }) 302 + } 303 + } 304 + 305 + /// Defines certain other features this PHY supports (like interrupts). 306 + /// 307 + /// These flag values are used in [`Driver::FLAGS`]. 308 + pub mod flags { 309 + /// PHY is internal. 310 + pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL; 311 + /// PHY needs to be reset after the refclk is enabled. 312 + pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN; 313 + /// Polling is used to detect PHY status changes. 314 + pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST; 315 + /// Don't suspend. 316 + pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND; 317 + } 318 + 319 + /// An adapter for the registration of a PHY driver. 320 + struct Adapter<T: Driver> { 321 + _p: PhantomData<T>, 322 + } 323 + 324 + impl<T: Driver> Adapter<T> { 325 + /// # Safety 326 + /// 327 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 328 + unsafe extern "C" fn soft_reset_callback( 329 + phydev: *mut bindings::phy_device, 330 + ) -> core::ffi::c_int { 331 + from_result(|| { 332 + // SAFETY: This callback is called only in contexts 333 + // where we hold `phy_device->lock`, so the accessors on 334 + // `Device` are okay to call. 335 + let dev = unsafe { Device::from_raw(phydev) }; 336 + T::soft_reset(dev)?; 337 + Ok(0) 338 + }) 339 + } 340 + 341 + /// # Safety 342 + /// 343 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 344 + unsafe extern "C" fn get_features_callback( 345 + phydev: *mut bindings::phy_device, 346 + ) -> core::ffi::c_int { 347 + from_result(|| { 348 + // SAFETY: This callback is called only in contexts 349 + // where we hold `phy_device->lock`, so the accessors on 350 + // `Device` are okay to call. 351 + let dev = unsafe { Device::from_raw(phydev) }; 352 + T::get_features(dev)?; 353 + Ok(0) 354 + }) 355 + } 356 + 357 + /// # Safety 358 + /// 359 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 360 + unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { 361 + from_result(|| { 362 + // SAFETY: The C core code ensures that the accessors on 363 + // `Device` are okay to call even though `phy_device->lock` 364 + // might not be held. 365 + let dev = unsafe { Device::from_raw(phydev) }; 366 + T::suspend(dev)?; 367 + Ok(0) 368 + }) 369 + } 370 + 371 + /// # Safety 372 + /// 373 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 374 + unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int { 375 + from_result(|| { 376 + // SAFETY: The C core code ensures that the accessors on 377 + // `Device` are okay to call even though `phy_device->lock` 378 + // might not be held. 379 + let dev = unsafe { Device::from_raw(phydev) }; 380 + T::resume(dev)?; 381 + Ok(0) 382 + }) 383 + } 384 + 385 + /// # Safety 386 + /// 387 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 388 + unsafe extern "C" fn config_aneg_callback( 389 + phydev: *mut bindings::phy_device, 390 + ) -> core::ffi::c_int { 391 + from_result(|| { 392 + // SAFETY: This callback is called only in contexts 393 + // where we hold `phy_device->lock`, so the accessors on 394 + // `Device` are okay to call. 395 + let dev = unsafe { Device::from_raw(phydev) }; 396 + T::config_aneg(dev)?; 397 + Ok(0) 398 + }) 399 + } 400 + 401 + /// # Safety 402 + /// 403 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 404 + unsafe extern "C" fn read_status_callback( 405 + phydev: *mut bindings::phy_device, 406 + ) -> core::ffi::c_int { 407 + from_result(|| { 408 + // SAFETY: This callback is called only in contexts 409 + // where we hold `phy_device->lock`, so the accessors on 410 + // `Device` are okay to call. 411 + let dev = unsafe { Device::from_raw(phydev) }; 412 + T::read_status(dev)?; 413 + Ok(0) 414 + }) 415 + } 416 + 417 + /// # Safety 418 + /// 419 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 420 + unsafe extern "C" fn match_phy_device_callback( 421 + phydev: *mut bindings::phy_device, 422 + ) -> core::ffi::c_int { 423 + // SAFETY: This callback is called only in contexts 424 + // where we hold `phy_device->lock`, so the accessors on 425 + // `Device` are okay to call. 426 + let dev = unsafe { Device::from_raw(phydev) }; 427 + T::match_phy_device(dev) as i32 428 + } 429 + 430 + /// # Safety 431 + /// 432 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 433 + unsafe extern "C" fn read_mmd_callback( 434 + phydev: *mut bindings::phy_device, 435 + devnum: i32, 436 + regnum: u16, 437 + ) -> i32 { 438 + from_result(|| { 439 + // SAFETY: This callback is called only in contexts 440 + // where we hold `phy_device->lock`, so the accessors on 441 + // `Device` are okay to call. 442 + let dev = unsafe { Device::from_raw(phydev) }; 443 + // CAST: the C side verifies devnum < 32. 444 + let ret = T::read_mmd(dev, devnum as u8, regnum)?; 445 + Ok(ret.into()) 446 + }) 447 + } 448 + 449 + /// # Safety 450 + /// 451 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 452 + unsafe extern "C" fn write_mmd_callback( 453 + phydev: *mut bindings::phy_device, 454 + devnum: i32, 455 + regnum: u16, 456 + val: u16, 457 + ) -> i32 { 458 + from_result(|| { 459 + // SAFETY: This callback is called only in contexts 460 + // where we hold `phy_device->lock`, so the accessors on 461 + // `Device` are okay to call. 462 + let dev = unsafe { Device::from_raw(phydev) }; 463 + T::write_mmd(dev, devnum as u8, regnum, val)?; 464 + Ok(0) 465 + }) 466 + } 467 + 468 + /// # Safety 469 + /// 470 + /// `phydev` must be passed by the corresponding callback in `phy_driver`. 471 + unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) { 472 + // SAFETY: This callback is called only in contexts 473 + // where we hold `phy_device->lock`, so the accessors on 474 + // `Device` are okay to call. 475 + let dev = unsafe { Device::from_raw(phydev) }; 476 + T::link_change_notify(dev); 477 + } 478 + } 479 + 480 + /// Driver structure for a particular PHY type. 481 + /// 482 + /// Wraps the kernel's [`struct phy_driver`]. 483 + /// This is used to register a driver for a particular PHY type with the kernel. 484 + /// 485 + /// # Invariants 486 + /// 487 + /// `self.0` is always in a valid state. 488 + /// 489 + /// [`struct phy_driver`]: ../../../../../../../include/linux/phy.h 490 + #[repr(transparent)] 491 + pub struct DriverVTable(Opaque<bindings::phy_driver>); 492 + 493 + // SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to 494 + // share `&DriverVTable` across execution context boundries. 495 + unsafe impl Sync for DriverVTable {} 496 + 497 + /// Creates a [`DriverVTable`] instance from [`Driver`]. 498 + /// 499 + /// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`. 500 + /// 501 + /// [`module_phy_driver`]: crate::module_phy_driver 502 + pub const fn create_phy_driver<T: Driver>() -> DriverVTable { 503 + // INVARIANT: All the fields of `struct phy_driver` are initialized properly. 504 + DriverVTable(Opaque::new(bindings::phy_driver { 505 + name: T::NAME.as_char_ptr().cast_mut(), 506 + flags: T::FLAGS, 507 + phy_id: T::PHY_DEVICE_ID.id, 508 + phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(), 509 + soft_reset: if T::HAS_SOFT_RESET { 510 + Some(Adapter::<T>::soft_reset_callback) 511 + } else { 512 + None 513 + }, 514 + get_features: if T::HAS_GET_FEATURES { 515 + Some(Adapter::<T>::get_features_callback) 516 + } else { 517 + None 518 + }, 519 + match_phy_device: if T::HAS_MATCH_PHY_DEVICE { 520 + Some(Adapter::<T>::match_phy_device_callback) 521 + } else { 522 + None 523 + }, 524 + suspend: if T::HAS_SUSPEND { 525 + Some(Adapter::<T>::suspend_callback) 526 + } else { 527 + None 528 + }, 529 + resume: if T::HAS_RESUME { 530 + Some(Adapter::<T>::resume_callback) 531 + } else { 532 + None 533 + }, 534 + config_aneg: if T::HAS_CONFIG_ANEG { 535 + Some(Adapter::<T>::config_aneg_callback) 536 + } else { 537 + None 538 + }, 539 + read_status: if T::HAS_READ_STATUS { 540 + Some(Adapter::<T>::read_status_callback) 541 + } else { 542 + None 543 + }, 544 + read_mmd: if T::HAS_READ_MMD { 545 + Some(Adapter::<T>::read_mmd_callback) 546 + } else { 547 + None 548 + }, 549 + write_mmd: if T::HAS_WRITE_MMD { 550 + Some(Adapter::<T>::write_mmd_callback) 551 + } else { 552 + None 553 + }, 554 + link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY { 555 + Some(Adapter::<T>::link_change_notify_callback) 556 + } else { 557 + None 558 + }, 559 + // SAFETY: The rest is zeroed out to initialize `struct phy_driver`, 560 + // sets `Option<&F>` to be `None`. 561 + ..unsafe { core::mem::MaybeUninit::<bindings::phy_driver>::zeroed().assume_init() } 562 + })) 563 + } 564 + 565 + /// Driver implementation for a particular PHY type. 566 + /// 567 + /// This trait is used to create a [`DriverVTable`]. 568 + #[vtable] 569 + pub trait Driver { 570 + /// Defines certain other features this PHY supports. 571 + /// It is a combination of the flags in the [`flags`] module. 572 + const FLAGS: u32 = 0; 573 + 574 + /// The friendly name of this PHY type. 575 + const NAME: &'static CStr; 576 + 577 + /// This driver only works for PHYs with IDs which match this field. 578 + /// The default id and mask are zero. 579 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0); 580 + 581 + /// Issues a PHY software reset. 582 + fn soft_reset(_dev: &mut Device) -> Result { 583 + Err(code::ENOTSUPP) 584 + } 585 + 586 + /// Probes the hardware to determine what abilities it has. 587 + fn get_features(_dev: &mut Device) -> Result { 588 + Err(code::ENOTSUPP) 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 + Err(code::ENOTSUPP) 601 + } 602 + 603 + /// Determines the negotiated speed and duplex. 604 + fn read_status(_dev: &mut Device) -> Result<u16> { 605 + Err(code::ENOTSUPP) 606 + } 607 + 608 + /// Suspends the hardware, saving state if needed. 609 + fn suspend(_dev: &mut Device) -> Result { 610 + Err(code::ENOTSUPP) 611 + } 612 + 613 + /// Resumes the hardware, restoring state if needed. 614 + fn resume(_dev: &mut Device) -> Result { 615 + Err(code::ENOTSUPP) 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 + Err(code::ENOTSUPP) 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 + Err(code::ENOTSUPP) 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`. 639 + pub struct Registration { 640 + drivers: Pin<&'static mut [DriverVTable]>, 641 + } 642 + 643 + impl Registration { 644 + /// Registers a PHY driver. 645 + pub fn register( 646 + module: &'static crate::ThisModule, 647 + drivers: Pin<&'static mut [DriverVTable]>, 648 + ) -> Result<Self> { 649 + if drivers.is_empty() { 650 + return Err(code::EINVAL); 651 + } 652 + // SAFETY: The type invariants of [`DriverVTable`] ensure that all elements of 653 + // the `drivers` slice are initialized properly. `drivers` will not be moved. 654 + // So it's just an FFI call. 655 + to_result(unsafe { 656 + bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0) 657 + })?; 658 + // INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`. 659 + Ok(Registration { drivers }) 660 + } 661 + } 662 + 663 + impl Drop for Registration { 664 + fn drop(&mut self) { 665 + // SAFETY: The type invariants guarantee that `self.drivers` is valid. 666 + // So it's just an FFI call. 667 + unsafe { 668 + bindings::phy_drivers_unregister(self.drivers[0].0.get(), self.drivers.len() as i32) 669 + }; 670 + } 671 + } 672 + 673 + /// An identifier for PHY devices on an MDIO/MII bus. 674 + /// 675 + /// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate 676 + /// PHY driver. 677 + pub struct DeviceId { 678 + id: u32, 679 + mask: DeviceMask, 680 + } 681 + 682 + impl DeviceId { 683 + /// Creates a new instance with the exact match mask. 684 + pub const fn new_with_exact_mask(id: u32) -> Self { 685 + DeviceId { 686 + id, 687 + mask: DeviceMask::Exact, 688 + } 689 + } 690 + 691 + /// Creates a new instance with the model match mask. 692 + pub const fn new_with_model_mask(id: u32) -> Self { 693 + DeviceId { 694 + id, 695 + mask: DeviceMask::Model, 696 + } 697 + } 698 + 699 + /// Creates a new instance with the vendor match mask. 700 + pub const fn new_with_vendor_mask(id: u32) -> Self { 701 + DeviceId { 702 + id, 703 + mask: DeviceMask::Vendor, 704 + } 705 + } 706 + 707 + /// Creates a new instance with a custom match mask. 708 + pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self { 709 + DeviceId { 710 + id, 711 + mask: DeviceMask::Custom(mask), 712 + } 713 + } 714 + 715 + /// Creates a new instance from [`Driver`]. 716 + pub const fn new_with_driver<T: Driver>() -> Self { 717 + T::PHY_DEVICE_ID 718 + } 719 + 720 + /// Get a `mask` as u32. 721 + pub const fn mask_as_int(&self) -> u32 { 722 + self.mask.as_int() 723 + } 724 + 725 + // macro use only 726 + #[doc(hidden)] 727 + pub const fn mdio_device_id(&self) -> bindings::mdio_device_id { 728 + bindings::mdio_device_id { 729 + phy_id: self.id, 730 + phy_id_mask: self.mask.as_int(), 731 + } 732 + } 733 + } 734 + 735 + enum DeviceMask { 736 + Exact, 737 + Model, 738 + Vendor, 739 + Custom(u32), 740 + } 741 + 742 + impl DeviceMask { 743 + const MASK_EXACT: u32 = !0; 744 + const MASK_MODEL: u32 = !0 << 4; 745 + const MASK_VENDOR: u32 = !0 << 10; 746 + 747 + const fn as_int(&self) -> u32 { 748 + match self { 749 + DeviceMask::Exact => Self::MASK_EXACT, 750 + DeviceMask::Model => Self::MASK_MODEL, 751 + DeviceMask::Vendor => Self::MASK_VENDOR, 752 + DeviceMask::Custom(mask) => *mask, 753 + } 754 + } 755 + } 756 + 757 + /// Declares a kernel module for PHYs drivers. 758 + /// 759 + /// This creates a static array of kernel's `struct phy_driver` and registers it. 760 + /// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information 761 + /// for module loading into the module binary file. Every driver needs an entry in `device_table`. 762 + /// 763 + /// # Examples 764 + /// 765 + /// ``` 766 + /// # mod module_phy_driver_sample { 767 + /// use kernel::c_str; 768 + /// use kernel::net::phy::{self, DeviceId}; 769 + /// use kernel::prelude::*; 770 + /// 771 + /// kernel::module_phy_driver! { 772 + /// drivers: [PhySample], 773 + /// device_table: [ 774 + /// DeviceId::new_with_driver::<PhySample>() 775 + /// ], 776 + /// name: "rust_sample_phy", 777 + /// author: "Rust for Linux Contributors", 778 + /// description: "Rust sample PHYs driver", 779 + /// license: "GPL", 780 + /// } 781 + /// 782 + /// struct PhySample; 783 + /// 784 + /// #[vtable] 785 + /// impl phy::Driver for PhySample { 786 + /// const NAME: &'static CStr = c_str!("PhySample"); 787 + /// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001); 788 + /// } 789 + /// # } 790 + /// ``` 791 + /// 792 + /// This expands to the following code: 793 + /// 794 + /// ```ignore 795 + /// use kernel::c_str; 796 + /// use kernel::net::phy::{self, DeviceId}; 797 + /// use kernel::prelude::*; 798 + /// 799 + /// struct Module { 800 + /// _reg: ::kernel::net::phy::Registration, 801 + /// } 802 + /// 803 + /// module! { 804 + /// type: Module, 805 + /// name: "rust_sample_phy", 806 + /// author: "Rust for Linux Contributors", 807 + /// description: "Rust sample PHYs driver", 808 + /// license: "GPL", 809 + /// } 810 + /// 811 + /// struct PhySample; 812 + /// 813 + /// #[vtable] 814 + /// impl phy::Driver for PhySample { 815 + /// const NAME: &'static CStr = c_str!("PhySample"); 816 + /// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001); 817 + /// } 818 + /// 819 + /// const _: () = { 820 + /// static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] = 821 + /// [::kernel::net::phy::create_phy_driver::<PhySample>()]; 822 + /// 823 + /// impl ::kernel::Module for Module { 824 + /// fn init(module: &'static ThisModule) -> Result<Self> { 825 + /// let drivers = unsafe { &mut DRIVERS }; 826 + /// let mut reg = ::kernel::net::phy::Registration::register( 827 + /// module, 828 + /// ::core::pin::Pin::static_mut(drivers), 829 + /// )?; 830 + /// Ok(Module { _reg: reg }) 831 + /// } 832 + /// } 833 + /// }; 834 + /// 835 + /// #[cfg(MODULE)] 836 + /// #[no_mangle] 837 + /// static __mod_mdio__phydev_device_table: [::kernel::bindings::mdio_device_id; 2] = [ 838 + /// ::kernel::bindings::mdio_device_id { 839 + /// phy_id: 0x00000001, 840 + /// phy_id_mask: 0xffffffff, 841 + /// }, 842 + /// ::kernel::bindings::mdio_device_id { 843 + /// phy_id: 0, 844 + /// phy_id_mask: 0, 845 + /// }, 846 + /// ]; 847 + /// ``` 848 + #[macro_export] 849 + macro_rules! module_phy_driver { 850 + (@replace_expr $_t:tt $sub:expr) => {$sub}; 851 + 852 + (@count_devices $($x:expr),*) => { 853 + 0usize $(+ $crate::module_phy_driver!(@replace_expr $x 1usize))* 854 + }; 855 + 856 + (@device_table [$($dev:expr),+]) => { 857 + // SAFETY: C will not read off the end of this constant since the last element is zero. 858 + #[cfg(MODULE)] 859 + #[no_mangle] 860 + static __mod_mdio__phydev_device_table: [$crate::bindings::mdio_device_id; 861 + $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [ 862 + $($dev.mdio_device_id()),+, 863 + $crate::bindings::mdio_device_id { 864 + phy_id: 0, 865 + phy_id_mask: 0 866 + } 867 + ]; 868 + }; 869 + 870 + (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => { 871 + struct Module { 872 + _reg: $crate::net::phy::Registration, 873 + } 874 + 875 + $crate::prelude::module! { 876 + type: Module, 877 + $($f)* 878 + } 879 + 880 + const _: () = { 881 + static mut DRIVERS: [$crate::net::phy::DriverVTable; 882 + $crate::module_phy_driver!(@count_devices $($driver),+)] = 883 + [$($crate::net::phy::create_phy_driver::<$driver>()),+]; 884 + 885 + impl $crate::Module for Module { 886 + fn init(module: &'static ThisModule) -> Result<Self> { 887 + // SAFETY: The anonymous constant guarantees that nobody else can access 888 + // the `DRIVERS` static. The array is used only in the C side. 889 + let drivers = unsafe { &mut DRIVERS }; 890 + let mut reg = $crate::net::phy::Registration::register( 891 + module, 892 + ::core::pin::Pin::static_mut(drivers), 893 + )?; 894 + Ok(Module { _reg: reg }) 895 + } 896 + } 897 + }; 898 + 899 + $crate::module_phy_driver!(@device_table [$($dev),+]); 900 + } 901 + }
+2
rust/uapi/uapi_helper.h
··· 7 7 */ 8 8 9 9 #include <uapi/asm-generic/ioctl.h> 10 + #include <uapi/linux/mii.h> 11 + #include <uapi/linux/ethtool.h>