From: Artem Lytkin <iprintercanon@gmail.com>
To: netdev@vger.kernel.org, rust-for-linux@vger.kernel.org
Cc: fujita.tomonori@gmail.com, andrew@lunn.ch, hkallweit1@gmail.com,
tmgross@umich.edu, ojeda@kernel.org, dakr@kernel.org
Subject: [PATCH 3/4] rust: phy: add config_init, read_page, and write_page callbacks
Date: Mon, 23 Mar 2026 23:19:24 +0300 [thread overview]
Message-ID: <20260323201925.8405-3-iprintercanon@gmail.com> (raw)
In-Reply-To: <20260323201925.8405-1-iprintercanon@gmail.com>
Add three new driver callbacks to the PHY abstraction:
- config_init: Called to initialize the PHY after a reset. This is
needed by nearly all real-world PHY drivers to configure
vendor-specific registers (RGMII delays, LED settings, etc.).
config_init was previously proposed in an RFC for the Rockchip PHY
driver but not merged at that time. This re-introduces it in a
form consistent with the existing vtable infrastructure.
- read_page / write_page: Required by page-based PHY chips (Realtek,
Marvell) for the kernel's paged register access infrastructure.
When these callbacks are registered, phy_read_paged(),
phy_write_paged(), and phy_modify_paged() use them to switch
register pages. Both must be implemented together.
Each callback follows the established Adapter<T> pattern with
unsafe extern "C" fn bridging to the Rust Driver trait method, and
conditional registration in create_phy_driver() via HAS_* flags
generated by the #[vtable] macro.
Signed-off-by: Artem Lytkin <iprintercanon@gmail.com>
---
rust/kernel/net/phy.rs | 83 ++++++++++++++++++++++++++++++++++++++++++
1 file changed, 83 insertions(+)
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 43d1ee360268b..8fb34d34fe7de 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -390,6 +390,51 @@ struct Adapter<T: Driver> {
}
impl<T: Driver> Adapter<T> {
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn config_init_callback(phydev: *mut bindings::phy_device) -> c_int {
+ from_result(|| {
+ // SAFETY: The C core calls config_init with the PHY mutex held
+ // (from phy_init_hw), so the accessors on `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::config_init(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn read_page_callback(phydev: *mut bindings::phy_device) -> c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ let page = T::read_page(dev)?;
+ Ok(page.into())
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn write_page_callback(
+ phydev: *mut bindings::phy_device,
+ page: c_int,
+ ) -> c_int {
+ from_result(|| {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock`, so the accessors on
+ // `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ let page = u16::try_from(page).map_err(|_| code::EINVAL)?;
+ T::write_page(dev, page)?;
+ Ok(0)
+ })
+ }
+
/// # Safety
///
/// `phydev` must be passed by the corresponding callback in `phy_driver`.
@@ -582,6 +627,11 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
flags: T::FLAGS,
phy_id: T::PHY_DEVICE_ID.id(),
phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
+ config_init: if T::HAS_CONFIG_INIT {
+ Some(Adapter::<T>::config_init_callback)
+ } else {
+ None
+ },
soft_reset: if T::HAS_SOFT_RESET {
Some(Adapter::<T>::soft_reset_callback)
} else {
@@ -632,6 +682,16 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
} else {
None
},
+ read_page: if T::HAS_READ_PAGE {
+ Some(Adapter::<T>::read_page_callback)
+ } else {
+ None
+ },
+ write_page: if T::HAS_WRITE_PAGE {
+ Some(Adapter::<T>::write_page_callback)
+ } else {
+ None
+ },
link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY {
Some(Adapter::<T>::link_change_notify_callback)
} else {
@@ -659,6 +719,11 @@ pub trait Driver {
/// The default id and mask are zero.
const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);
+ /// Called to initialize the PHY, including after a reset.
+ fn config_init(_dev: &mut Device) -> Result {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
/// Issues a PHY software reset.
fn soft_reset(_dev: &mut Device) -> Result {
build_error!(VTABLE_DEFAULT_ERROR)
@@ -711,6 +776,24 @@ fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result
build_error!(VTABLE_DEFAULT_ERROR)
}
+ /// Returns the current PHY register page number.
+ ///
+ /// Must be implemented together with [`Driver::write_page`]. The kernel's
+ /// paged register access infrastructure requires both callbacks to be
+ /// present.
+ fn read_page(_dev: &mut Device) -> Result<u16> {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
+ /// Sets the current PHY register page number.
+ ///
+ /// Must be implemented together with [`Driver::read_page`]. The kernel's
+ /// paged register access infrastructure requires both callbacks to be
+ /// present.
+ fn write_page(_dev: &mut Device, _page: u16) -> Result {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
/// Callback for notification of link change.
fn link_change_notify(_dev: &mut Device) {}
}
--
2.43.0
next prev parent reply other threads:[~2026-03-23 20:19 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-23 20:19 [PATCH 1/4] rust: phy: add read-only device field accessors Artem Lytkin
2026-03-23 20:19 ` [PATCH 2/4] rust: phy: add paged register access and bit manipulation helpers Artem Lytkin
2026-03-24 14:40 ` kernel test robot
2026-03-23 20:19 ` Artem Lytkin [this message]
2026-03-23 20:19 ` [PATCH 4/4] rust: phy: add interrupt support Artem Lytkin
2026-03-24 15:51 ` kernel test robot
2026-03-23 22:18 ` [PATCH 1/4] rust: phy: add read-only device field accessors Andrew Lunn
2026-03-23 22:21 ` Andrew Lunn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260323201925.8405-3-iprintercanon@gmail.com \
--to=iprintercanon@gmail.com \
--cc=andrew@lunn.ch \
--cc=dakr@kernel.org \
--cc=fujita.tomonori@gmail.com \
--cc=hkallweit1@gmail.com \
--cc=netdev@vger.kernel.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox