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 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.