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

Configure Feed

Select the types of activity you want to include in your feed.

at v6.13-rc3 134 lines 4.0 kB view raw
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) 7use kernel::{ 8 c_str, 9 net::phy::{self, reg::C22, DeviceId, Driver}, 10 prelude::*, 11 uapi, 12}; 13 14kernel::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 27const BMCR_SPEED100: u16 = uapi::BMCR_SPEED100 as u16; 28const BMCR_FULLDPLX: u16 = uapi::BMCR_FULLDPLX as u16; 29 30// Performs a software PHY reset using the standard 31// BMCR_RESET bit and poll for the reset bit to be cleared. 32// Toggle BMCR_RESET bit off to accommodate broken AX8796B PHY implementation 33// such as used on the Individual Computers' X-Surf 100 Zorro card. 34fn asix_soft_reset(dev: &mut phy::Device) -> Result { 35 dev.write(C22::BMCR, 0)?; 36 dev.genphy_soft_reset() 37} 38 39struct PhyAX88772A; 40 41#[vtable] 42impl Driver for PhyAX88772A { 43 const FLAGS: u32 = phy::flags::IS_INTERNAL; 44 const NAME: &'static CStr = c_str!("Asix Electronics AX88772A"); 45 const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1861); 46 47 // AX88772A is not working properly with some old switches (NETGEAR EN 108TP): 48 // after autoneg is done and the link status is reported as active, the MII_LPA 49 // register is 0. This issue is not reproducible on AX88772C. 50 fn read_status(dev: &mut phy::Device) -> Result<u16> { 51 dev.genphy_update_link()?; 52 if !dev.is_link_up() { 53 return Ok(0); 54 } 55 // If MII_LPA is 0, phy_resolve_aneg_linkmode() will fail to resolve 56 // linkmode so use MII_BMCR as default values. 57 let ret = dev.read(C22::BMCR)?; 58 59 if ret & BMCR_SPEED100 != 0 { 60 dev.set_speed(uapi::SPEED_100); 61 } else { 62 dev.set_speed(uapi::SPEED_10); 63 } 64 65 let duplex = if ret & BMCR_FULLDPLX != 0 { 66 phy::DuplexMode::Full 67 } else { 68 phy::DuplexMode::Half 69 }; 70 dev.set_duplex(duplex); 71 72 dev.genphy_read_lpa()?; 73 74 if dev.is_autoneg_enabled() && dev.is_autoneg_completed() { 75 dev.resolve_aneg_linkmode(); 76 } 77 78 Ok(0) 79 } 80 81 fn suspend(dev: &mut phy::Device) -> Result { 82 dev.genphy_suspend() 83 } 84 85 fn resume(dev: &mut phy::Device) -> Result { 86 dev.genphy_resume() 87 } 88 89 fn soft_reset(dev: &mut phy::Device) -> Result { 90 asix_soft_reset(dev) 91 } 92 93 fn link_change_notify(dev: &mut phy::Device) { 94 // Reset PHY, otherwise MII_LPA will provide outdated information. 95 // This issue is reproducible only with some link partner PHYs. 96 if dev.state() == phy::DeviceState::NoLink { 97 let _ = dev.init_hw(); 98 let _ = dev.start_aneg(); 99 } 100 } 101} 102 103struct PhyAX88772C; 104 105#[vtable] 106impl Driver for PhyAX88772C { 107 const FLAGS: u32 = phy::flags::IS_INTERNAL; 108 const NAME: &'static CStr = c_str!("Asix Electronics AX88772C"); 109 const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_exact_mask(0x003b1881); 110 111 fn suspend(dev: &mut phy::Device) -> Result { 112 dev.genphy_suspend() 113 } 114 115 fn resume(dev: &mut phy::Device) -> Result { 116 dev.genphy_resume() 117 } 118 119 fn soft_reset(dev: &mut phy::Device) -> Result { 120 asix_soft_reset(dev) 121 } 122} 123 124struct PhyAX88796B; 125 126#[vtable] 127impl Driver for PhyAX88796B { 128 const NAME: &'static CStr = c_str!("Asix Electronics AX88796B"); 129 const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_model_mask(0x003b1841); 130 131 fn soft_reset(dev: &mut phy::Device) -> Result { 132 asix_soft_reset(dev) 133 } 134}