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 net-next v2 3/5] rust: phy: add config_init, read_page, and write_page callbacks
Date: Tue, 24 Mar 2026 18:52:47 +0300 [thread overview]
Message-ID: <20260324155249.15098-4-iprintercanon@gmail.com> (raw)
In-Reply-To: <20260324155249.15098-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 142f7101723c8..9ffece7ee41c7 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -388,6 +388,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`.
@@ -580,6 +625,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 {
@@ -630,6 +680,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 {
@@ -657,6 +717,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)
@@ -709,6 +774,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-24 15:53 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-24 15:52 [PATCH net-next v2 0/5] rust: phy: extend abstractions for real-world PHY drivers Artem Lytkin
2026-03-24 15:52 ` [PATCH net-next v2 1/5] rust: phy: add read-only device field accessors Artem Lytkin
2026-03-24 15:52 ` [PATCH net-next v2 2/5] rust: phy: add paged register access and bit manipulation helpers Artem Lytkin
2026-03-24 15:52 ` Artem Lytkin [this message]
2026-03-24 15:52 ` [PATCH net-next v2 4/5] rust: phy: add interrupt support Artem Lytkin
2026-03-24 15:52 ` [PATCH net-next v2 5/5] net: phy: realtek: add Rust RTL8211F PHY driver Artem Lytkin
2026-03-24 15:57 ` 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=20260324155249.15098-4-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.