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