rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: FUJITA Tomonori <fujita.tomonori@gmail.com>
To: rust-for-linux@vger.kernel.org
Cc: andrew@lunn.ch, benno.lossin@proton.me, tmgross@umich.edu
Subject: [RFC PATCH v2 1/2] rust: net::phy support for C45 register access
Date: Sat,  1 Jun 2024 13:35:34 +0900	[thread overview]
Message-ID: <20240601043535.53545-2-fujita.tomonori@gmail.com> (raw)
In-Reply-To: <20240601043535.53545-1-fujita.tomonori@gmail.com>

Adds support for C45 register access. Instead of adding read/write_c45
methods, this unifies the API to access C22 and C45 registers with
trait.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
---
 drivers/net/phy/ax88796b_rust.rs |   7 +-
 rust/kernel/net/phy.rs           | 192 +++++++++++++++++++++++++++----
 rust/uapi/uapi_helper.h          |   1 +
 3 files changed, 173 insertions(+), 27 deletions(-)

diff --git a/drivers/net/phy/ax88796b_rust.rs b/drivers/net/phy/ax88796b_rust.rs
index 5c92572962dc..8c7eb009d9fc 100644
--- a/drivers/net/phy/ax88796b_rust.rs
+++ b/drivers/net/phy/ax88796b_rust.rs
@@ -6,7 +6,7 @@
 //! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c)
 use kernel::{
     c_str,
-    net::phy::{self, DeviceId, Driver},
+    net::phy::{self, reg::C22, DeviceId, Driver},
     prelude::*,
     uapi,
 };
@@ -24,7 +24,6 @@
     license: "GPL",
 }
 
-const MII_BMCR: u16 = uapi::MII_BMCR as u16;
 const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16;
 const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16;
 
@@ -33,7 +32,7 @@
 // Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation
 // such as used on the Individual Computers' X-Surf 100 Zorro card.
 fn asix_soft_reset(dev: &mut phy::Device) -> Result {
-    dev.write(uapi::MII_BMCR as u16, 0)?;
+    dev.write(C22::BMCR, 0)?;
     dev.genphy_soft_reset()
 }
 
@@ -55,7 +54,7 @@ fn read_status(dev: &mut phy::Device) -> Result<u16> {
         }
         // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve
         // linkmode so use MII_BMCR as default values.
-        let ret = dev.read(MII_BMCR)?;
+        let ret = dev.read(C22::BMCR)?;
 
         if ret & BMCR_SPEED100 != 0 {
             dev.set_speed(uapi::SPEED_100);
diff --git a/rust/kernel/net/phy.rs b/rust/kernel/net/phy.rs
index fd40b703d224..286fd5a7ec91 100644
--- a/rust/kernel/net/phy.rs
+++ b/rust/kernel/net/phy.rs
@@ -175,32 +175,15 @@ pub fn set_duplex(&mut self, mode: DuplexMode) {
         unsafe { (*phydev).duplex = v };
     }
 
-    /// Reads a given C22 PHY register.
+    /// Reads a PHY register.
     // This function reads a hardware register and updates the stats so takes `&mut self`.
-    pub fn read(&mut self, regnum: u16) -> Result<u16> {
-        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, open code of `phy_read()` with a valid `phy_device` pointer
-        // `phydev`.
-        let ret = unsafe {
-            bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into())
-        };
-        if ret < 0 {
-            Err(Error::from_errno(ret))
-        } else {
-            Ok(ret as u16)
-        }
+    pub fn read<R: reg::Access>(&mut self, reg: R) -> Result<u16> {
+        reg.read(self)
     }
 
-    /// Writes a given C22 PHY register.
-    pub fn write(&mut self, regnum: u16, val: u16) -> Result {
-        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, open code of `phy_write()` with a valid `phy_device` pointer
-        // `phydev`.
-        to_result(unsafe {
-            bindings::mdiobus_write((*phydev).mdio.bus, (*phydev).mdio.addr, regnum.into(), val)
-        })
+    /// Writes a PHY register.
+    pub fn write<R: reg::Access>(&mut self, reg: R, val: u16) -> Result {
+        reg.write(self, val)
     }
 
     /// Reads a paged register.
@@ -302,6 +285,169 @@ pub fn genphy_read_abilities(&mut self) -> Result {
     }
 }
 
+/// Defines PHY registers.
+pub mod reg {
+    use super::Device;
+    use crate::build_assert;
+    use crate::error::*;
+    use crate::uapi;
+
+    /// Reads and writes PHY registers.
+    ///
+    /// This trait is used to implement multiple ways to read and write
+    /// PHY registers.
+    pub trait Access {
+        /// Reads a PHY register.
+        fn read(&self, dev: &mut Device) -> Result<u16>;
+
+        /// Writes a PHY register.
+        fn write(&self, dev: &mut Device, val: u16) -> Result;
+    }
+
+    /// C22 registers.
+    pub struct C22(u8);
+
+    impl C22 {
+        /// Basic mode control.
+        pub const BMCR: Self = C22(0x00);
+        /// Basic mode status.
+        pub const BMSR: Self = C22(0x01);
+        /// PHY identifier 1.
+        pub const PHYSID1: Self = C22(0x02);
+        /// PHY identifier 2.
+        pub const PHYSID2: Self = C22(0x03);
+        /// Auto-negotiation advertisement.
+        pub const ADVERTISE: Self = C22(0x04);
+        /// Auto-negotiation link partner base page ability.
+        pub const LPA: Self = C22(0x05);
+        /// Auto-negotiation expansion.
+        pub const EXPANSION: Self = C22(0x06);
+        /// Auto-negotiation next page transmit.
+        pub const NEXT_PAGE_TRANSMIT: Self = C22(0x07);
+        /// Auto-negotiation link partner received next page.
+        pub const LP_RECEIVED_NEXT_PAGE: Self = C22(0x08);
+        /// Master-slave control.
+        pub const MASTER_SLAVE_CONTROL: Self = C22(0x09);
+        /// Master-slave status.
+        pub const MASTER_SLAVE_STATUS: Self = C22(0x0a);
+        /// PSE Control.
+        pub const PSE_CONTROL: Self = C22(0x0b);
+        /// PSE Status.
+        pub const PSE_STATUS: Self = C22(0x0c);
+        /// MMD access control.
+        pub const MMD_CONTROL: Self = C22(0x0d);
+        /// MMD access address data.
+        pub const MMD_DATA: Self = C22(0x0e);
+        /// Extended status.
+        pub const EXTENDED_STATUS: Self = C22(0x0f);
+
+        /// Creates a new instance of `C22` with a vendor specific register.
+        pub const fn vendor_specific<const N: u8>() -> Self {
+            build_assert!(N > 0x0f && N < 0x20);
+            C22(N)
+        }
+    }
+
+    impl Access for C22 {
+        /// Reads a given C22 PHY register.
+        fn read(&self, dev: &mut Device) -> Result<u16> {
+            let phydev = dev.0.get();
+            // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Device`.
+            // So it's just an FFI call, open code of `phy_read()` with a valid `phy_device` pointer
+            // `phydev`.
+            let ret = unsafe {
+                bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, self.0.into())
+            };
+            if ret < 0 {
+                Err(Error::from_errno(ret))
+            } else {
+                Ok(ret as u16)
+            }
+        }
+
+        /// Writes a given C22 PHY register.
+        fn write(&self, dev: &mut Device, val: u16) -> Result {
+            let phydev = dev.0.get();
+            // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Device`.
+            // So it's just an FFI call, open code of `phy_write()` with a valid `phy_device` pointer
+            // `phydev`.
+            to_result(unsafe {
+                bindings::mdiobus_write((*phydev).mdio.bus, (*phydev).mdio.addr, self.0.into(), val)
+            })
+        }
+    }
+
+    /// MDIO manageable devices.
+    pub struct Mmd(u8);
+
+    impl Mmd {
+        /// Physical Medium Attachment/Dependent.
+        pub const PMAPMD: Self = Mmd(uapi::MDIO_MMD_PMAPMD as u8);
+        /// WAN interface sublayer.
+        pub const WIS: Self = Mmd(uapi::MDIO_MMD_WIS as u8);
+        /// Physical coding sublayer.
+        pub const PCS: Self = Mmd(uapi::MDIO_MMD_PCS as u8);
+        /// PHY Extender sublayer.
+        pub const PHYXS: Self = Mmd(uapi::MDIO_MMD_PHYXS as u8);
+        /// DTE Extender sublayer.
+        pub const DTEXS: Self = Mmd(uapi::MDIO_MMD_DTEXS as u8);
+        /// Transmission convergence.
+        pub const TC: Self = Mmd(uapi::MDIO_MMD_TC as u8);
+        /// Auto negotiation.
+        pub const AN: Self = Mmd(uapi::MDIO_MMD_AN as u8);
+        /// Clause 22 extension.
+        pub const C22_EXT: Self = Mmd(uapi::MDIO_MMD_C22EXT as u8);
+        /// Vendor specific 1.
+        pub const VEND1: Self = Mmd(uapi::MDIO_MMD_VEND1 as u8);
+        /// Vendor specific 2.
+        pub const VEND2: Self = Mmd(uapi::MDIO_MMD_VEND2 as u8);
+
+        /// Creates a new instance of `Mmd` with a specific device address.
+        pub fn new(devad: u8) -> Self {
+            Mmd(devad)
+        }
+    }
+
+    /// C45 registers.
+    pub struct C45 {
+        devad: Mmd,
+        regnum: u16,
+    }
+
+    impl C45 {
+        /// Creates a new instance of `C45`.
+        pub fn new(devad: Mmd, regnum: u16) -> Self {
+            Self { devad, regnum }
+        }
+    }
+
+    impl Access for C45 {
+        /// Reads a given C45 PHY register.
+        fn read(&self, dev: &mut Device) -> Result<u16> {
+            let phydev = dev.0.get();
+            // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Device`.
+            // So it's just an FFI call.
+            let ret =
+                unsafe { bindings::phy_read_mmd(phydev, self.devad.0.into(), self.regnum.into()) };
+            if ret < 0 {
+                Err(Error::from_errno(ret))
+            } else {
+                Ok(ret as u16)
+            }
+        }
+
+        /// Writes a given C45 PHY register.
+        fn write(&self, dev: &mut Device, val: u16) -> Result {
+            let phydev = dev.0.get();
+            // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Device`.
+            // So it's just an FFI call.
+            to_result(unsafe {
+                bindings::phy_write_mmd(phydev, self.devad.0.into(), self.regnum.into(), val)
+            })
+        }
+    }
+}
+
 /// Defines certain other features this PHY supports (like interrupts).
 ///
 /// These flag values are used in [`Driver::FLAGS`].
diff --git a/rust/uapi/uapi_helper.h b/rust/uapi/uapi_helper.h
index 08f5e9334c9e..76d3f103e764 100644
--- a/rust/uapi/uapi_helper.h
+++ b/rust/uapi/uapi_helper.h
@@ -7,5 +7,6 @@
  */
 
 #include <uapi/asm-generic/ioctl.h>
+#include <uapi/linux/mdio.h>
 #include <uapi/linux/mii.h>
 #include <uapi/linux/ethtool.h>
-- 
2.34.1


  reply	other threads:[~2024-06-01  4:37 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-06-01  4:35 [RFC PATCH v2 0/2] net::phy support for C45 FUJITA Tomonori
2024-06-01  4:35 ` FUJITA Tomonori [this message]
2024-06-01 12:21   ` [RFC PATCH v2 1/2] rust: net::phy support for C45 register access Benno Lossin
2024-06-02  7:24     ` FUJITA Tomonori
2024-06-02  9:59       ` Benno Lossin
2024-06-01  4:35 ` [RFC PATCH v2 2/2] rust: net::phy support for C45 genphy helpers FUJITA Tomonori
2024-06-01 12:23   ` Benno Lossin
2024-06-02  7:36     ` FUJITA Tomonori

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=20240601043535.53545-2-fujita.tomonori@gmail.com \
    --to=fujita.tomonori@gmail.com \
    --cc=andrew@lunn.ch \
    --cc=benno.lossin@proton.me \
    --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;
as well as URLs for NNTP newsgroup(s).