1f20fd544SFUJITA Tomonori // SPDX-License-Identifier: GPL-2.0
2f20fd544SFUJITA Tomonori
3f20fd544SFUJITA Tomonori // Copyright (C) 2023 FUJITA Tomonori <[email protected]>
4f20fd544SFUJITA Tomonori
5f20fd544SFUJITA Tomonori //! Network PHY device.
6f20fd544SFUJITA Tomonori //!
71d4046b5SFUJITA Tomonori //! C headers: [`include/linux/phy.h`](srctree/include/linux/phy.h).
8f20fd544SFUJITA Tomonori
900280272SMiguel Ojeda use crate::{error::*, prelude::*, types::Opaque};
107909892aSFUJITA Tomonori use core::{marker::PhantomData, ptr::addr_of_mut};
11f20fd544SFUJITA Tomonori
12b2e47002SFUJITA Tomonori pub mod reg;
13b2e47002SFUJITA Tomonori
14f20fd544SFUJITA Tomonori /// PHY state machine states.
15f20fd544SFUJITA Tomonori ///
16f20fd544SFUJITA Tomonori /// Corresponds to the kernel's [`enum phy_state`].
17f20fd544SFUJITA Tomonori ///
18f20fd544SFUJITA Tomonori /// Some of PHY drivers access to the state of PHY's software state machine.
19f20fd544SFUJITA Tomonori ///
201d4046b5SFUJITA Tomonori /// [`enum phy_state`]: srctree/include/linux/phy.h
21f20fd544SFUJITA Tomonori #[derive(PartialEq, Eq)]
22f20fd544SFUJITA Tomonori pub enum DeviceState {
23f20fd544SFUJITA Tomonori /// PHY device and driver are not ready for anything.
24f20fd544SFUJITA Tomonori Down,
25f20fd544SFUJITA Tomonori /// PHY is ready to send and receive packets.
26f20fd544SFUJITA Tomonori Ready,
27f20fd544SFUJITA Tomonori /// PHY is up, but no polling or interrupts are done.
28f20fd544SFUJITA Tomonori Halted,
29f20fd544SFUJITA Tomonori /// PHY is up, but is in an error state.
30f20fd544SFUJITA Tomonori Error,
31f20fd544SFUJITA Tomonori /// PHY and attached device are ready to do work.
32f20fd544SFUJITA Tomonori Up,
33f20fd544SFUJITA Tomonori /// PHY is currently running.
34f20fd544SFUJITA Tomonori Running,
35f20fd544SFUJITA Tomonori /// PHY is up, but not currently plugged in.
36f20fd544SFUJITA Tomonori NoLink,
37f20fd544SFUJITA Tomonori /// PHY is performing a cable test.
38f20fd544SFUJITA Tomonori CableTest,
39f20fd544SFUJITA Tomonori }
40f20fd544SFUJITA Tomonori
41f20fd544SFUJITA Tomonori /// A mode of Ethernet communication.
42f20fd544SFUJITA Tomonori ///
43f20fd544SFUJITA Tomonori /// PHY drivers get duplex information from hardware and update the current state.
44f20fd544SFUJITA Tomonori pub enum DuplexMode {
45f20fd544SFUJITA Tomonori /// PHY is in full-duplex mode.
46f20fd544SFUJITA Tomonori Full,
47f20fd544SFUJITA Tomonori /// PHY is in half-duplex mode.
48f20fd544SFUJITA Tomonori Half,
49f20fd544SFUJITA Tomonori /// PHY is in unknown duplex mode.
50f20fd544SFUJITA Tomonori Unknown,
51f20fd544SFUJITA Tomonori }
52f20fd544SFUJITA Tomonori
53f20fd544SFUJITA Tomonori /// An instance of a PHY device.
54f20fd544SFUJITA Tomonori ///
55f20fd544SFUJITA Tomonori /// Wraps the kernel's [`struct phy_device`].
56f20fd544SFUJITA Tomonori ///
57f20fd544SFUJITA Tomonori /// A [`Device`] instance is created when a callback in [`Driver`] is executed. A PHY driver
58f20fd544SFUJITA Tomonori /// executes [`Driver`]'s methods during the callback.
59f20fd544SFUJITA Tomonori ///
60f20fd544SFUJITA Tomonori /// # Invariants
61f20fd544SFUJITA Tomonori ///
627909892aSFUJITA Tomonori /// - Referencing a `phy_device` using this struct asserts that you are in
63f20fd544SFUJITA Tomonori /// a context where all methods defined on this struct are safe to call.
647909892aSFUJITA Tomonori /// - This struct always has a valid `self.0.mdio.dev`.
65f20fd544SFUJITA Tomonori ///
661d4046b5SFUJITA Tomonori /// [`struct phy_device`]: srctree/include/linux/phy.h
67f20fd544SFUJITA Tomonori // During the calls to most functions in [`Driver`], the C side (`PHYLIB`) holds a lock that is
68f20fd544SFUJITA Tomonori // unique for every instance of [`Device`]. `PHYLIB` uses a different serialization technique for
69f20fd544SFUJITA Tomonori // [`Driver::resume`] and [`Driver::suspend`]: `PHYLIB` updates `phy_device`'s state with
70f20fd544SFUJITA Tomonori // the lock held, thus guaranteeing that [`Driver::resume`] has exclusive access to the instance.
71f20fd544SFUJITA Tomonori // [`Driver::resume`] and [`Driver::suspend`] also are called where only one thread can access
72f20fd544SFUJITA Tomonori // to the instance.
73f20fd544SFUJITA Tomonori #[repr(transparent)]
74f20fd544SFUJITA Tomonori pub struct Device(Opaque<bindings::phy_device>);
75f20fd544SFUJITA Tomonori
76f20fd544SFUJITA Tomonori impl Device {
77f20fd544SFUJITA Tomonori /// Creates a new [`Device`] instance from a raw pointer.
78f20fd544SFUJITA Tomonori ///
79f20fd544SFUJITA Tomonori /// # Safety
80f20fd544SFUJITA Tomonori ///
817909892aSFUJITA Tomonori /// For the duration of `'a`,
827909892aSFUJITA Tomonori /// - the pointer must point at a valid `phy_device`, and the caller
837909892aSFUJITA Tomonori /// must be in a context where all methods defined on this struct
84f20fd544SFUJITA Tomonori /// are safe to call.
857909892aSFUJITA Tomonori /// - `(*ptr).mdio.dev` must be a valid.
from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self86f20fd544SFUJITA Tomonori unsafe fn from_raw<'a>(ptr: *mut bindings::phy_device) -> &'a mut Self {
87f20fd544SFUJITA Tomonori // CAST: `Self` is a `repr(transparent)` wrapper around `bindings::phy_device`.
88f20fd544SFUJITA Tomonori let ptr = ptr.cast::<Self>();
89f20fd544SFUJITA Tomonori // SAFETY: by the function requirements the pointer is valid and we have unique access for
90f20fd544SFUJITA Tomonori // the duration of `'a`.
91f20fd544SFUJITA Tomonori unsafe { &mut *ptr }
92f20fd544SFUJITA Tomonori }
93f20fd544SFUJITA Tomonori
94f20fd544SFUJITA Tomonori /// Gets the id of the PHY.
phy_id(&self) -> u3295f20fd544SFUJITA Tomonori pub fn phy_id(&self) -> u32 {
96f20fd544SFUJITA Tomonori let phydev = self.0.get();
97f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
98f20fd544SFUJITA Tomonori // this field without additional synchronization.
99f20fd544SFUJITA Tomonori unsafe { (*phydev).phy_id }
100f20fd544SFUJITA Tomonori }
101f20fd544SFUJITA Tomonori
102f20fd544SFUJITA Tomonori /// Gets the state of PHY state machine states.
state(&self) -> DeviceState103f20fd544SFUJITA Tomonori pub fn state(&self) -> DeviceState {
104f20fd544SFUJITA Tomonori let phydev = self.0.get();
105f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
106f20fd544SFUJITA Tomonori // this field without additional synchronization.
107f20fd544SFUJITA Tomonori let state = unsafe { (*phydev).state };
108f20fd544SFUJITA Tomonori // TODO: this conversion code will be replaced with automatically generated code by bindgen
109f20fd544SFUJITA Tomonori // when it becomes possible.
110f20fd544SFUJITA Tomonori match state {
111f20fd544SFUJITA Tomonori bindings::phy_state_PHY_DOWN => DeviceState::Down,
112f20fd544SFUJITA Tomonori bindings::phy_state_PHY_READY => DeviceState::Ready,
113f20fd544SFUJITA Tomonori bindings::phy_state_PHY_HALTED => DeviceState::Halted,
114f20fd544SFUJITA Tomonori bindings::phy_state_PHY_ERROR => DeviceState::Error,
115f20fd544SFUJITA Tomonori bindings::phy_state_PHY_UP => DeviceState::Up,
116f20fd544SFUJITA Tomonori bindings::phy_state_PHY_RUNNING => DeviceState::Running,
117f20fd544SFUJITA Tomonori bindings::phy_state_PHY_NOLINK => DeviceState::NoLink,
118f20fd544SFUJITA Tomonori bindings::phy_state_PHY_CABLETEST => DeviceState::CableTest,
119f20fd544SFUJITA Tomonori _ => DeviceState::Error,
120f20fd544SFUJITA Tomonori }
121f20fd544SFUJITA Tomonori }
122f20fd544SFUJITA Tomonori
123f20fd544SFUJITA Tomonori /// Gets the current link state.
124f20fd544SFUJITA Tomonori ///
125f20fd544SFUJITA Tomonori /// It returns true if the link is up.
is_link_up(&self) -> bool126f20fd544SFUJITA Tomonori pub fn is_link_up(&self) -> bool {
127f20fd544SFUJITA Tomonori const LINK_IS_UP: u64 = 1;
128f20fd544SFUJITA Tomonori // TODO: the code to access to the bit field will be replaced with automatically
129f20fd544SFUJITA Tomonori // generated code by bindgen when it becomes possible.
130f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
131f20fd544SFUJITA Tomonori // this field without additional synchronization.
132f20fd544SFUJITA Tomonori let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
133f20fd544SFUJITA Tomonori bit_field.get(14, 1) == LINK_IS_UP
134f20fd544SFUJITA Tomonori }
135f20fd544SFUJITA Tomonori
136f20fd544SFUJITA Tomonori /// Gets the current auto-negotiation configuration.
137f20fd544SFUJITA Tomonori ///
138f20fd544SFUJITA Tomonori /// It returns true if auto-negotiation is enabled.
is_autoneg_enabled(&self) -> bool139f20fd544SFUJITA Tomonori pub fn is_autoneg_enabled(&self) -> bool {
140f20fd544SFUJITA Tomonori // TODO: the code to access to the bit field will be replaced with automatically
141f20fd544SFUJITA Tomonori // generated code by bindgen when it becomes possible.
142f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
143f20fd544SFUJITA Tomonori // this field without additional synchronization.
144f20fd544SFUJITA Tomonori let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
145f20fd544SFUJITA Tomonori bit_field.get(13, 1) == bindings::AUTONEG_ENABLE as u64
146f20fd544SFUJITA Tomonori }
147f20fd544SFUJITA Tomonori
148f20fd544SFUJITA Tomonori /// Gets the current auto-negotiation state.
149f20fd544SFUJITA Tomonori ///
150f20fd544SFUJITA Tomonori /// It returns true if auto-negotiation is completed.
is_autoneg_completed(&self) -> bool151f20fd544SFUJITA Tomonori pub fn is_autoneg_completed(&self) -> bool {
152f20fd544SFUJITA Tomonori const AUTONEG_COMPLETED: u64 = 1;
153f20fd544SFUJITA Tomonori // TODO: the code to access to the bit field will be replaced with automatically
154f20fd544SFUJITA Tomonori // generated code by bindgen when it becomes possible.
155f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
156f20fd544SFUJITA Tomonori // this field without additional synchronization.
157f20fd544SFUJITA Tomonori let bit_field = unsafe { &(*self.0.get())._bitfield_1 };
158f20fd544SFUJITA Tomonori bit_field.get(15, 1) == AUTONEG_COMPLETED
159f20fd544SFUJITA Tomonori }
160f20fd544SFUJITA Tomonori
161f20fd544SFUJITA Tomonori /// Sets the speed of the PHY.
set_speed(&mut self, speed: u32)162f20fd544SFUJITA Tomonori pub fn set_speed(&mut self, speed: u32) {
163f20fd544SFUJITA Tomonori let phydev = self.0.get();
164f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
165f20fd544SFUJITA Tomonori // this field without additional synchronization.
166f20fd544SFUJITA Tomonori unsafe { (*phydev).speed = speed as i32 };
167f20fd544SFUJITA Tomonori }
168f20fd544SFUJITA Tomonori
169f20fd544SFUJITA Tomonori /// Sets duplex mode.
set_duplex(&mut self, mode: DuplexMode)170f20fd544SFUJITA Tomonori pub fn set_duplex(&mut self, mode: DuplexMode) {
171f20fd544SFUJITA Tomonori let phydev = self.0.get();
172f20fd544SFUJITA Tomonori let v = match mode {
173f20fd544SFUJITA Tomonori DuplexMode::Full => bindings::DUPLEX_FULL as i32,
174f20fd544SFUJITA Tomonori DuplexMode::Half => bindings::DUPLEX_HALF as i32,
175f20fd544SFUJITA Tomonori DuplexMode::Unknown => bindings::DUPLEX_UNKNOWN as i32,
176f20fd544SFUJITA Tomonori };
177f20fd544SFUJITA Tomonori // SAFETY: The struct invariant ensures that we may access
178f20fd544SFUJITA Tomonori // this field without additional synchronization.
179f20fd544SFUJITA Tomonori unsafe { (*phydev).duplex = v };
180f20fd544SFUJITA Tomonori }
181f20fd544SFUJITA Tomonori
182b2e47002SFUJITA Tomonori /// Reads a PHY register.
183f20fd544SFUJITA Tomonori // This function reads a hardware register and updates the stats so takes `&mut self`.
read<R: reg::Register>(&mut self, reg: R) -> Result<u16>184b2e47002SFUJITA Tomonori pub fn read<R: reg::Register>(&mut self, reg: R) -> Result<u16> {
185b2e47002SFUJITA Tomonori reg.read(self)
186f20fd544SFUJITA Tomonori }
187f20fd544SFUJITA Tomonori
188b2e47002SFUJITA Tomonori /// Writes a PHY register.
write<R: reg::Register>(&mut self, reg: R, val: u16) -> Result189b2e47002SFUJITA Tomonori pub fn write<R: reg::Register>(&mut self, reg: R, val: u16) -> Result {
190b2e47002SFUJITA Tomonori reg.write(self, val)
191f20fd544SFUJITA Tomonori }
192f20fd544SFUJITA Tomonori
193f20fd544SFUJITA Tomonori /// Reads a paged register.
read_paged(&mut self, page: u16, regnum: u16) -> Result<u16>194f20fd544SFUJITA Tomonori pub fn read_paged(&mut self, page: u16, regnum: u16) -> Result<u16> {
195f20fd544SFUJITA Tomonori let phydev = self.0.get();
196f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
197f20fd544SFUJITA Tomonori // So it's just an FFI call.
198f20fd544SFUJITA Tomonori let ret = unsafe { bindings::phy_read_paged(phydev, page.into(), regnum.into()) };
199f20fd544SFUJITA Tomonori if ret < 0 {
200f20fd544SFUJITA Tomonori Err(Error::from_errno(ret))
201f20fd544SFUJITA Tomonori } else {
202f20fd544SFUJITA Tomonori Ok(ret as u16)
203f20fd544SFUJITA Tomonori }
204f20fd544SFUJITA Tomonori }
205f20fd544SFUJITA Tomonori
206f20fd544SFUJITA Tomonori /// Resolves the advertisements into PHY settings.
resolve_aneg_linkmode(&mut self)207f20fd544SFUJITA Tomonori pub fn resolve_aneg_linkmode(&mut self) {
208f20fd544SFUJITA Tomonori let phydev = self.0.get();
209f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
210f20fd544SFUJITA Tomonori // So it's just an FFI call.
211f20fd544SFUJITA Tomonori unsafe { bindings::phy_resolve_aneg_linkmode(phydev) };
212f20fd544SFUJITA Tomonori }
213f20fd544SFUJITA Tomonori
214f20fd544SFUJITA Tomonori /// Executes software reset the PHY via `BMCR_RESET` bit.
genphy_soft_reset(&mut self) -> Result215f20fd544SFUJITA Tomonori pub fn genphy_soft_reset(&mut self) -> Result {
216f20fd544SFUJITA Tomonori let phydev = self.0.get();
217f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
218f20fd544SFUJITA Tomonori // So it's just an FFI call.
219f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_soft_reset(phydev) })
220f20fd544SFUJITA Tomonori }
221f20fd544SFUJITA Tomonori
222f20fd544SFUJITA Tomonori /// Initializes the PHY.
init_hw(&mut self) -> Result223f20fd544SFUJITA Tomonori pub fn init_hw(&mut self) -> Result {
224f20fd544SFUJITA Tomonori let phydev = self.0.get();
225f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
226f20fd544SFUJITA Tomonori // So it's just an FFI call.
227f20fd544SFUJITA Tomonori to_result(unsafe { bindings::phy_init_hw(phydev) })
228f20fd544SFUJITA Tomonori }
229f20fd544SFUJITA Tomonori
230f20fd544SFUJITA Tomonori /// Starts auto-negotiation.
start_aneg(&mut self) -> Result231f20fd544SFUJITA Tomonori pub fn start_aneg(&mut self) -> Result {
232f20fd544SFUJITA Tomonori let phydev = self.0.get();
233f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
234f20fd544SFUJITA Tomonori // So it's just an FFI call.
235f20fd544SFUJITA Tomonori to_result(unsafe { bindings::_phy_start_aneg(phydev) })
236f20fd544SFUJITA Tomonori }
237f20fd544SFUJITA Tomonori
238f20fd544SFUJITA Tomonori /// Resumes the PHY via `BMCR_PDOWN` bit.
genphy_resume(&mut self) -> Result239f20fd544SFUJITA Tomonori pub fn genphy_resume(&mut self) -> Result {
240f20fd544SFUJITA Tomonori let phydev = self.0.get();
241f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
242f20fd544SFUJITA Tomonori // So it's just an FFI call.
243f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_resume(phydev) })
244f20fd544SFUJITA Tomonori }
245f20fd544SFUJITA Tomonori
246f20fd544SFUJITA Tomonori /// Suspends the PHY via `BMCR_PDOWN` bit.
genphy_suspend(&mut self) -> Result247f20fd544SFUJITA Tomonori pub fn genphy_suspend(&mut self) -> Result {
248f20fd544SFUJITA Tomonori let phydev = self.0.get();
249f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
250f20fd544SFUJITA Tomonori // So it's just an FFI call.
251f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_suspend(phydev) })
252f20fd544SFUJITA Tomonori }
253f20fd544SFUJITA Tomonori
254f20fd544SFUJITA Tomonori /// Checks the link status and updates current link state.
genphy_read_status<R: reg::Register>(&mut self) -> Result<u16>2555114e05aSFUJITA Tomonori pub fn genphy_read_status<R: reg::Register>(&mut self) -> Result<u16> {
2565114e05aSFUJITA Tomonori R::read_status(self)
257f20fd544SFUJITA Tomonori }
258f20fd544SFUJITA Tomonori
259f20fd544SFUJITA Tomonori /// Updates the link status.
genphy_update_link(&mut self) -> Result260f20fd544SFUJITA Tomonori pub fn genphy_update_link(&mut self) -> Result {
261f20fd544SFUJITA Tomonori let phydev = self.0.get();
262f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
263f20fd544SFUJITA Tomonori // So it's just an FFI call.
264f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_update_link(phydev) })
265f20fd544SFUJITA Tomonori }
266f20fd544SFUJITA Tomonori
267f20fd544SFUJITA Tomonori /// Reads link partner ability.
genphy_read_lpa(&mut self) -> Result268f20fd544SFUJITA Tomonori pub fn genphy_read_lpa(&mut self) -> Result {
269f20fd544SFUJITA Tomonori let phydev = self.0.get();
270f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
271f20fd544SFUJITA Tomonori // So it's just an FFI call.
272f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_read_lpa(phydev) })
273f20fd544SFUJITA Tomonori }
274f20fd544SFUJITA Tomonori
275f20fd544SFUJITA Tomonori /// Reads PHY abilities.
genphy_read_abilities(&mut self) -> Result276f20fd544SFUJITA Tomonori pub fn genphy_read_abilities(&mut self) -> Result {
277f20fd544SFUJITA Tomonori let phydev = self.0.get();
278f20fd544SFUJITA Tomonori // SAFETY: `phydev` is pointing to a valid object by the type invariant of `Self`.
279f20fd544SFUJITA Tomonori // So it's just an FFI call.
280f20fd544SFUJITA Tomonori to_result(unsafe { bindings::genphy_read_abilities(phydev) })
281f20fd544SFUJITA Tomonori }
282f20fd544SFUJITA Tomonori }
283f20fd544SFUJITA Tomonori
2847909892aSFUJITA Tomonori impl AsRef<kernel::device::Device> for Device {
as_ref(&self) -> &kernel::device::Device2857909892aSFUJITA Tomonori fn as_ref(&self) -> &kernel::device::Device {
2867909892aSFUJITA Tomonori let phydev = self.0.get();
2877909892aSFUJITA Tomonori // SAFETY: The struct invariant ensures that `mdio.dev` is valid.
2887909892aSFUJITA Tomonori unsafe { kernel::device::Device::as_ref(addr_of_mut!((*phydev).mdio.dev)) }
2897909892aSFUJITA Tomonori }
2907909892aSFUJITA Tomonori }
2917909892aSFUJITA Tomonori
292f20fd544SFUJITA Tomonori /// Defines certain other features this PHY supports (like interrupts).
293f20fd544SFUJITA Tomonori ///
294f20fd544SFUJITA Tomonori /// These flag values are used in [`Driver::FLAGS`].
295f20fd544SFUJITA Tomonori pub mod flags {
296f20fd544SFUJITA Tomonori /// PHY is internal.
297f20fd544SFUJITA Tomonori pub const IS_INTERNAL: u32 = bindings::PHY_IS_INTERNAL;
298f20fd544SFUJITA Tomonori /// PHY needs to be reset after the refclk is enabled.
299f20fd544SFUJITA Tomonori pub const RST_AFTER_CLK_EN: u32 = bindings::PHY_RST_AFTER_CLK_EN;
300f20fd544SFUJITA Tomonori /// Polling is used to detect PHY status changes.
301f20fd544SFUJITA Tomonori pub const POLL_CABLE_TEST: u32 = bindings::PHY_POLL_CABLE_TEST;
302f20fd544SFUJITA Tomonori /// Don't suspend.
303f20fd544SFUJITA Tomonori pub const ALWAYS_CALL_SUSPEND: u32 = bindings::PHY_ALWAYS_CALL_SUSPEND;
304f20fd544SFUJITA Tomonori }
305f20fd544SFUJITA Tomonori
306f20fd544SFUJITA Tomonori /// An adapter for the registration of a PHY driver.
307f20fd544SFUJITA Tomonori struct Adapter<T: Driver> {
308f20fd544SFUJITA Tomonori _p: PhantomData<T>,
309f20fd544SFUJITA Tomonori }
310f20fd544SFUJITA Tomonori
311f20fd544SFUJITA Tomonori impl<T: Driver> Adapter<T> {
312f20fd544SFUJITA Tomonori /// # Safety
313f20fd544SFUJITA Tomonori ///
314f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
soft_reset_callback( phydev: *mut bindings::phy_device, ) -> crate::ffi::c_int315f20fd544SFUJITA Tomonori unsafe extern "C" fn soft_reset_callback(
316f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
317d072acdaSGary Guo ) -> crate::ffi::c_int {
318f20fd544SFUJITA Tomonori from_result(|| {
319f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
320f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
321f20fd544SFUJITA Tomonori // `Device` are okay to call.
322f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
323f20fd544SFUJITA Tomonori T::soft_reset(dev)?;
324f20fd544SFUJITA Tomonori Ok(0)
325f20fd544SFUJITA Tomonori })
326f20fd544SFUJITA Tomonori }
327f20fd544SFUJITA Tomonori
328f20fd544SFUJITA Tomonori /// # Safety
329f20fd544SFUJITA Tomonori ///
330f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
probe_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int331d072acdaSGary Guo unsafe extern "C" fn probe_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int {
332ffd2747dSFUJITA Tomonori from_result(|| {
333ffd2747dSFUJITA Tomonori // SAFETY: This callback is called only in contexts
334ffd2747dSFUJITA Tomonori // where we can exclusively access `phy_device` because
335ffd2747dSFUJITA Tomonori // it's not published yet, so the accessors on `Device` are okay
336ffd2747dSFUJITA Tomonori // to call.
337ffd2747dSFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
338ffd2747dSFUJITA Tomonori T::probe(dev)?;
339ffd2747dSFUJITA Tomonori Ok(0)
340ffd2747dSFUJITA Tomonori })
341ffd2747dSFUJITA Tomonori }
342ffd2747dSFUJITA Tomonori
343ffd2747dSFUJITA Tomonori /// # Safety
344ffd2747dSFUJITA Tomonori ///
345ffd2747dSFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
get_features_callback( phydev: *mut bindings::phy_device, ) -> crate::ffi::c_int346f20fd544SFUJITA Tomonori unsafe extern "C" fn get_features_callback(
347f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
348d072acdaSGary Guo ) -> crate::ffi::c_int {
349f20fd544SFUJITA Tomonori from_result(|| {
350f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
351f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
352f20fd544SFUJITA Tomonori // `Device` are okay to call.
353f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
354f20fd544SFUJITA Tomonori T::get_features(dev)?;
355f20fd544SFUJITA Tomonori Ok(0)
356f20fd544SFUJITA Tomonori })
357f20fd544SFUJITA Tomonori }
358f20fd544SFUJITA Tomonori
359f20fd544SFUJITA Tomonori /// # Safety
360f20fd544SFUJITA Tomonori ///
361f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
suspend_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int362d072acdaSGary Guo unsafe extern "C" fn suspend_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int {
363f20fd544SFUJITA Tomonori from_result(|| {
364f20fd544SFUJITA Tomonori // SAFETY: The C core code ensures that the accessors on
365f20fd544SFUJITA Tomonori // `Device` are okay to call even though `phy_device->lock`
366f20fd544SFUJITA Tomonori // might not be held.
367f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
368f20fd544SFUJITA Tomonori T::suspend(dev)?;
369f20fd544SFUJITA Tomonori Ok(0)
370f20fd544SFUJITA Tomonori })
371f20fd544SFUJITA Tomonori }
372f20fd544SFUJITA Tomonori
373f20fd544SFUJITA Tomonori /// # Safety
374f20fd544SFUJITA Tomonori ///
375f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
resume_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int376d072acdaSGary Guo unsafe extern "C" fn resume_callback(phydev: *mut bindings::phy_device) -> crate::ffi::c_int {
377f20fd544SFUJITA Tomonori from_result(|| {
378f20fd544SFUJITA Tomonori // SAFETY: The C core code ensures that the accessors on
379f20fd544SFUJITA Tomonori // `Device` are okay to call even though `phy_device->lock`
380f20fd544SFUJITA Tomonori // might not be held.
381f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
382f20fd544SFUJITA Tomonori T::resume(dev)?;
383f20fd544SFUJITA Tomonori Ok(0)
384f20fd544SFUJITA Tomonori })
385f20fd544SFUJITA Tomonori }
386f20fd544SFUJITA Tomonori
387f20fd544SFUJITA Tomonori /// # Safety
388f20fd544SFUJITA Tomonori ///
389f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
config_aneg_callback( phydev: *mut bindings::phy_device, ) -> crate::ffi::c_int390f20fd544SFUJITA Tomonori unsafe extern "C" fn config_aneg_callback(
391f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
392d072acdaSGary Guo ) -> crate::ffi::c_int {
393f20fd544SFUJITA Tomonori from_result(|| {
394f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
395f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
396f20fd544SFUJITA Tomonori // `Device` are okay to call.
397f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
398f20fd544SFUJITA Tomonori T::config_aneg(dev)?;
399f20fd544SFUJITA Tomonori Ok(0)
400f20fd544SFUJITA Tomonori })
401f20fd544SFUJITA Tomonori }
402f20fd544SFUJITA Tomonori
403f20fd544SFUJITA Tomonori /// # Safety
404f20fd544SFUJITA Tomonori ///
405f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
read_status_callback( phydev: *mut bindings::phy_device, ) -> crate::ffi::c_int406f20fd544SFUJITA Tomonori unsafe extern "C" fn read_status_callback(
407f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
408d072acdaSGary Guo ) -> crate::ffi::c_int {
409f20fd544SFUJITA Tomonori from_result(|| {
410f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
411f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
412f20fd544SFUJITA Tomonori // `Device` are okay to call.
413f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
414f20fd544SFUJITA Tomonori T::read_status(dev)?;
415f20fd544SFUJITA Tomonori Ok(0)
416f20fd544SFUJITA Tomonori })
417f20fd544SFUJITA Tomonori }
418f20fd544SFUJITA Tomonori
419f20fd544SFUJITA Tomonori /// # Safety
420f20fd544SFUJITA Tomonori ///
421f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
match_phy_device_callback( phydev: *mut bindings::phy_device, ) -> crate::ffi::c_int422f20fd544SFUJITA Tomonori unsafe extern "C" fn match_phy_device_callback(
423f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
424d072acdaSGary Guo ) -> crate::ffi::c_int {
425f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
426f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
427f20fd544SFUJITA Tomonori // `Device` are okay to call.
428f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
429f20fd544SFUJITA Tomonori T::match_phy_device(dev) as i32
430f20fd544SFUJITA Tomonori }
431f20fd544SFUJITA Tomonori
432f20fd544SFUJITA Tomonori /// # Safety
433f20fd544SFUJITA Tomonori ///
434f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
read_mmd_callback( phydev: *mut bindings::phy_device, devnum: i32, regnum: u16, ) -> i32435f20fd544SFUJITA Tomonori unsafe extern "C" fn read_mmd_callback(
436f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
437f20fd544SFUJITA Tomonori devnum: i32,
438f20fd544SFUJITA Tomonori regnum: u16,
439f20fd544SFUJITA Tomonori ) -> i32 {
440f20fd544SFUJITA Tomonori from_result(|| {
441f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
442f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
443f20fd544SFUJITA Tomonori // `Device` are okay to call.
444f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
445f20fd544SFUJITA Tomonori // CAST: the C side verifies devnum < 32.
446f20fd544SFUJITA Tomonori let ret = T::read_mmd(dev, devnum as u8, regnum)?;
447f20fd544SFUJITA Tomonori Ok(ret.into())
448f20fd544SFUJITA Tomonori })
449f20fd544SFUJITA Tomonori }
450f20fd544SFUJITA Tomonori
451f20fd544SFUJITA Tomonori /// # Safety
452f20fd544SFUJITA Tomonori ///
453f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
write_mmd_callback( phydev: *mut bindings::phy_device, devnum: i32, regnum: u16, val: u16, ) -> i32454f20fd544SFUJITA Tomonori unsafe extern "C" fn write_mmd_callback(
455f20fd544SFUJITA Tomonori phydev: *mut bindings::phy_device,
456f20fd544SFUJITA Tomonori devnum: i32,
457f20fd544SFUJITA Tomonori regnum: u16,
458f20fd544SFUJITA Tomonori val: u16,
459f20fd544SFUJITA Tomonori ) -> i32 {
460f20fd544SFUJITA Tomonori from_result(|| {
461f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
462f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
463f20fd544SFUJITA Tomonori // `Device` are okay to call.
464f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
465f20fd544SFUJITA Tomonori T::write_mmd(dev, devnum as u8, regnum, val)?;
466f20fd544SFUJITA Tomonori Ok(0)
467f20fd544SFUJITA Tomonori })
468f20fd544SFUJITA Tomonori }
469f20fd544SFUJITA Tomonori
470f20fd544SFUJITA Tomonori /// # Safety
471f20fd544SFUJITA Tomonori ///
472f20fd544SFUJITA Tomonori /// `phydev` must be passed by the corresponding callback in `phy_driver`.
link_change_notify_callback(phydev: *mut bindings::phy_device)473f20fd544SFUJITA Tomonori unsafe extern "C" fn link_change_notify_callback(phydev: *mut bindings::phy_device) {
474f20fd544SFUJITA Tomonori // SAFETY: This callback is called only in contexts
475f20fd544SFUJITA Tomonori // where we hold `phy_device->lock`, so the accessors on
476f20fd544SFUJITA Tomonori // `Device` are okay to call.
477f20fd544SFUJITA Tomonori let dev = unsafe { Device::from_raw(phydev) };
478f20fd544SFUJITA Tomonori T::link_change_notify(dev);
479f20fd544SFUJITA Tomonori }
480f20fd544SFUJITA Tomonori }
481f20fd544SFUJITA Tomonori
482f20fd544SFUJITA Tomonori /// Driver structure for a particular PHY type.
483f20fd544SFUJITA Tomonori ///
484f20fd544SFUJITA Tomonori /// Wraps the kernel's [`struct phy_driver`].
485f20fd544SFUJITA Tomonori /// This is used to register a driver for a particular PHY type with the kernel.
486f20fd544SFUJITA Tomonori ///
487f20fd544SFUJITA Tomonori /// # Invariants
488f20fd544SFUJITA Tomonori ///
489f20fd544SFUJITA Tomonori /// `self.0` is always in a valid state.
490f20fd544SFUJITA Tomonori ///
4911d4046b5SFUJITA Tomonori /// [`struct phy_driver`]: srctree/include/linux/phy.h
492f20fd544SFUJITA Tomonori #[repr(transparent)]
493f20fd544SFUJITA Tomonori pub struct DriverVTable(Opaque<bindings::phy_driver>);
494f20fd544SFUJITA Tomonori
495f20fd544SFUJITA Tomonori // SAFETY: `DriverVTable` doesn't expose any &self method to access internal data, so it's safe to
4960ff8f3f0SMichael Vetter // share `&DriverVTable` across execution context boundaries.
497f20fd544SFUJITA Tomonori unsafe impl Sync for DriverVTable {}
498f20fd544SFUJITA Tomonori
499f20fd544SFUJITA Tomonori /// Creates a [`DriverVTable`] instance from [`Driver`].
500f20fd544SFUJITA Tomonori ///
501f20fd544SFUJITA Tomonori /// This is used by [`module_phy_driver`] macro to create a static array of `phy_driver`.
502f20fd544SFUJITA Tomonori ///
503f20fd544SFUJITA Tomonori /// [`module_phy_driver`]: crate::module_phy_driver
create_phy_driver<T: Driver>() -> DriverVTable504f20fd544SFUJITA Tomonori pub const fn create_phy_driver<T: Driver>() -> DriverVTable {
505f20fd544SFUJITA Tomonori // INVARIANT: All the fields of `struct phy_driver` are initialized properly.
506f20fd544SFUJITA Tomonori DriverVTable(Opaque::new(bindings::phy_driver {
507f20fd544SFUJITA Tomonori name: T::NAME.as_char_ptr().cast_mut(),
508f20fd544SFUJITA Tomonori flags: T::FLAGS,
509f20fd544SFUJITA Tomonori phy_id: T::PHY_DEVICE_ID.id,
510f20fd544SFUJITA Tomonori phy_id_mask: T::PHY_DEVICE_ID.mask_as_int(),
511f20fd544SFUJITA Tomonori soft_reset: if T::HAS_SOFT_RESET {
512f20fd544SFUJITA Tomonori Some(Adapter::<T>::soft_reset_callback)
513f20fd544SFUJITA Tomonori } else {
514f20fd544SFUJITA Tomonori None
515f20fd544SFUJITA Tomonori },
516ffd2747dSFUJITA Tomonori probe: if T::HAS_PROBE {
517ffd2747dSFUJITA Tomonori Some(Adapter::<T>::probe_callback)
518ffd2747dSFUJITA Tomonori } else {
519ffd2747dSFUJITA Tomonori None
520ffd2747dSFUJITA Tomonori },
521f20fd544SFUJITA Tomonori get_features: if T::HAS_GET_FEATURES {
522f20fd544SFUJITA Tomonori Some(Adapter::<T>::get_features_callback)
523f20fd544SFUJITA Tomonori } else {
524f20fd544SFUJITA Tomonori None
525f20fd544SFUJITA Tomonori },
526f20fd544SFUJITA Tomonori match_phy_device: if T::HAS_MATCH_PHY_DEVICE {
527f20fd544SFUJITA Tomonori Some(Adapter::<T>::match_phy_device_callback)
528f20fd544SFUJITA Tomonori } else {
529f20fd544SFUJITA Tomonori None
530f20fd544SFUJITA Tomonori },
531f20fd544SFUJITA Tomonori suspend: if T::HAS_SUSPEND {
532f20fd544SFUJITA Tomonori Some(Adapter::<T>::suspend_callback)
533f20fd544SFUJITA Tomonori } else {
534f20fd544SFUJITA Tomonori None
535f20fd544SFUJITA Tomonori },
536f20fd544SFUJITA Tomonori resume: if T::HAS_RESUME {
537f20fd544SFUJITA Tomonori Some(Adapter::<T>::resume_callback)
538f20fd544SFUJITA Tomonori } else {
539f20fd544SFUJITA Tomonori None
540f20fd544SFUJITA Tomonori },
541f20fd544SFUJITA Tomonori config_aneg: if T::HAS_CONFIG_ANEG {
542f20fd544SFUJITA Tomonori Some(Adapter::<T>::config_aneg_callback)
543f20fd544SFUJITA Tomonori } else {
544f20fd544SFUJITA Tomonori None
545f20fd544SFUJITA Tomonori },
546f20fd544SFUJITA Tomonori read_status: if T::HAS_READ_STATUS {
547f20fd544SFUJITA Tomonori Some(Adapter::<T>::read_status_callback)
548f20fd544SFUJITA Tomonori } else {
549f20fd544SFUJITA Tomonori None
550f20fd544SFUJITA Tomonori },
551f20fd544SFUJITA Tomonori read_mmd: if T::HAS_READ_MMD {
552f20fd544SFUJITA Tomonori Some(Adapter::<T>::read_mmd_callback)
553f20fd544SFUJITA Tomonori } else {
554f20fd544SFUJITA Tomonori None
555f20fd544SFUJITA Tomonori },
556f20fd544SFUJITA Tomonori write_mmd: if T::HAS_WRITE_MMD {
557f20fd544SFUJITA Tomonori Some(Adapter::<T>::write_mmd_callback)
558f20fd544SFUJITA Tomonori } else {
559f20fd544SFUJITA Tomonori None
560f20fd544SFUJITA Tomonori },
561f20fd544SFUJITA Tomonori link_change_notify: if T::HAS_LINK_CHANGE_NOTIFY {
562f20fd544SFUJITA Tomonori Some(Adapter::<T>::link_change_notify_callback)
563f20fd544SFUJITA Tomonori } else {
564f20fd544SFUJITA Tomonori None
565f20fd544SFUJITA Tomonori },
566f20fd544SFUJITA Tomonori // SAFETY: The rest is zeroed out to initialize `struct phy_driver`,
567f20fd544SFUJITA Tomonori // sets `Option<&F>` to be `None`.
568f20fd544SFUJITA Tomonori ..unsafe { core::mem::MaybeUninit::<bindings::phy_driver>::zeroed().assume_init() }
569f20fd544SFUJITA Tomonori }))
570f20fd544SFUJITA Tomonori }
571f20fd544SFUJITA Tomonori
572f20fd544SFUJITA Tomonori /// Driver implementation for a particular PHY type.
573f20fd544SFUJITA Tomonori ///
574f20fd544SFUJITA Tomonori /// This trait is used to create a [`DriverVTable`].
575f20fd544SFUJITA Tomonori #[vtable]
576f20fd544SFUJITA Tomonori pub trait Driver {
577f20fd544SFUJITA Tomonori /// Defines certain other features this PHY supports.
578f20fd544SFUJITA Tomonori /// It is a combination of the flags in the [`flags`] module.
579f20fd544SFUJITA Tomonori const FLAGS: u32 = 0;
580f20fd544SFUJITA Tomonori
581f20fd544SFUJITA Tomonori /// The friendly name of this PHY type.
582f20fd544SFUJITA Tomonori const NAME: &'static CStr;
583f20fd544SFUJITA Tomonori
584f20fd544SFUJITA Tomonori /// This driver only works for PHYs with IDs which match this field.
585f20fd544SFUJITA Tomonori /// The default id and mask are zero.
586f20fd544SFUJITA Tomonori const PHY_DEVICE_ID: DeviceId = DeviceId::new_with_custom_mask(0, 0);
587f20fd544SFUJITA Tomonori
588f20fd544SFUJITA Tomonori /// Issues a PHY software reset.
soft_reset(_dev: &mut Device) -> Result589f20fd544SFUJITA Tomonori fn soft_reset(_dev: &mut Device) -> Result {
5904401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
591f20fd544SFUJITA Tomonori }
592f20fd544SFUJITA Tomonori
593ffd2747dSFUJITA Tomonori /// Sets up device-specific structures during discovery.
probe(_dev: &mut Device) -> Result594ffd2747dSFUJITA Tomonori fn probe(_dev: &mut Device) -> Result {
5954401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
596ffd2747dSFUJITA Tomonori }
597ffd2747dSFUJITA Tomonori
598f20fd544SFUJITA Tomonori /// Probes the hardware to determine what abilities it has.
get_features(_dev: &mut Device) -> Result599f20fd544SFUJITA Tomonori fn get_features(_dev: &mut Device) -> Result {
6004401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
601f20fd544SFUJITA Tomonori }
602f20fd544SFUJITA Tomonori
603f20fd544SFUJITA Tomonori /// Returns true if this is a suitable driver for the given phydev.
604f20fd544SFUJITA Tomonori /// If not implemented, matching is based on [`Driver::PHY_DEVICE_ID`].
match_phy_device(_dev: &Device) -> bool605f20fd544SFUJITA Tomonori fn match_phy_device(_dev: &Device) -> bool {
606f20fd544SFUJITA Tomonori false
607f20fd544SFUJITA Tomonori }
608f20fd544SFUJITA Tomonori
609f20fd544SFUJITA Tomonori /// Configures the advertisement and resets auto-negotiation
610f20fd544SFUJITA Tomonori /// if auto-negotiation is enabled.
config_aneg(_dev: &mut Device) -> Result611f20fd544SFUJITA Tomonori fn config_aneg(_dev: &mut Device) -> Result {
6124401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
613f20fd544SFUJITA Tomonori }
614f20fd544SFUJITA Tomonori
615f20fd544SFUJITA Tomonori /// Determines the negotiated speed and duplex.
read_status(_dev: &mut Device) -> Result<u16>616f20fd544SFUJITA Tomonori fn read_status(_dev: &mut Device) -> Result<u16> {
6174401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
618f20fd544SFUJITA Tomonori }
619f20fd544SFUJITA Tomonori
620f20fd544SFUJITA Tomonori /// Suspends the hardware, saving state if needed.
suspend(_dev: &mut Device) -> Result621f20fd544SFUJITA Tomonori fn suspend(_dev: &mut Device) -> Result {
6224401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
623f20fd544SFUJITA Tomonori }
624f20fd544SFUJITA Tomonori
625f20fd544SFUJITA Tomonori /// Resumes the hardware, restoring state if needed.
resume(_dev: &mut Device) -> Result626f20fd544SFUJITA Tomonori fn resume(_dev: &mut Device) -> Result {
6274401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
628f20fd544SFUJITA Tomonori }
629f20fd544SFUJITA Tomonori
630f20fd544SFUJITA Tomonori /// Overrides the default MMD read function for reading a MMD register.
read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16>631f20fd544SFUJITA Tomonori fn read_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16) -> Result<u16> {
6324401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
633f20fd544SFUJITA Tomonori }
634f20fd544SFUJITA Tomonori
635f20fd544SFUJITA Tomonori /// Overrides the default MMD write function for writing a MMD register.
write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result636f20fd544SFUJITA Tomonori fn write_mmd(_dev: &mut Device, _devnum: u8, _regnum: u16, _val: u16) -> Result {
6374401565fSMiguel Ojeda build_error!(VTABLE_DEFAULT_ERROR)
638f20fd544SFUJITA Tomonori }
639f20fd544SFUJITA Tomonori
640f20fd544SFUJITA Tomonori /// Callback for notification of link change.
link_change_notify(_dev: &mut Device)641f20fd544SFUJITA Tomonori fn link_change_notify(_dev: &mut Device) {}
642f20fd544SFUJITA Tomonori }
643f20fd544SFUJITA Tomonori
644f20fd544SFUJITA Tomonori /// Registration structure for PHY drivers.
645f20fd544SFUJITA Tomonori ///
646f20fd544SFUJITA Tomonori /// Registers [`DriverVTable`] instances with the kernel. They will be unregistered when dropped.
647f20fd544SFUJITA Tomonori ///
648f20fd544SFUJITA Tomonori /// # Invariants
649f20fd544SFUJITA Tomonori ///
650f20fd544SFUJITA Tomonori /// The `drivers` slice are currently registered to the kernel via `phy_drivers_register`.
651f20fd544SFUJITA Tomonori pub struct Registration {
652f20fd544SFUJITA Tomonori drivers: Pin<&'static mut [DriverVTable]>,
653f20fd544SFUJITA Tomonori }
654f20fd544SFUJITA Tomonori
655df70d04dSWedson Almeida Filho // SAFETY: The only action allowed in a `Registration` instance is dropping it, which is safe to do
656df70d04dSWedson Almeida Filho // from any thread because `phy_drivers_unregister` can be called from any thread context.
657df70d04dSWedson Almeida Filho unsafe impl Send for Registration {}
658df70d04dSWedson Almeida Filho
659f20fd544SFUJITA Tomonori impl Registration {
660f20fd544SFUJITA Tomonori /// Registers a PHY driver.
register( module: &'static crate::ThisModule, drivers: Pin<&'static mut [DriverVTable]>, ) -> Result<Self>661f20fd544SFUJITA Tomonori pub fn register(
662f20fd544SFUJITA Tomonori module: &'static crate::ThisModule,
663f20fd544SFUJITA Tomonori drivers: Pin<&'static mut [DriverVTable]>,
664f20fd544SFUJITA Tomonori ) -> Result<Self> {
665f20fd544SFUJITA Tomonori if drivers.is_empty() {
666f20fd544SFUJITA Tomonori return Err(code::EINVAL);
667f20fd544SFUJITA Tomonori }
668f20fd544SFUJITA Tomonori // SAFETY: The type invariants of [`DriverVTable`] ensure that all elements of
669f20fd544SFUJITA Tomonori // the `drivers` slice are initialized properly. `drivers` will not be moved.
670f20fd544SFUJITA Tomonori // So it's just an FFI call.
671f20fd544SFUJITA Tomonori to_result(unsafe {
672f20fd544SFUJITA Tomonori bindings::phy_drivers_register(drivers[0].0.get(), drivers.len().try_into()?, module.0)
673f20fd544SFUJITA Tomonori })?;
674f20fd544SFUJITA Tomonori // INVARIANT: The `drivers` slice is successfully registered to the kernel via `phy_drivers_register`.
675f20fd544SFUJITA Tomonori Ok(Registration { drivers })
676f20fd544SFUJITA Tomonori }
677f20fd544SFUJITA Tomonori }
678f20fd544SFUJITA Tomonori
679f20fd544SFUJITA Tomonori impl Drop for Registration {
drop(&mut self)680f20fd544SFUJITA Tomonori fn drop(&mut self) {
681f20fd544SFUJITA Tomonori // SAFETY: The type invariants guarantee that `self.drivers` is valid.
682f20fd544SFUJITA Tomonori // So it's just an FFI call.
683f20fd544SFUJITA Tomonori unsafe {
684f20fd544SFUJITA Tomonori bindings::phy_drivers_unregister(self.drivers[0].0.get(), self.drivers.len() as i32)
685f20fd544SFUJITA Tomonori };
686f20fd544SFUJITA Tomonori }
687f20fd544SFUJITA Tomonori }
688f20fd544SFUJITA Tomonori
689f20fd544SFUJITA Tomonori /// An identifier for PHY devices on an MDIO/MII bus.
690f20fd544SFUJITA Tomonori ///
691f20fd544SFUJITA Tomonori /// Represents the kernel's `struct mdio_device_id`. This is used to find an appropriate
692f20fd544SFUJITA Tomonori /// PHY driver.
693f20fd544SFUJITA Tomonori pub struct DeviceId {
694f20fd544SFUJITA Tomonori id: u32,
695f20fd544SFUJITA Tomonori mask: DeviceMask,
696f20fd544SFUJITA Tomonori }
697f20fd544SFUJITA Tomonori
698f20fd544SFUJITA Tomonori impl DeviceId {
699f20fd544SFUJITA Tomonori /// Creates a new instance with the exact match mask.
new_with_exact_mask(id: u32) -> Self700f20fd544SFUJITA Tomonori pub const fn new_with_exact_mask(id: u32) -> Self {
701f20fd544SFUJITA Tomonori DeviceId {
702f20fd544SFUJITA Tomonori id,
703f20fd544SFUJITA Tomonori mask: DeviceMask::Exact,
704f20fd544SFUJITA Tomonori }
705f20fd544SFUJITA Tomonori }
706f20fd544SFUJITA Tomonori
707f20fd544SFUJITA Tomonori /// Creates a new instance with the model match mask.
new_with_model_mask(id: u32) -> Self708f20fd544SFUJITA Tomonori pub const fn new_with_model_mask(id: u32) -> Self {
709f20fd544SFUJITA Tomonori DeviceId {
710f20fd544SFUJITA Tomonori id,
711f20fd544SFUJITA Tomonori mask: DeviceMask::Model,
712f20fd544SFUJITA Tomonori }
713f20fd544SFUJITA Tomonori }
714f20fd544SFUJITA Tomonori
715f20fd544SFUJITA Tomonori /// Creates a new instance with the vendor match mask.
new_with_vendor_mask(id: u32) -> Self716f20fd544SFUJITA Tomonori pub const fn new_with_vendor_mask(id: u32) -> Self {
717f20fd544SFUJITA Tomonori DeviceId {
718f20fd544SFUJITA Tomonori id,
719f20fd544SFUJITA Tomonori mask: DeviceMask::Vendor,
720f20fd544SFUJITA Tomonori }
721f20fd544SFUJITA Tomonori }
722f20fd544SFUJITA Tomonori
723f20fd544SFUJITA Tomonori /// Creates a new instance with a custom match mask.
new_with_custom_mask(id: u32, mask: u32) -> Self724f20fd544SFUJITA Tomonori pub const fn new_with_custom_mask(id: u32, mask: u32) -> Self {
725f20fd544SFUJITA Tomonori DeviceId {
726f20fd544SFUJITA Tomonori id,
727f20fd544SFUJITA Tomonori mask: DeviceMask::Custom(mask),
728f20fd544SFUJITA Tomonori }
729f20fd544SFUJITA Tomonori }
730f20fd544SFUJITA Tomonori
731f20fd544SFUJITA Tomonori /// Creates a new instance from [`Driver`].
new_with_driver<T: Driver>() -> Self732f20fd544SFUJITA Tomonori pub const fn new_with_driver<T: Driver>() -> Self {
733f20fd544SFUJITA Tomonori T::PHY_DEVICE_ID
734f20fd544SFUJITA Tomonori }
735f20fd544SFUJITA Tomonori
736f20fd544SFUJITA Tomonori /// Get a `mask` as u32.
mask_as_int(&self) -> u32737f20fd544SFUJITA Tomonori pub const fn mask_as_int(&self) -> u32 {
738f20fd544SFUJITA Tomonori self.mask.as_int()
739f20fd544SFUJITA Tomonori }
740f20fd544SFUJITA Tomonori
741f20fd544SFUJITA Tomonori // macro use only
742f20fd544SFUJITA Tomonori #[doc(hidden)]
mdio_device_id(&self) -> bindings::mdio_device_id743f20fd544SFUJITA Tomonori pub const fn mdio_device_id(&self) -> bindings::mdio_device_id {
744f20fd544SFUJITA Tomonori bindings::mdio_device_id {
745f20fd544SFUJITA Tomonori phy_id: self.id,
746f20fd544SFUJITA Tomonori phy_id_mask: self.mask.as_int(),
747f20fd544SFUJITA Tomonori }
748f20fd544SFUJITA Tomonori }
749f20fd544SFUJITA Tomonori }
750f20fd544SFUJITA Tomonori
751f20fd544SFUJITA Tomonori enum DeviceMask {
752f20fd544SFUJITA Tomonori Exact,
753f20fd544SFUJITA Tomonori Model,
754f20fd544SFUJITA Tomonori Vendor,
755f20fd544SFUJITA Tomonori Custom(u32),
756f20fd544SFUJITA Tomonori }
757f20fd544SFUJITA Tomonori
758f20fd544SFUJITA Tomonori impl DeviceMask {
759f20fd544SFUJITA Tomonori const MASK_EXACT: u32 = !0;
760f20fd544SFUJITA Tomonori const MASK_MODEL: u32 = !0 << 4;
761f20fd544SFUJITA Tomonori const MASK_VENDOR: u32 = !0 << 10;
762f20fd544SFUJITA Tomonori
as_int(&self) -> u32763f20fd544SFUJITA Tomonori const fn as_int(&self) -> u32 {
764f20fd544SFUJITA Tomonori match self {
765f20fd544SFUJITA Tomonori DeviceMask::Exact => Self::MASK_EXACT,
766f20fd544SFUJITA Tomonori DeviceMask::Model => Self::MASK_MODEL,
767f20fd544SFUJITA Tomonori DeviceMask::Vendor => Self::MASK_VENDOR,
768f20fd544SFUJITA Tomonori DeviceMask::Custom(mask) => *mask,
769f20fd544SFUJITA Tomonori }
770f20fd544SFUJITA Tomonori }
771f20fd544SFUJITA Tomonori }
7722fe11d5aSFUJITA Tomonori
7732fe11d5aSFUJITA Tomonori /// Declares a kernel module for PHYs drivers.
7742fe11d5aSFUJITA Tomonori ///
7752fe11d5aSFUJITA Tomonori /// This creates a static array of kernel's `struct phy_driver` and registers it.
7762fe11d5aSFUJITA Tomonori /// This also corresponds to the kernel's `MODULE_DEVICE_TABLE` macro, which embeds the information
7772fe11d5aSFUJITA Tomonori /// for module loading into the module binary file. Every driver needs an entry in `device_table`.
7782fe11d5aSFUJITA Tomonori ///
7792fe11d5aSFUJITA Tomonori /// # Examples
7802fe11d5aSFUJITA Tomonori ///
7812fe11d5aSFUJITA Tomonori /// ```
7822fe11d5aSFUJITA Tomonori /// # mod module_phy_driver_sample {
7832fe11d5aSFUJITA Tomonori /// use kernel::c_str;
7842fe11d5aSFUJITA Tomonori /// use kernel::net::phy::{self, DeviceId};
7852fe11d5aSFUJITA Tomonori /// use kernel::prelude::*;
7862fe11d5aSFUJITA Tomonori ///
7872fe11d5aSFUJITA Tomonori /// kernel::module_phy_driver! {
7882fe11d5aSFUJITA Tomonori /// drivers: [PhySample],
7892fe11d5aSFUJITA Tomonori /// device_table: [
7902fe11d5aSFUJITA Tomonori /// DeviceId::new_with_driver::<PhySample>()
7912fe11d5aSFUJITA Tomonori /// ],
7922fe11d5aSFUJITA Tomonori /// name: "rust_sample_phy",
793*38559da6SGuilherme Giacomo Simoes /// authors: ["Rust for Linux Contributors"],
7942fe11d5aSFUJITA Tomonori /// description: "Rust sample PHYs driver",
7952fe11d5aSFUJITA Tomonori /// license: "GPL",
7962fe11d5aSFUJITA Tomonori /// }
7972fe11d5aSFUJITA Tomonori ///
7982fe11d5aSFUJITA Tomonori /// struct PhySample;
7992fe11d5aSFUJITA Tomonori ///
8002fe11d5aSFUJITA Tomonori /// #[vtable]
8012fe11d5aSFUJITA Tomonori /// impl phy::Driver for PhySample {
8022fe11d5aSFUJITA Tomonori /// const NAME: &'static CStr = c_str!("PhySample");
8032fe11d5aSFUJITA Tomonori /// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
8042fe11d5aSFUJITA Tomonori /// }
8052fe11d5aSFUJITA Tomonori /// # }
8062fe11d5aSFUJITA Tomonori /// ```
8072fe11d5aSFUJITA Tomonori ///
8082fe11d5aSFUJITA Tomonori /// This expands to the following code:
8092fe11d5aSFUJITA Tomonori ///
8102fe11d5aSFUJITA Tomonori /// ```ignore
8112fe11d5aSFUJITA Tomonori /// use kernel::c_str;
8122fe11d5aSFUJITA Tomonori /// use kernel::net::phy::{self, DeviceId};
8132fe11d5aSFUJITA Tomonori /// use kernel::prelude::*;
8142fe11d5aSFUJITA Tomonori ///
8152fe11d5aSFUJITA Tomonori /// struct Module {
8162fe11d5aSFUJITA Tomonori /// _reg: ::kernel::net::phy::Registration,
8172fe11d5aSFUJITA Tomonori /// }
8182fe11d5aSFUJITA Tomonori ///
8192fe11d5aSFUJITA Tomonori /// module! {
8202fe11d5aSFUJITA Tomonori /// type: Module,
8212fe11d5aSFUJITA Tomonori /// name: "rust_sample_phy",
822*38559da6SGuilherme Giacomo Simoes /// authors: ["Rust for Linux Contributors"],
8232fe11d5aSFUJITA Tomonori /// description: "Rust sample PHYs driver",
8242fe11d5aSFUJITA Tomonori /// license: "GPL",
8252fe11d5aSFUJITA Tomonori /// }
8262fe11d5aSFUJITA Tomonori ///
8272fe11d5aSFUJITA Tomonori /// struct PhySample;
8282fe11d5aSFUJITA Tomonori ///
8292fe11d5aSFUJITA Tomonori /// #[vtable]
8302fe11d5aSFUJITA Tomonori /// impl phy::Driver for PhySample {
8312fe11d5aSFUJITA Tomonori /// const NAME: &'static CStr = c_str!("PhySample");
8322fe11d5aSFUJITA Tomonori /// const PHY_DEVICE_ID: phy::DeviceId = phy::DeviceId::new_with_exact_mask(0x00000001);
8332fe11d5aSFUJITA Tomonori /// }
8342fe11d5aSFUJITA Tomonori ///
8352fe11d5aSFUJITA Tomonori /// const _: () = {
8362fe11d5aSFUJITA Tomonori /// static mut DRIVERS: [::kernel::net::phy::DriverVTable; 1] =
8372fe11d5aSFUJITA Tomonori /// [::kernel::net::phy::create_phy_driver::<PhySample>()];
8382fe11d5aSFUJITA Tomonori ///
8392fe11d5aSFUJITA Tomonori /// impl ::kernel::Module for Module {
840d22f955cSRahul Rameshbabu /// fn init(module: &'static ::kernel::ThisModule) -> Result<Self> {
8412fe11d5aSFUJITA Tomonori /// let drivers = unsafe { &mut DRIVERS };
8422fe11d5aSFUJITA Tomonori /// let mut reg = ::kernel::net::phy::Registration::register(
8432fe11d5aSFUJITA Tomonori /// module,
8442fe11d5aSFUJITA Tomonori /// ::core::pin::Pin::static_mut(drivers),
8452fe11d5aSFUJITA Tomonori /// )?;
8462fe11d5aSFUJITA Tomonori /// Ok(Module { _reg: reg })
8472fe11d5aSFUJITA Tomonori /// }
8482fe11d5aSFUJITA Tomonori /// }
8492fe11d5aSFUJITA Tomonori /// };
8502fe11d5aSFUJITA Tomonori ///
8513ed8d344SFUJITA Tomonori /// const _DEVICE_TABLE: [::kernel::bindings::mdio_device_id; 2] = [
8522fe11d5aSFUJITA Tomonori /// ::kernel::bindings::mdio_device_id {
8532fe11d5aSFUJITA Tomonori /// phy_id: 0x00000001,
8542fe11d5aSFUJITA Tomonori /// phy_id_mask: 0xffffffff,
8552fe11d5aSFUJITA Tomonori /// },
8562fe11d5aSFUJITA Tomonori /// ::kernel::bindings::mdio_device_id {
8572fe11d5aSFUJITA Tomonori /// phy_id: 0,
8582fe11d5aSFUJITA Tomonori /// phy_id_mask: 0,
8592fe11d5aSFUJITA Tomonori /// },
8602fe11d5aSFUJITA Tomonori /// ];
8613ed8d344SFUJITA Tomonori /// #[cfg(MODULE)]
8623ed8d344SFUJITA Tomonori /// #[no_mangle]
86394901b7aSFUJITA Tomonori /// static __mod_device_table__mdio__phydev: [::kernel::bindings::mdio_device_id; 2] = _DEVICE_TABLE;
8642fe11d5aSFUJITA Tomonori /// ```
8652fe11d5aSFUJITA Tomonori #[macro_export]
8662fe11d5aSFUJITA Tomonori macro_rules! module_phy_driver {
8672fe11d5aSFUJITA Tomonori (@replace_expr $_t:tt $sub:expr) => {$sub};
8682fe11d5aSFUJITA Tomonori
8692fe11d5aSFUJITA Tomonori (@count_devices $($x:expr),*) => {
8702fe11d5aSFUJITA Tomonori 0usize $(+ $crate::module_phy_driver!(@replace_expr $x 1usize))*
8712fe11d5aSFUJITA Tomonori };
8722fe11d5aSFUJITA Tomonori
8732fe11d5aSFUJITA Tomonori (@device_table [$($dev:expr),+]) => {
8742fe11d5aSFUJITA Tomonori // SAFETY: C will not read off the end of this constant since the last element is zero.
8753ed8d344SFUJITA Tomonori const _DEVICE_TABLE: [$crate::bindings::mdio_device_id;
8762fe11d5aSFUJITA Tomonori $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = [
8772fe11d5aSFUJITA Tomonori $($dev.mdio_device_id()),+,
8782fe11d5aSFUJITA Tomonori $crate::bindings::mdio_device_id {
8792fe11d5aSFUJITA Tomonori phy_id: 0,
8802fe11d5aSFUJITA Tomonori phy_id_mask: 0
8812fe11d5aSFUJITA Tomonori }
8822fe11d5aSFUJITA Tomonori ];
8833ed8d344SFUJITA Tomonori
8843ed8d344SFUJITA Tomonori #[cfg(MODULE)]
8853ed8d344SFUJITA Tomonori #[no_mangle]
88694901b7aSFUJITA Tomonori static __mod_device_table__mdio__phydev: [$crate::bindings::mdio_device_id;
8873ed8d344SFUJITA Tomonori $crate::module_phy_driver!(@count_devices $($dev),+) + 1] = _DEVICE_TABLE;
8882fe11d5aSFUJITA Tomonori };
8892fe11d5aSFUJITA Tomonori
8902fe11d5aSFUJITA Tomonori (drivers: [$($driver:ident),+ $(,)?], device_table: [$($dev:expr),+ $(,)?], $($f:tt)*) => {
8912fe11d5aSFUJITA Tomonori struct Module {
8922fe11d5aSFUJITA Tomonori _reg: $crate::net::phy::Registration,
8932fe11d5aSFUJITA Tomonori }
8942fe11d5aSFUJITA Tomonori
8952fe11d5aSFUJITA Tomonori $crate::prelude::module! {
8962fe11d5aSFUJITA Tomonori type: Module,
8972fe11d5aSFUJITA Tomonori $($f)*
8982fe11d5aSFUJITA Tomonori }
8992fe11d5aSFUJITA Tomonori
9002fe11d5aSFUJITA Tomonori const _: () = {
9012fe11d5aSFUJITA Tomonori static mut DRIVERS: [$crate::net::phy::DriverVTable;
9022fe11d5aSFUJITA Tomonori $crate::module_phy_driver!(@count_devices $($driver),+)] =
9032fe11d5aSFUJITA Tomonori [$($crate::net::phy::create_phy_driver::<$driver>()),+];
9042fe11d5aSFUJITA Tomonori
9052fe11d5aSFUJITA Tomonori impl $crate::Module for Module {
906d22f955cSRahul Rameshbabu fn init(module: &'static $crate::ThisModule) -> Result<Self> {
9072fe11d5aSFUJITA Tomonori // SAFETY: The anonymous constant guarantees that nobody else can access
9082fe11d5aSFUJITA Tomonori // the `DRIVERS` static. The array is used only in the C side.
9092fe11d5aSFUJITA Tomonori let drivers = unsafe { &mut DRIVERS };
9102fe11d5aSFUJITA Tomonori let mut reg = $crate::net::phy::Registration::register(
9112fe11d5aSFUJITA Tomonori module,
9122fe11d5aSFUJITA Tomonori ::core::pin::Pin::static_mut(drivers),
9132fe11d5aSFUJITA Tomonori )?;
9142fe11d5aSFUJITA Tomonori Ok(Module { _reg: reg })
9152fe11d5aSFUJITA Tomonori }
9162fe11d5aSFUJITA Tomonori }
9172fe11d5aSFUJITA Tomonori };
9182fe11d5aSFUJITA Tomonori
9192fe11d5aSFUJITA Tomonori $crate::module_phy_driver!(@device_table [$($dev),+]);
9202fe11d5aSFUJITA Tomonori }
9212fe11d5aSFUJITA Tomonori }
922