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 4/4] rust: phy: add interrupt support
Date: Mon, 23 Mar 2026 23:19:25 +0300 [thread overview]
Message-ID: <20260323201925.8405-4-iprintercanon@gmail.com> (raw)
In-Reply-To: <20260323201925.8405-1-iprintercanon@gmail.com>
Add interrupt handling support to the Rust PHY abstraction:
New driver callbacks:
- config_intr: Enables or disables PHY link state change interrupts.
- handle_interrupt: Called when the PHY's interrupt fires. Returns
IrqReturn (reused from kernel::irq). Unlike other callbacks that
use from_result(), this directly returns irqreturn_t matching the
C callback signature.
New Device methods:
- trigger_machine(): Schedules a PHY state machine update. Used in
interrupt handlers after detecting a link change event.
- phy_error(): Reports a PHY error and transitions the state machine
to the error state. Produces a WARN_ON. Must be called with
phy_device->lock held (which is the case inside handle_interrupt).
Both callbacks run with phy_device->lock held (from phy_interrupt()
in the threaded IRQ context), consistent with the existing callback
safety model.
These additions enable Rust PHY drivers to use interrupt-driven link
detection, which is required for production-quality drivers like the
Realtek RTL8211F.
Signed-off-by: Artem Lytkin <iprintercanon@gmail.com>
---
rust/kernel/net/phy.rs | 79 +++++++++++++++++++++++++++++++++++++++++-
1 file changed, 78 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 8fb34d34fe7de..3a75d3a90333e 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -6,7 +6,7 @@
//!
//! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
-use crate::{device_id::RawDeviceId, error::*, prelude::*, types::Opaque};
+use crate::{device_id::RawDeviceId, error::*, irq::IrqReturn, prelude::*, types::Opaque};
use core::{marker::PhantomData, ptr::addr_of_mut};
pub mod reg;
@@ -360,6 +360,29 @@ pub fn genphy_read_abilities(&mut self) -> Result {
// So it's just an FFI call.
to_result(unsafe { bindings::genphy_read_abilities(phydev) })
}
+
+ /// Triggers the PHY state machine to run.
+ ///
+ /// Used in interrupt handlers to schedule a state machine update
+ /// after processing an interrupt event.
+ pub fn trigger_machine(&mut self) {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ unsafe { bindings::phy_trigger_machine(phydev) };
+ }
+
+ /// Reports a PHY error and moves the state machine to the error state.
+ ///
+ /// Used in interrupt handlers when a register read fails. This will
+ /// produce a kernel `WARN_ON`. Must be called with `phy_device->lock`
+ /// held (which is the case inside [`Driver::handle_interrupt`]).
+ pub fn phy_error(&mut self) {
+ let phydev = self.0.get();
+ // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
+ // So it's just an FFI call.
+ unsafe { bindings::phy_error(phydev) };
+ }
}
impl AsRef<kernel::device::Device> for Device {
@@ -509,6 +532,35 @@ impl<T: Driver> Adapter<T> {
/// # Safety
///
/// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn config_intr_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) };
+ T::config_intr(dev)?;
+ Ok(0)
+ })
+ }
+
+ /// # Safety
+ ///
+ /// `phydev` must be passed by the corresponding callback in `phy_driver`.
+ unsafe extern "C" fn handle_interrupt_callback(
+ phydev: *mut bindings::phy_device,
+ ) -> bindings::irqreturn_t {
+ // SAFETY: This callback is called only in contexts
+ // where we hold `phy_device->lock` (from phy_interrupt),
+ // so the accessors on `Device` are okay to call.
+ let dev = unsafe { Device::from_raw(phydev) };
+ T::handle_interrupt(dev) as core::ffi::c_uint
+ }
+
unsafe extern "C" fn config_aneg_callback(phydev: *mut bindings::phy_device) -> c_int {
from_result(|| {
// SAFETY: This callback is called only in contexts
@@ -662,6 +714,16 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
} else {
None
},
+ config_intr: if T::HAS_CONFIG_INTR {
+ Some(Adapter::<T>::config_intr_callback)
+ } else {
+ None
+ },
+ handle_interrupt: if T::HAS_HANDLE_INTERRUPT {
+ Some(Adapter::<T>::handle_interrupt_callback)
+ } else {
+ None
+ },
config_aneg: if T::HAS_CONFIG_ANEG {
Some(Adapter::<T>::config_aneg_callback)
} else {
@@ -745,6 +807,21 @@ fn match_phy_device(_dev: &Device) -> bool {
false
}
+ /// Enables or disables PHY interrupts.
+ fn config_intr(_dev: &mut Device) -> Result {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
+ /// Handles a PHY interrupt.
+ ///
+ /// Called when the PHY's interrupt line fires. The driver should read the
+ /// interrupt status register to determine the cause and call
+ /// [`Device::trigger_machine`] to schedule a state machine update.
+ /// Returns [`IrqReturn::Handled`] if the interrupt was from this PHY.
+ fn handle_interrupt(_dev: &mut Device) -> IrqReturn {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
/// Configures the advertisement and resets auto-negotiation
/// if auto-negotiation is enabled.
fn config_aneg(_dev: &mut Device) -> Result {
--
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 ` [PATCH 3/4] rust: phy: add config_init, read_page, and write_page callbacks Artem Lytkin
2026-03-23 20:19 ` Artem Lytkin [this message]
2026-03-24 15:51 ` [PATCH 4/4] rust: phy: add interrupt support 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-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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox