Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: phy: add Rust Asix PHY driver

This is the Rust implementation of drivers/net/phy/ax88796b.c. The
features are equivalent. You can choose C or Rust version kernel
configuration.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@gmail.com>
Reviewed-by: Trevor Gross <tmgross@umich.edu>
Reviewed-by: Benno Lossin <benno.lossin@proton.me>
Reviewed-by: Andrew Lunn <andrew@lunn.ch>
Reviewed-by: Alice Ryhl <aliceryhl@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

FUJITA Tomonori and committed by
David S. Miller
cbe0e415 cbaa28f9

+158 -1
+8
MAINTAINERS
··· 3072 3072 F: Documentation/devicetree/bindings/net/asix,ax88796c.yaml 3073 3073 F: drivers/net/ethernet/asix/ax88796c_* 3074 3074 3075 + ASIX PHY DRIVER [RUST] 3076 + M: FUJITA Tomonori <fujita.tomonori@gmail.com> 3077 + R: Trevor Gross <tmgross@umich.edu> 3078 + L: netdev@vger.kernel.org 3079 + L: rust-for-linux@vger.kernel.org 3080 + S: Maintained 3081 + F: drivers/net/phy/ax88796b_rust.rs 3082 + 3075 3083 ASPEED CRYPTO DRIVER 3076 3084 M: Neal Liu <neal_liu@aspeedtech.com> 3077 3085 L: linux-aspeed@lists.ozlabs.org (moderated for non-subscribers)
+8
drivers/net/phy/Kconfig
··· 112 112 Currently supports the Asix Electronics PHY found in the X-Surf 100 113 113 AX88796B package. 114 114 115 + config AX88796B_RUST_PHY 116 + bool "Rust reference driver for Asix PHYs" 117 + depends on RUST_PHYLIB_ABSTRACTIONS && AX88796B_PHY 118 + help 119 + Uses the Rust reference driver for Asix PHYs (ax88796b_rust.ko). 120 + The features are equivalent. It supports the Asix Electronics PHY 121 + found in the X-Surf 100 AX88796B package. 122 + 115 123 config BROADCOM_PHY 116 124 tristate "Broadcom 54XX PHYs" 117 125 select BCM_NET_PHYLIB
+5 -1
drivers/net/phy/Makefile
··· 37 37 obj-$(CONFIG_AMD_PHY) += amd.o 38 38 obj-$(CONFIG_AQUANTIA_PHY) += aquantia/ 39 39 obj-$(CONFIG_AT803X_PHY) += at803x.o 40 - obj-$(CONFIG_AX88796B_PHY) += ax88796b.o 40 + ifdef CONFIG_AX88796B_RUST_PHY 41 + obj-$(CONFIG_AX88796B_PHY) += ax88796b_rust.o 42 + else 43 + obj-$(CONFIG_AX88796B_PHY) += ax88796b.o 44 + endif 41 45 obj-$(CONFIG_BCM54140_PHY) += bcm54140.o 42 46 obj-$(CONFIG_BCM63XX_PHY) += bcm63xx.o 43 47 obj-$(CONFIG_BCM7XXX_PHY) += bcm7xxx.o
+135
drivers/net/phy/ax88796b_rust.rs
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + // Copyright (C) 2023 FUJITA Tomonori <fujita.tomonori@gmail.com> 3 + 4 + //! Rust Asix PHYs driver 5 + //! 6 + //! C version of this driver: [`drivers/net/phy/ax88796b.c`](./ax88796b.c) 7 + use kernel::{ 8 + c_str, 9 + net::phy::{self, DeviceId, Driver}, 10 + prelude::*, 11 + uapi, 12 + }; 13 + 14 + kernel::module_phy_driver! { 15 + drivers: [PhyAX88772A, PhyAX88772C, PhyAX88796B], 16 + device_table: [ 17 + DeviceId::new_with_driver::<PhyAX88772A>(), 18 + DeviceId::new_with_driver::<PhyAX88772C>(), 19 + DeviceId::new_with_driver::<PhyAX88796B>() 20 + ], 21 + name: "rust_asix_phy", 22 + author: "FUJITA Tomonori <fujita.tomonori@gmail.com>", 23 + description: "Rust Asix PHYs driver", 24 + license: "GPL", 25 + } 26 + 27 + const MII_BMCR: u16 = uapi::MII_BMCR as u16; 28 + const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16; 29 + const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16; 30 + 31 + // Performs a software PHY reset using the standard 32 + // BMCR_RESET bit and poll for the reset bit to be cleared. 33 + // Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation 34 + // such as used on the Individual Computers' X-Surf 100 Zorro card. 35 + fn asix_soft_reset(dev: &mut phy::Device) -> Result { 36 + dev.write(uapi::MII_BMCR as u16, 0)?; 37 + dev.genphy_soft_reset() 38 + } 39 + 40 + struct PhyAX88772A; 41 + 42 + #[vtable] 43 + impl Driver for PhyAX88772A { 44 + const FLAGS: u32 = phy::flags::IS_INTERNAL; 45 + const NAME: &'static CStr = c_str!("Asix Electronics AX88772A"); 46 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861); 47 + 48 + // AX88772A is not working properly with some old switches (NETGEAR EN 108TP): 49 + // after autoneg is done and the link status is reported as active, the MII_LPA 50 + // register is 0. This issue is not reproducible on AX88772C. 51 + fn read_status(dev: &mut phy::Device) -> Result<u16> { 52 + dev.genphy_update_link()?; 53 + if !dev.is_link_up() { 54 + return Ok(0); 55 + } 56 + // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve 57 + // linkmode so use MII_BMCR as default values. 58 + let ret = dev.read(MII_BMCR)?; 59 + 60 + if ret & BMCR_SPEED100 != 0 { 61 + dev.set_speed(uapi::SPEED_100); 62 + } else { 63 + dev.set_speed(uapi::SPEED_10); 64 + } 65 + 66 + let duplex = if ret & BMCR_FULLDPLX != 0 { 67 + phy::DuplexMode::Full 68 + } else { 69 + phy::DuplexMode::Half 70 + }; 71 + dev.set_duplex(duplex); 72 + 73 + dev.genphy_read_lpa()?; 74 + 75 + if dev.is_autoneg_enabled() && dev.is_autoneg_completed() { 76 + dev.resolve_aneg_linkmode(); 77 + } 78 + 79 + Ok(0) 80 + } 81 + 82 + fn suspend(dev: &mut phy::Device) -> Result { 83 + dev.genphy_suspend() 84 + } 85 + 86 + fn resume(dev: &mut phy::Device) -> Result { 87 + dev.genphy_resume() 88 + } 89 + 90 + fn soft_reset(dev: &mut phy::Device) -> Result { 91 + asix_soft_reset(dev) 92 + } 93 + 94 + fn link_change_notify(dev: &mut phy::Device) { 95 + // Reset PHY, otherwise MII_LPA will provide outdated information. 96 + // This issue is reproducible only with some link partner PHYs. 97 + if dev.state() == phy::DeviceState::NoLink { 98 + let _ = dev.init_hw(); 99 + let _ = dev.start_aneg(); 100 + } 101 + } 102 + } 103 + 104 + struct PhyAX88772C; 105 + 106 + #[vtable] 107 + impl Driver for PhyAX88772C { 108 + const FLAGS: u32 = phy::flags::IS_INTERNAL; 109 + const NAME: &'static CStr = c_str!("Asix Electronics AX88772C"); 110 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881); 111 + 112 + fn suspend(dev: &mut phy::Device) -> Result { 113 + dev.genphy_suspend() 114 + } 115 + 116 + fn resume(dev: &mut phy::Device) -> Result { 117 + dev.genphy_resume() 118 + } 119 + 120 + fn soft_reset(dev: &mut phy::Device) -> Result { 121 + asix_soft_reset(dev) 122 + } 123 + } 124 + 125 + struct PhyAX88796B; 126 + 127 + #[vtable] 128 + impl Driver for PhyAX88796B { 129 + const NAME: &'static CStr = c_str!("Asix Electronics AX88796B"); 130 + const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841); 131 + 132 + fn soft_reset(dev: &mut phy::Device) -> Result { 133 + asix_soft_reset(dev) 134 + } 135 + }
+2
rust/uapi/uapi_helper.h
··· 7 7 */ 8 8 9 9 #include <uapi/asm-generic/ioctl.h> 10 + #include <uapi/linux/mii.h> 11 + #include <uapi/linux/ethtool.h>