Commit fbdaffe4 authored by David S. Miller's avatar David S. Miller

Merge branch 'am-qt2025-phy-rust'

FUJITA Tomonori says:

====================
net: phy: add Applied Micro QT2025 PHY driver

This patchset adds a PHY driver for Applied Micro Circuits Corporation
QT2025.

The first patch adds Rust equivalent to include/linux/sizes.h, makes
code more readable. The 2-5th patches update the PHYLIB Rust bindings.
The 4th and 5th patches have been reviewed previously in a different
thread [1].

QT2025 PHY support was implemented as a part of an Ethernet driver for
Tehuti Networks TN40xx chips. Multiple vendors (DLink, Asus, Edimax,
QNAP, etc) developed adapters based on TN40xx chips. Tehuti Networks
went out of business and the driver wasn't merged into mainline. But
it's still distributed with some of the hardware (and also available
on some vendor sites).

The original driver handles multiple PHY hardware (AMCC QT2025, TI
TLK10232, Aqrate AQR105, and Marvell MV88X3120, MV88X3310, and
MV88E2010). I divided the original driver into MAC and PHY drivers and
implemented a QT2025 PHY driver in Rust.

The MAC driver for Tehuti Networks TN40xx chips was already merged in
6.11-rc1. The MAC and this PHY drivers have been tested with Edimax
EN-9320SFP+ 10G network adapter.

[1] https://lore.kernel.org/rust-for-linux/20240607052113.69026-1-fujita.tomonori@gmail.com/

v7:
- add Trevor as Reviewer to MAINTAINERS file entry
- add Trevor Reviewed-by
- add/fix comments
- replace uppercase hex with lowercase
- remove unnecessary code
- update the commit message (1st patch)
v6: https://lore.kernel.org/netdev/20240820225719.91410-1-fujita.tomonori@gmail.com/
- improve comments
- make the logic to load firmware more readable
- add Copy trait to reg::{C22 and C45}
- add Trevor Reviewed-by
v5: https://lore.kernel.org/netdev/20240819005345.84255-1-fujita.tomonori@gmail.com/
- fix the comments (3th patch)
- add RUST_FW_LOADER_ABSTRACTIONS dependency
- add Andrew and Benno Reviewed-by
v4: https://lore.kernel.org/netdev/20240817051939.77735-1-fujita.tomonori@gmail.com/
- fix the comments
- add Andrew's Reviewed-by
- fix the order of tags
- remove wrong endianness conversion
v3: https://lore.kernel.org/netdev/20240804233835.223460-1-fujita.tomonori@gmail.com/
- use addr_of_mut!` to avoid intermediate mutable reference
- update probe callback's Safety comment
- add MODULE_FIRMWARE equivalent
- add Alice's Reviewed-by
v2: https://lore.kernel.org/netdev/20240731042136.201327-1-fujita.tomonori@gmail.com/
- add comments in accordance with the hw datasheet
- unify C22 and C45 APIs
- load firmware in probe callback instead of config_init
- use firmware API
- handle firmware endian
- check firmware size
- use SZ_*K constants
- avoid confusing phy_id variable
v1: https://lore.kernel.org/netdev/20240415104701.4772-1-fujita.tomonori@gmail.com/
====================

rom: FUJITA Tomonori <fujita.tomonori@gmail.com>
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 v7 0/6] net: phy: add Applied Micro QT2025 PHY driver
Date: Sat, 24 Aug 2024 02:06:10 +0000	[thread overview]
Message-ID: <20240824020617.113828-1-fujita.tomonori@gmail.com> (raw)

This patchset adds a PHY driver for Applied Micro Circuits Corporation
QT2025.

The first patch adds Rust equivalent to include/linux/sizes.h, makes
code more readable. The 2-5th patches update the PHYLIB Rust bindings.
The 4th and 5th patches have been reviewed previously in a different
thread [1].

QT2025 PHY support was implemented as a part of an Ethernet driver for
Tehuti Networks TN40xx chips. Multiple vendors (DLink, Asus, Edimax,
QNAP, etc) developed adapters based on TN40xx chips. Tehuti Networks
went out of business and the driver wasn't merged into mainline. But
it's still distributed with some of the hardware (and also available
on some vendor sites).

The original driver handles multiple PHY hardware (AMCC QT2025, TI
TLK10232, Aqrate AQR105, and Marvell MV88X3120, MV88X3310, and
MV88E2010). I divided the original driver into MAC and PHY drivers and
implemented a QT2025 PHY driver in Rust.

The MAC driver for Tehuti Networks TN40xx chips was already merged in
6.11-rc1. The MAC and this PHY drivers have been tested with Edimax
EN-9320SFP+ 10G network adapter.

[1] https://lore.kernel.org/rust-for-linux/20240607052113.69026-1-fujita.tomonori@gmail.com/

v7:
- add Trevor as Reviewer to MAINTAINERS file entry
- add Trevor Reviewed-by
- add/fix comments
- replace uppercase hex with lowercase
- remove unnecessary code
- update the commit message (1st patch)
v6: https://lore.kernel.org/netdev/20240820225719.91410-1-fujita.tomonori@gmail.com/
- improve comments
- make the logic to load firmware more readable
- add Copy trait to reg::{C22 and C45}
- add Trevor Reviewed-by
v5: https://lore.kernel.org/netdev/20240819005345.84255-1-fujita.tomonori@gmail.com/
- fix the comments (3th patch)
- add RUST_FW_LOADER_ABSTRACTIONS dependency
- add Andrew and Benno Reviewed-by
v4: https://lore.kernel.org/netdev/20240817051939.77735-1-fujita.tomonori@gmail.com/
- fix the comments
- add Andrew's Reviewed-by
- fix the order of tags
- remove wrong endianness conversion
v3: https://lore.kernel.org/netdev/20240804233835.223460-1-fujita.tomonori@gmail.com/
- use addr_of_mut!` to avoid intermediate mutable reference
- update probe callback's Safety comment
- add MODULE_FIRMWARE equivalent
- add Alice's Reviewed-by
v2: https://lore.kernel.org/netdev/20240731042136.201327-1-fujita.tomonori@gmail.com/
- add comments in accordance with the hw datasheet
- unify C22 and C45 APIs
- load firmware in probe callback instead of config_init
- use firmware API
- handle firmware endian
- check firmware size
- use SZ_*K constants
- avoid confusing phy_id variable
v1: https://lore.kernel.org/netdev/20240415104701.4772-1-fujita.tomonori@gmail.com/Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>

rom: FUJITA Tomonori <fujita.tomonori@gmail.com>
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 v7 0/6] net: phy: add Applied Micro QT2025 PHY driver
Date: Sat, 24 Aug 2024 02:06:10 +0000	[thread overview]
Message-ID: <20240824020617.113828-1-fujita.tomonori@gmail.com> (raw)

This patchset adds a PHY driver for Applied Micro Circuits Corporation
QT2025.

The first patch adds Rust equivalent to include/linux/sizes.h, makes
code more readable. The 2-5th patches update the PHYLIB Rust bindings.
The 4th and 5th patches have been reviewed previously in a different
thread [1].

QT2025 PHY support was implemented as a part of an Ethernet driver for
Tehuti Networks TN40xx chips. Multiple vendors (DLink, Asus, Edimax,
QNAP, etc) developed adapters based on TN40xx chips. Tehuti Networks
went out of business and the driver wasn't merged into mainline. But
it's still distributed with some of the hardware (and also available
on some vendor sites).

The original driver handles multiple PHY hardware (AMCC QT2025, TI
TLK10232, Aqrate AQR105, and Marvell MV88X3120, MV88X3310, and
MV88E2010). I divided the original driver into MAC and PHY drivers and
implemented a QT2025 PHY driver in Rust.

The MAC driver for Tehuti Networks TN40xx chips was already merged in
6.11-rc1. The MAC and this PHY drivers have been tested with Edimax
EN-9320SFP+ 10G network adapter.

[1] https://lore.kernel.org/rust-for-linux/20240607052113.69026-1-fujita.tomonori@gmail.com/

v7:
- add Trevor as Reviewer to MAINTAINERS file entry
- add Trevor Reviewed-by
- add/fix comments
- replace uppercase hex with lowercase
- remove unnecessary code
- update the commit message (1st patch)
v6: https://lore.kernel.org/netdev/20240820225719.91410-1-fujita.tomonori@gmail.com/
- improve comments
- make the logic to load firmware more readable
- add Copy trait to reg::{C22 and C45}
- add Trevor Reviewed-by
v5: https://lore.kernel.org/netdev/20240819005345.84255-1-fujita.tomonori@gmail.com/
- fix the comments (3th patch)
- add RUST_FW_LOADER_ABSTRACTIONS dependency
- add Andrew and Benno Reviewed-by
v4: https://lore.kernel.org/netdev/20240817051939.77735-1-fujita.tomonori@gmail.com/
- fix the comments
- add Andrew's Reviewed-by
- fix the order of tags
- remove wrong endianness conversion
v3: https://lore.kernel.org/netdev/20240804233835.223460-1-fujita.tomonori@gmail.com/
- use addr_of_mut!` to avoid intermediate mutable reference
- update probe callback's Safety comment
- add MODULE_FIRMWARE equivalent
- add Alice's Reviewed-by
v2: https://lore.kernel.org/netdev/20240731042136.201327-1-fujita.tomonori@gmail.com/
- add comments in accordance with the hw datasheet
- unify C22 and C45 APIs
- load firmware in probe callback instead of config_init
- use firmware API
- handle firmware endian
- check firmware size
- use SZ_*K constants
- avoid confusing phy_id variable
v1: https://lore.kernel.org/netdev/20240415104701.4772-1-fujita.tomonori@gmail.com/Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
Reviewed-by: default avatarAndrew Lunn <andrew@lunn.ch>
parents 670726a8 fd3eaad8
......@@ -1609,6 +1609,14 @@ F: Documentation/admin-guide/perf/xgene-pmu.rst
F: Documentation/devicetree/bindings/perf/apm-xgene-pmu.txt
F: drivers/perf/xgene_pmu.c
APPLIED MICRO QT2025 PHY DRIVER
M: FUJITA Tomonori <fujita.tomonori@gmail.com>
R: Trevor Gross <tmgross@umich.edu>
L: netdev@vger.kernel.org
L: rust-for-linux@vger.kernel.org
S: Maintained
F: drivers/net/phy/qt2025.rs
APTINA CAMERA SENSOR PLL
M: Laurent Pinchart <Laurent.pinchart@ideasonboard.com>
L: linux-media@vger.kernel.org
......@@ -8357,6 +8365,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 <ebiederm@xmission.com>
......
......@@ -112,6 +112,13 @@ config ADIN1100_PHY
Currently supports the:
- ADIN1100 - Robust,Industrial, Low Power 10BASE-T1L Ethernet PHY
config AMCC_QT2025_PHY
tristate "AMCC QT2025 PHY"
depends on RUST_PHYLIB_ABSTRACTIONS
depends on RUST_FW_LOADER_ABSTRACTIONS
help
Adds support for the Applied Micro Circuits Corporation QT2025 PHY.
source "drivers/net/phy/aquantia/Kconfig"
config AX88796B_PHY
......
......@@ -37,6 +37,7 @@ obj-$(CONFIG_ADIN_PHY) += adin.o
obj-$(CONFIG_ADIN1100_PHY) += adin1100.o
obj-$(CONFIG_AIR_EN8811H_PHY) += air_en8811h.o
obj-$(CONFIG_AMD_PHY) += amd.o
obj-$(CONFIG_AMCC_QT2025_PHY) += qt2025.o
obj-$(CONFIG_AQUANTIA_PHY) += aquantia/
ifdef CONFIG_AX88796B_RUST_PHY
obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o
......
......@@ -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);
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) Tehuti Networks Ltd.
// Copyright (C) 2024 FUJITA Tomonori <fujita.tomonori@gmail.com>
//! Applied Micro Circuits Corporation QT2025 PHY driver
//!
//! This driver is based on the vendor driver `QT2025_phy.c`. This source
//! and firmware can be downloaded on the EN-9320SFP+ support site.
//!
//! The QT2025 PHY integrates an Intel 8051 micro-controller.
use kernel::c_str;
use kernel::error::code;
use kernel::firmware::Firmware;
use kernel::net::phy::{
self,
reg::{Mmd, C45},
DeviceId, Driver,
};
use kernel::prelude::*;
use kernel::sizes::{SZ_16K, SZ_8K};
kernel::module_phy_driver! {
drivers: [PhyQT2025],
device_table: [
DeviceId::new_with_driver::<PhyQT2025>(),
],
name: "qt2025_phy",
author: "FUJITA Tomonori <fujita.tomonori@gmail.com>",
description: "AMCC QT2025 PHY driver",
license: "GPL",
firmware: ["qt2025-2.0.3.3.fw"],
}
struct PhyQT2025;
#[vtable]
impl Driver for PhyQT2025 {
const NAME: &'static CStr = c_str!("QT2025 10Gpbs SFP+");
const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x0043a400);
fn probe(dev: &mut phy::Device) -> Result<()> {
// Check the hardware revision code.
// Only 0x3b works with this driver and firmware.
let hw_rev = dev.read(C45::new(Mmd::PMAPMD, 0xd001))?;
if (hw_rev >> 8) != 0xb3 {
return Err(code::ENODEV);
}
// `MICRO_RESETN`: hold the micro-controller in reset while configuring.
dev.write(C45::new(Mmd::PMAPMD, 0xc300), 0x0000)?;
// `SREFCLK_FREQ`: configure clock frequency of the micro-controller.
dev.write(C45::new(Mmd::PMAPMD, 0xc302), 0x0004)?;
// Non loopback mode.
dev.write(C45::new(Mmd::PMAPMD, 0xc319), 0x0038)?;
// `CUS_LAN_WAN_CONFIG`: select between LAN and WAN (WIS) mode.
dev.write(C45::new(Mmd::PMAPMD, 0xc31a), 0x0098)?;
// The following writes use standardized registers (3.38 through
// 3.41 5/10/25GBASE-R PCS test pattern seed B) for something else.
// We don't know what.
dev.write(C45::new(Mmd::PCS, 0x0026), 0x0e00)?;
dev.write(C45::new(Mmd::PCS, 0x0027), 0x0893)?;
dev.write(C45::new(Mmd::PCS, 0x0028), 0xa528)?;
dev.write(C45::new(Mmd::PCS, 0x0029), 0x0003)?;
// Configure transmit and recovered clock.
dev.write(C45::new(Mmd::PMAPMD, 0xa30a), 0x06e1)?;
// `MICRO_RESETN`: release the micro-controller from the reset state.
dev.write(C45::new(Mmd::PMAPMD, 0xc300), 0x0002)?;
// The micro-controller will start running from the boot ROM.
dev.write(C45::new(Mmd::PCS, 0xe854), 0x00c0)?;
let fw = Firmware::request(c_str!("qt2025-2.0.3.3.fw"), dev.as_ref())?;
if fw.data().len() > SZ_16K + SZ_8K {
return Err(code::EFBIG);
}
// The 24kB of program memory space is accessible by MDIO.
// The first 16kB of memory is located in the address range 3.8000h - 3.BFFFh.
// The next 8kB of memory is located at 4.8000h - 4.9FFFh.
let mut dst_offset = 0;
let mut dst_mmd = Mmd::PCS;
for (src_idx, val) in fw.data().iter().enumerate() {
if src_idx == SZ_16K {
// Start writing to the next register with no offset
dst_offset = 0;
dst_mmd = Mmd::PHYXS;
}
dev.write(C45::new(dst_mmd, 0x8000 + dst_offset), (*val).into())?;
dst_offset += 1;
}
// The micro-controller will start running from SRAM.
dev.write(C45::new(Mmd::PCS, 0xe854), 0x0040)?;
// TODO: sleep here until the hw becomes ready.
Ok(())
}
fn read_status(dev: &mut phy::Device) -> Result<u16> {
dev.genphy_read_status::<C45>()
}
}
......@@ -43,6 +43,7 @@
pub mod page;
pub mod prelude;
pub mod print;
pub mod sizes;
mod static_assert;
#[doc(hidden)]
pub mod std_vendor;
......
......@@ -7,8 +7,9 @@
//! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
use crate::{error::*, prelude::*, types::Opaque};
use core::{marker::PhantomData, ptr::addr_of_mut};
use core::marker::PhantomData;
pub mod reg;
/// PHY state machine states.
///
......@@ -58,8 +59,9 @@ pub enum DuplexMode {
///
/// # Invariants
///
/// Referencing a `phy_device` using this struct asserts that you are in
/// - Referencing a `phy_device` using this struct asserts that you are in
/// a context where all methods defined on this struct are safe to call.
/// - This struct always has a valid `self.0.mdio.dev`.
///
/// [`struct phy_device`]: srctree/include/linux/phy.h
// During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
......@@ -76,9 +78,11 @@ impl Device {
///
/// # Safety
///
/// For the duration of 'a, the pointer must point at a valid `phy_device`,
/// and the caller must be in a context where all methods defined on this struct
/// For the duration of `'a`,
/// - the pointer must point at a valid `phy_device`, and the caller
/// must be in a context where all methods defined on this struct
/// are safe to call.
/// - `(*ptr).mdio.dev` must be a valid.
unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
// CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
let ptr = ptr.cast::<Self>();
......@@ -175,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<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::Register>(&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::Register>(&mut self, reg: R, val: u16) -> Result {
reg.write(self, val)
}
/// Reads a paged register.
......@@ -265,16 +252,8 @@ pub fn genphy_suspend(&mut self) -> Result {
}
/// Checks the link status and updates current link state.
pub fn genphy_read_status(&mut self) -> 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.
let ret = unsafe { bindings::genphy_read_status(phydev) };
if ret < 0 {
Err(Error::from_errno(ret))
} else {
Ok(ret as u16)
}
pub fn genphy_read_status<R: reg::Register>(&mut self) -> Result<u16> {
R::read_status(self)
}
/// Updates the link status.
......@@ -302,6 +281,14 @@ pub fn genphy_read_abilities(&mut self) -> Result {
}
}
impl AsRef<kernel::device::Device> for Device {
fn as_ref(&self) -> &kernel::device::Device {
let phydev = self.0.get();
// SAFETY: The struct invariant ensures that `mdio.dev` is valid.
unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
}
}
/// Defines certain other features this PHY supports (like interrupts).
///
/// These flag values are used in [`Driver::FLAGS`].
......@@ -338,6 +325,21 @@ impl<T: Driver> Adapter<T> {
})
}
/// # Safety
///
/// `phydev` must be passed by the corresponding callback in `phy_driver`.
unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> core::ffi::c_int {
from_result(|| {
// SAFETY: This callback is called only in contexts
// where we can exclusively access `phy_device` because
// it's not published yet, so the accessors on `Device` are okay
// to call.
let dev = unsafe { Device::from_raw(phydev) };
T::probe(dev)?;
Ok(0)
})
}
/// # Safety
///
/// `phydev` must be passed by the corresponding callback in `phy_driver`.
......@@ -511,6 +513,11 @@ pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
} else {
None
},
probe: if T::HAS_PROBE {
Some(Adapter::<T>::probe_callback)
} else {
None
},
get_features: if T::HAS_GET_FEATURES {
Some(Adapter::<T>::get_features_callback)
} else {
......@@ -583,6 +590,11 @@ fn soft_reset(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
}
/// Sets up device-specific structures during discovery.
fn probe(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
}
/// Probes the hardware to determine what abilities it has.
fn get_features(_dev: &mut Device) -> Result {
kernel::build_error(VTABLE_DEFAULT_ERROR)
......
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2024 FUJITA Tomonori <fujita.tomonori@gmail.com>
//! 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));
///
/// // Checks the link status as reported by registers in the C22 namespace
/// // and updates current link state.
/// dev.genphy_read_status::<phy::C22>();
/// // Checks the link status as reported by registers in the C45 namespace
/// // and updates current link state.
/// dev.genphy_read_status::<phy::C45>();
/// }
/// ```
pub trait Register: private::Sealed {
/// 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;
/// Checks the link status and updates current link state.
fn read_status(dev: &mut Device) -> Result<u16>;
}
/// A single MDIO clause 22 register address (5 bits).
#[derive(Copy, Clone, Debug)]
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<const N: u8>() -> 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<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())
};
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)
})
}
fn read_status(dev: &mut Device) -> Result<u16> {
let phydev = dev.0.get();
// SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
// So it's just an FFI call.
let ret = unsafe { bindings::genphy_read_status(phydev) };
to_result(ret)?;
Ok(ret as u16)
}
}
/// A single MDIO clause 45 register device and address.
#[derive(Copy, Clone, Debug)]
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<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()) };
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)
})
}
fn read_status(dev: &mut Device) -> Result<u16> {
let phydev = dev.0.get();
// SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
// So it's just an FFI call.
let ret = unsafe { bindings::genphy_c45_read_status(phydev) };
to_result(ret)?;
Ok(ret as u16)
}
}
// SPDX-License-Identifier: GPL-2.0
//! Commonly used sizes.
//!
//! C headers: [`include/linux/sizes.h`](srctree/include/linux/sizes.h).
/// 0x00000400
pub const SZ_1K: usize = bindings::SZ_1K as usize;
/// 0x00000800
pub const SZ_2K: usize = bindings::SZ_2K as usize;
/// 0x00001000
pub const SZ_4K: usize = bindings::SZ_4K as usize;
/// 0x00002000
pub const SZ_8K: usize = bindings::SZ_8K as usize;
/// 0x00004000
pub const SZ_16K: usize = bindings::SZ_16K as usize;
/// 0x00008000
pub const SZ_32K: usize = bindings::SZ_32K as usize;
/// 0x00010000
pub const SZ_64K: usize = bindings::SZ_64K as usize;
/// 0x00020000
pub const SZ_128K: usize = bindings::SZ_128K as usize;
/// 0x00040000
pub const SZ_256K: usize = bindings::SZ_256K as usize;
/// 0x00080000
pub const SZ_512K: usize = bindings::SZ_512K as usize;
......@@ -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>
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment