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 4/5] rust: phy: add interrupt support
Date: Tue, 24 Mar 2026 18:52:48 +0300 [thread overview]
Message-ID: <20260324155249.15098-5-iprintercanon@gmail.com> (raw)
In-Reply-To: <20260324155249.15098-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 | 93 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 90 insertions(+), 3 deletions(-)
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index 9ffece7ee41c7..e8f920620841c 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;
@@ -211,6 +211,20 @@ pub fn interface(&self) -> u32 {
unsafe { (*phydev).interface }
}
+ /// Returns `true` if PHY interrupts are enabled.
+ ///
+ /// This reflects the `phydev->interrupts` field which is set by the PHY
+ /// core before calling [`Driver::config_intr`] to indicate whether
+ /// interrupts should be enabled or disabled.
+ pub fn is_interrupts_enabled(&self) -> bool {
+ // TODO: the code to access the bit field will be replaced with automatically
+ // generated code by bindgen when it becomes possible.
+ // SAFETY: The struct invariant ensures that we may access
+ // this field without additional synchronization.
+ let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
+ bit_field.get(18, 1) == 1
+ }
+
/// Gets the PHY's IRQ number.
pub fn irq(&self) -> i32 {
let phydev = self.0.get();
@@ -358,6 +372,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 {
@@ -393,8 +430,9 @@ impl<T: Driver> Adapter<T> {
/// `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.
+ // 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_init(dev)?;
Ok(0)
@@ -507,6 +545,30 @@ impl<T: Driver> Adapter<T> {
/// # 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
@@ -660,6 +722,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 {
@@ -743,6 +815,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-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 ` [PATCH net-next v2 3/5] rust: phy: add config_init, read_page, and write_page callbacks Artem Lytkin
2026-03-24 15:52 ` Artem Lytkin [this message]
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-5-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