rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Benno Lossin <benno.lossin@proton.me>
To: FUJITA Tomonori <fujita.tomonori@gmail.com>,
	rust-for-linux@vger.kernel.org
Cc: andrew@lunn.ch, tmgross@umich.edu
Subject: Re: [RFC PATCH v2 1/2] rust: net::phy support for C45 register access
Date: Sat, 01 Jun 2024 12:21:14 +0000	[thread overview]
Message-ID: <1def4559-d812-4426-94bb-b668f9ccb824@proton.me> (raw)
In-Reply-To: <20240601043535.53545-2-fujita.tomonori@gmail.com>

On 01.06.24 06:35, FUJITA Tomonori wrote:
> 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.

The short commit message only mentions C45, should it also include C22?

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

I would have put this into its own file under `phy/reg.rs`.

> +    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 {

I think `Register` is a better name.

> +        /// 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);

An error message would be nice.

> +            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)

Is there also a range that makes sense to exclude (similar to C22)?

> +        }
> +    }
> +
> +    /// 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 {

I really like that the first argument has a proper type now, do you
think that the same is also possible for `regnum`? Or are there no
common values for `regnum` (that also have the same meaning across
devices/drivers)? In that case, keep the `u16`.

---
Cheers,
Benno

> +            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 12:21 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 ` [RFC PATCH v2 1/2] rust: net::phy support for C45 register access FUJITA Tomonori
2024-06-01 12:21   ` Benno Lossin [this message]
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=1def4559-d812-4426-94bb-b668f9ccb824@proton.me \
    --to=benno.lossin@proton.me \
    --cc=andrew@lunn.ch \
    --cc=fujita.tomonori@gmail.com \
    --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).