From patchwork Tue Aug 20 22:57:17 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: FUJITA Tomonori X-Patchwork-Id: 13770621 X-Patchwork-Delegate: kuba@kernel.org Received: from mail-pg1-f182.google.com (mail-pg1-f182.google.com [209.85.215.182]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id CDCB41C8FDE; Tue, 20 Aug 2024 22:59:15 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.182 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724194757; cv=none; b=pKCgEOKe//nuJo4M9NAwwGjYxjyM4KXbWzbHQIQrCvYgz9rMgZ/4fWmc61RAMMtFAqkZxBbUsitipxsskTMIc8IUbdcJ/xakUaQS/l+lTAatzUND8UCGQAFojWKFsCUR34GosGtGLKPyUR/SdgD7IaJFeo28467O9DG0eBQCGF4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1724194757; c=relaxed/simple; bh=S5zkxpATFwetTi9bWfpFFdeUxKyFSKs+AMtNz4KCZV8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=V3l6Ct+/DiZrdw1jL/YvmeeSec/zbnMFhTVHrw5kQ2ZoUTnt8REh9PJWfECndmm4xU8vNM1Ww9q4cZSJLyzijaBhG6Ba0OH2dqVYCW1ZVknBuTgKXuIQ/48vQDjkyY7fGKTHSieAk3gf01INrMp6U78L3vmvV4e9vLhAUpCZZF0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Bcbz0KLs; arc=none smtp.client-ip=209.85.215.182 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Bcbz0KLs" Received: by mail-pg1-f182.google.com with SMTP id 41be03b00d2f7-7c6aee8e8daso4193081a12.0; Tue, 20 Aug 2024 15:59:15 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1724194755; x=1724799555; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=XXUuOruEl2gk6u3o0am5+Sa5un4jX2I2MrYZDBAKn70=; b=Bcbz0KLsWGiOwL8fRe0RL0SpUZ7kpvEVp0+m/Y8D64ivvGFoeJV8vJPN5slp7yWAAM aiAs3Dj95vPqVLl+FZJqXgNu24xLvUrCZo+VGFK5ugqPrQH+Cf951nsI2q2jaP8rod0p O+YEgXuCe1T0npOB5ZCFKt8qzxjnDqAKU6/uA6uM/8tQRp5SdMg3N5xIuKm+5QVQu6oi 0/UKShUBYcf86SR0YU2/3CUzhMkzuLCJYjIWp9sYspelPyc3rJTH+eVakdgxscT+9Pw2 nBpMDsRCywCSKP/B0nnibJAMguRQX+Gz8nxQ2e4CFN6rjz+taegDG3YRlroXnVO3MlFV RiCg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1724194755; x=1724799555; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=XXUuOruEl2gk6u3o0am5+Sa5un4jX2I2MrYZDBAKn70=; b=TYkCLc1rYMQJaiyWFY3Bz1VguqZqAYWifNh039fipYIPSs565F+GhqUVcOAym9g0Vl /QGo1gK67tfQS5XYB4sqGbywt44csU0bam6xhIhmgHbLNMoDXf69EqYGdDw3ZJiFL5+K duiMtTsNzym3XLzH18o/oQBNztxtqfcDR7MwAPQ8PhjKmOZZ93Aj7PloOkrMLaEalgLG YKMu4PcE9N8LMG21ms0vxYPw+uPgFYph0bCP8dxjW/y/drStIochDMyiKCvpWZlsgfLL Y8RsX+J1HnmWCzjEbEbvZjkrllxe+fzle2QlSqVuSOQ8RaFxAtlcWO/g8FQu8rfXjM3A WBSA== X-Gm-Message-State: AOJu0YxS7GNvkX9bykRhypkwZFO6/IEkKqVinAQ+LSRZX1jPhqyJWzpQ nRH4Pg/bLC36v+vfG/4HUC2ZW7VZJf0aO8Zdk0/2iDEbUe2arZCgicg0Slcq X-Google-Smtp-Source: AGHT+IFRaTP+pypxnjOPwGEGth/XUUKgWAJslcHcHW6tNzouiQPV+gObttE1bWvvyvnIcy/UNB+0Ng== X-Received: by 2002:a05:6a21:3482:b0:1c4:8291:e94e with SMTP id adf61e73a8af0-1cad818534emr1248675637.45.1724194754633; Tue, 20 Aug 2024 15:59:14 -0700 (PDT) Received: from localhost.localdomain (p4468007-ipxg23001hodogaya.kanagawa.ocn.ne.jp. [153.204.200.7]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-7c6b61d5045sm9922076a12.38.2024.08.20.15.59.12 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 20 Aug 2024 15:59:14 -0700 (PDT) From: FUJITA Tomonori To: netdev@vger.kernel.org Cc: rust-for-linux@vger.kernel.org, andrew@lunn.ch, tmgross@umich.edu, miguel.ojeda.sandonis@gmail.com, benno.lossin@proton.me, aliceryhl@google.com Subject: [PATCH net-next v6 4/6] rust: net::phy unified read/write API for C22 and C45 registers Date: Tue, 20 Aug 2024 22:57:17 +0000 Message-ID: <20240820225719.91410-5-fujita.tomonori@gmail.com> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240820225719.91410-1-fujita.tomonori@gmail.com> References: <20240820225719.91410-1-fujita.tomonori@gmail.com> Precedence: bulk X-Mailing-List: netdev@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Patchwork-Delegate: kuba@kernel.org Add the unified read/write API for C22 and C45 registers. The abstractions support access to only C22 registers now. Instead of adding read/write_c45 methods specifically for C45, a new reg module supports the unified API to access C22 and C45 registers with trait, by calling an appropriate phylib functions. Reviewed-by: Trevor Gross Reviewed-by: Benno Lossin Reviewed-by: Andrew Lunn Signed-off-by: FUJITA Tomonori --- MAINTAINERS | 1 + drivers/net/phy/ax88796b_rust.rs | 7 +- rust/kernel/net/phy.rs | 31 ++--- rust/kernel/net/phy/reg.rs | 196 +++++++++++++++++++++++++++++++ rust/uapi/uapi_helper.h | 1 + 5 files changed, 209 insertions(+), 27 deletions(-) create mode 100644 rust/kernel/net/phy/reg.rs diff --git a/MAINTAINERS b/MAINTAINERS index 5dbf23cf11c8..9dbfcf77acb2 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -8354,6 +8354,7 @@ L: netdev@vger.kernel.org L: rust-for-linux@vger.kernel.org S: Maintained F: rust/kernel/net/phy.rs +F: rust/kernel/net/phy/reg.rs EXEC & BINFMT API, ELF R: Eric Biederman 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 { } // 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 b16e8c10a0a2..45866db14c76 100644 --- a/rust/kernel/net/phy.rs +++ b/rust/kernel/net/phy.rs @@ -9,6 +9,8 @@ use crate::{error::*, prelude::*, types::Opaque}; use core::{marker::PhantomData, ptr::addr_of_mut}; +pub mod reg; + /// PHY state machine states. /// /// Corresponds to the kernel's [`enum phy_state`]. @@ -177,32 +179,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 { - 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(&mut self, reg: R) -> Result { + 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(&mut self, reg: R, val: u16) -> Result { + reg.write(self, val) } /// Reads a paged register. diff --git a/rust/kernel/net/phy/reg.rs b/rust/kernel/net/phy/reg.rs new file mode 100644 index 000000000000..191b96a524f5 --- /dev/null +++ b/rust/kernel/net/phy/reg.rs @@ -0,0 +1,196 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2024 FUJITA Tomonori + +//! PHY register interfaces. +//! +//! This module provides support for accessing PHY registers in the +//! Ethernet management interface clauses 22 and 45 register namespaces, as +//! defined in IEEE 802.3. + +use super::Device; +use crate::build_assert; +use crate::error::*; +use crate::uapi; + +mod private { + /// Marker that a trait cannot be implemented outside of this crate + pub trait Sealed {} +} + +/// Accesses PHY registers. +/// +/// This trait is used to implement the unified interface to access +/// C22 and C45 PHY registers. +/// +/// # Examples +/// +/// ```ignore +/// fn link_change_notify(dev: &mut Device) { +/// // read C22 BMCR register +/// dev.read(C22::BMCR); +/// // read C45 PMA/PMD control 1 register +/// dev.read(C45::new(Mmd::PMAPMD, 0)); +/// } +/// ``` +pub trait Register: private::Sealed { + /// Reads a PHY register. + fn read(&self, dev: &mut Device) -> Result; + + /// Writes a PHY register. + fn write(&self, dev: &mut Device, val: u16) -> Result; +} + +/// A single MDIO clause 22 register address (5 bits). +#[derive(Copy, Clone)] +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 Register control. + pub const MMD_CONTROL: Self = C22(0x0d); + /// MMD Register 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() -> Self { + build_assert!( + N > 0x0f && N < 0x20, + "Vendor-specific register address must be between 16 and 31" + ); + C22(N) + } +} + +impl private::Sealed for C22 {} + +impl Register for C22 { + fn read(&self, dev: &mut Device) -> 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_read()` with a valid `phy_device` pointer + // `phydev`. + let ret = unsafe { + bindings::mdiobus_read((*phydev).mdio.bus, (*phydev).mdio.addr, self.0.into()) + }; + to_result(ret)?; + Ok(ret as u16) + } + + 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) + }) + } +} + +/// A single MDIO clause 45 register device and address. +#[derive(Copy, Clone)] +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); + /// Separated PMA (1). + pub const SEPARATED_PMA1: Self = Mmd(8); + /// Separated PMA (2). + pub const SEPARATED_PMA2: Self = Mmd(9); + /// Separated PMA (3). + pub const SEPARATED_PMA3: Self = Mmd(10); + /// Separated PMA (4). + pub const SEPARATED_PMA4: Self = Mmd(11); + /// OFDM PMA/PMD. + pub const OFDM_PMAPMD: Self = Mmd(12); + /// Power unit. + pub const POWER_UNIT: Self = Mmd(13); + /// 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); +} + +/// A single MDIO clause 45 register device and address. +/// +/// Clause 45 uses a 5-bit device address to access a specific MMD within +/// a port, then a 16-bit register address to access a location within +/// that device. `C45` represents this by storing a [`Mmd`] and +/// a register number. +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 private::Sealed for C45 {} + +impl Register for C45 { + fn read(&self, dev: &mut Device) -> 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. + let ret = + unsafe { bindings::phy_read_mmd(phydev, self.devad.0.into(), self.regnum.into()) }; + to_result(ret)?; + Ok(ret as u16) + } + + 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) + }) + } +} 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 +#include #include #include