STRUCT PHY_DRIVER(9)
πΈ struct phy_driver(9) β Kernel API Manual πΈ
β¨ NAME β¨
struct phy_driver β the driver structure for a particular PHY type. Bestie, this is the blueprint a PHY driver fills out so the kernel knows what it can do π.
π¦ SYNOPSIS π¦
struct phy_driver {
struct mdio_driver_common mdiodrv;
u32 phy_id;
char *name;
u32 phy_id_mask;
const unsigned long * const features;
u32 flags;
const void *driver_data;
int (*soft_reset)(struct phy_device *phydev);
int (*config_init)(struct phy_device *phydev);
int (*probe)(struct phy_device *phydev);
int (*get_features)(struct phy_device *phydev);
unsigned int (*inband_caps)(struct phy_device *phydev,
phy_interface_t interface);
int (*config_inband)(struct phy_device *phydev, unsigned int modes);
int (*get_rate_matching)(struct phy_device *phydev, phy_interface_t
iface);
int (*suspend)(struct phy_device *phydev);
int (*resume)(struct phy_device *phydev);
int (*config_aneg)(struct phy_device *phydev);
int (*aneg_done)(struct phy_device *phydev);
int (*read_status)(struct phy_device *phydev);
int (*config_intr)(struct phy_device *phydev);
irqreturn_t (*handle_interrupt)(struct phy_device *phydev);
void (*remove)(struct phy_device *phydev);
int (*match_phy_device)(struct phy_device *phydev, const struct
phy_driver *phydrv);
int (*set_wol)(struct phy_device *dev, struct ethtool_wolinfo *wol);
void (*get_wol)(struct phy_device *dev, struct ethtool_wolinfo
*wol);
void (*link_change_notify)(struct phy_device *dev);
int (*read_mmd)(struct phy_device *dev, int devnum, u16 regnum);
int (*write_mmd)(struct phy_device *dev, int devnum, u16 regnum, u16
val);
int (*read_page)(struct phy_device *dev);
int (*write_page)(struct phy_device *dev, int page);
int (*module_info)(struct phy_device *dev, struct ethtool_modinfo
*modinfo);
int (*module_eeprom)(struct phy_device *dev, struct ethtool_eeprom
*ee, u8 *data);
int (*cable_test_start)(struct phy_device *dev);
int (*cable_test_tdr_start)(struct phy_device *dev, const struct
phy_tdr_config *config);
int (*cable_test_get_status)(struct phy_device *dev, bool
*finished);
void (*get_phy_stats)(struct phy_device *dev, struct
ethtool_eth_phy_stats *eth_stats, struct ethtool_phy_stats *stats);
void (*get_link_stats)(struct phy_device *dev, struct
ethtool_link_ext_stats *link_stats);
int (*update_stats)(struct phy_device *dev);
int (*get_sset_count)(struct phy_device *dev);
void (*get_strings)(struct phy_device *dev, u8 *data);
void (*get_stats)(struct phy_device *dev, struct ethtool_stats
*stats, u64 *data);
int (*disable_autonomous_eee)(struct phy_device *dev);
int (*get_tunable)(struct phy_device *dev, struct ethtool_tunable
*tuna, void *data);
int (*set_tunable)(struct phy_device *dev, struct ethtool_tunable
*tuna, const void *data);
int (*set_loopback)(struct phy_device *dev, bool enable, int speed);
int (*get_sqi)(struct phy_device *dev);
int (*get_sqi_max)(struct phy_device *dev);
int (*get_mse_capability)(struct phy_device *dev, struct
phy_mse_capability *cap);
int (*get_mse_snapshot)(struct phy_device *dev, enum phy_mse_channel
channel, struct phy_mse_snapshot *snapshot);
int (*get_plca_cfg)(struct phy_device *dev, struct phy_plca_cfg
*plca_cfg);
int (*set_plca_cfg)(struct phy_device *dev, const struct
phy_plca_cfg *plca_cfg);
int (*get_plca_status)(struct phy_device *dev, struct
phy_plca_status *plca_st);
int (*led_brightness_set)(struct phy_device *dev, u8 index, enum
led_brightness value);
int (*led_blink_set)(struct phy_device *dev, u8 index, unsigned long
*delay_on, unsigned long *delay_off);
int (*led_hw_is_supported)(struct phy_device *dev, u8 index,
unsigned long rules);
int (*led_hw_control_set)(struct phy_device *dev, u8 index, unsigned
long rules);
int (*led_hw_control_get)(struct phy_device *dev, u8 index, unsigned
long *rules);
int (*led_polarity_set)(struct phy_device *dev, int index, unsigned
long modes);
unsigned int (*get_next_update_time)(struct phy_device *dev);
int (*attach_mii_port)(struct phy_device *dev, struct phy_port
*port);
int (*attach_mdi_port)(struct phy_device *dev, struct phy_port
*port);
};
π Members π
okay so hereβs the cast of characters in this struct β each one is a little hook the PHY driver can provide π
mdiodrvβ data common to all MDIO devices.phy_idβ the result of reading the UID registers of this PHY type, and ANDing them with thephy_id_mask. This driver only works for PHYs with IDs which match this field.nameβ the friendly name of this PHY type.phy_id_maskβ defines the important bits of thephy_id.featuresβ a mandatory list of features (speed, duplex, etc) supported by this PHY.flagsβ a bitfield defining certain other features this PHY supports (like interrupts).driver_dataβ static driver data.soft_resetβ called to issue a PHY software reset.config_initβ called to initialize the PHY, including after a reset.probeβ called during discovery. Used to set up device-specific structures, if any.get_featuresβ probe the hardware to determine what abilities it has. Should only setphydev->supported.inband_capsβ query whether in-band is supported for the given PHY interface mode. Returns a bitmask of bits defined byenum link_inband_signalling.config_inbandβ configure in-band mode for the PHY.get_rate_matchingβ get the supported type of rate matching for a particular phy interface. This is used by phy consumers to determine whether to advertise lower-speed modes for that interface. It is assumed that if a rate matching mode is supported on an interface, then that interfaceβs rate can be adapted to all slower link speeds supported by the phy. If the interface is not supported, this should returnRATE_MATCH_NONE.suspendβ suspend the hardware, saving state if needed.resumeβ resume the hardware, restoring state if needed.config_anegβ configures the advertisement and resets autonegotiation ifphydev->autonegis on, forces the speed to the current settings inphydevifphydev->autonegis off.aneg_doneβ determines the auto negotiation result.read_statusβ determines the negotiated speed and duplex.config_intrβ enables or disables interrupts. It should also clear any pending interrupts prior to enabling the IRQs and after disabling them.handle_interruptβ override default interrupt handling.removeβ clears up any memory if needed.match_phy_deviceβ returns true if this is a suitable driver for the givenphydev. IfNULL, matching is based onphy_idandphy_id_mask.set_wolβ some devices (e.g.qnap TS-119P II) require PHY register changes to enable Wake on LAN, soset_wolis provided to be called in the ethernet driverβsset_wolfunction.get_wolβ seeset_wol, but for checking whether Wake on LAN is enabled.link_change_notifyβ called to inform a PHY device driver when the core is about to change the link state. This callback is supposed to be used as fixup hook for drivers that need to take action when the link state changes. Drivers are by no means allowed to mess with the PHY device structure in their implementations.read_mmdβ PHY specific driver override for reading a MMD register. This function is optional for PHY specific drivers. When not provided, the default MMD read function will be used byphy_read_mmd, which will use either a direct read for Clause 45 PHYs or an indirect read for Clause 22 PHYs.devnumis the MMD device number within the PHY device,regnumis the register within the selected MMD device.write_mmdβ PHY specific driver override for writing a MMD register. This function is optional for PHY specific drivers. When not provided, the default MMD write function will be used byphy_write_mmd, which will use either a direct write for Clause 45 PHYs, or an indirect write for Clause 22 PHYs.devnumis the MMD device number within the PHY device,regnumis the register within the selected MMD device.valis the value to be written.read_pageβ return the current PHY register page number.write_pageβ set the current PHY register page number.module_infoβ get the size and type of the eeprom contained within a plug-in module.module_eepromβ get the eeprom information from the plug-in module.cable_test_startβ start a cable test.cable_test_tdr_startβ start a raw TDR cable test.cable_test_get_statusβ once per second, or on interrupt, request the status of the test.get_phy_statsβ retrieve PHY statistics.dev: the PHY device for which the statistics are retrieved.eth_stats: structure where Ethernet PHY stats will be stored.stats: structure where additional PHY-specific stats will be stored.
Retrieves the supported PHY statistics and populates the provided structures. The input structures are pre-initialized with ETHTOOL_STAT_NOT_SET, and the driver must only modify members corresponding to supported statistics. Unmodified members will remain set to ETHTOOL_STAT_NOT_SET and will not be returned to userspace.
get_link_statsβ retrieve link statistics.dev: the PHY device for which the statistics are retrieved.link_stats: structure where link-specific stats will be stored.
Retrieves link-related statistics for the given PHY device. The input structure is pre-initialized with ETHTOOL_STAT_NOT_SET, and the driver must only modify members corresponding to supported statistics. Unmodified members will remain set to ETHTOOL_STAT_NOT_SET and will not be returned to userspace.
update_statsβ trigger periodic statistics updates.dev: the PHY device for which statistics updates are triggered.update_statsβ pulls the stats off the PHY on a schedule so your local 64-bit counters stay accurate β¨ this matters because some PHYs only give you reduced-width counters (like 16-bit or 32-bit) and those overflow way faster than 64-bit ones. By calling this callback, drivers can grab the current counter values, catch the overflow, and accumulate everything into local 64-bit counters soget_phy_statsandget_link_statsreport the truth. π
Return: 0 on success or a negative error code on failure.
get_sset_countβ number of statistic counters πget_stringsβ the names of the statistic counters πget_statsβ hands back the statistic counter values πdisable_autonomous_eeeβ turns off PHY-autonomous EEE πΈ
So like, some PHYs just manage EEE all on their own and won't let the MAC control LPI signaling. This callback disables that autonomous EEE right at the PHY.
Return: 0 on success, negative errno on failure.
get_tunableβ returns the value of a tunable π¦set_tunableβ sets the value of a tunable π¦set_loopbackβ sets the loopback mode of the PHY.enableselects whether the loopback mode is enabled or disabled. If loopback is enabled, then the speed of the loopback mode can be requested with thespeedargument. Ifspeedis zero, then any speed can be selected. Ifspeedis> 0, then that speed shall be selected for the loopback mode β orEOPNOTSUPPshall be returned if speed selection isn't supported. π€get_sqiβ get the signal quality indication β¨get_sqi_maxβ get the maximum signal quality indication πget_mse_capabilityβ get capabilities and scale of MSE measurement.dev: PHY device.cap: Output (filled on success).
Fills cap with the PHY's MSE capability for the current link mode: scale limits (max_average_mse, max_peak_mse), update interval (refresh_rate_ps), sample length (num_symbols) and the capability bitmask (supported_caps). π§
Implementations may defer the capability report until the hardware has converged β in that case they should return -EAGAIN and let the caller retry later. No biggie, just try again bestie π
Return: 0 on success. On failure, returns a negative errno code, such as -EOPNOTSUPP if MSE measurement isn't supported by the PHY or in the current link mode, or -EAGAIN if the capability information isn't available yet.
get_mse_snapshotβ retrieve a snapshot of MSE diagnostic values.dev: PHY device.channel: Channel identifier (PHY_MSE_CHANNEL_*).snapshot: Output (filled on success).
Fills snapshot with a correlated set of MSE values from the most recent measurement window. πͺ
Callers must validate channel against supported_caps returned by get_mse_capability. Drivers must not coerce channel β if the requested selector isn't implemented by the device or the current link mode, the operation must fail. periodt. π
worst_peak_mse is latched and must be treated as read-to-clear.
Return: 0 on success. On failure, returns a negative errno code, such as -EOPNOTSUPP if MSE measurement isn't supported by the PHY or in the current link mode, or -EAGAIN if measurements aren't available yet.
get_plca_cfgβ return the current PLCA configuration πset_plca_cfgβ set the PLCA configuration πget_plca_statusβ return the current PLCA status info πled_brightness_setβ set a PHY LED brightness.indexindicates which of the PHY's LEDs should be set.valuefollows the standard LED class meaning, e.g.LED_OFF,LED_HALF,LED_FULL. π‘led_blink_setβ set a PHY LED blinking.indexindicates which of the PHY's LEDs should be configured to blink. Delays are in milliseconds, and if both are zero then a sensible default should be chosen. The call should adjust the timings in that case β and if it can't match the values specified exactly. β¨led_hw_is_supportedβ can the HW support the given rules?dev: PHY device which has the LED.index: which LED of the PHY device.rules: the rules the core is interested in.
Return 0 if yes, -EOPNOTSUPP if not, or an error code. π«Ά
led_hw_control_setβ set the HW to control the LED.dev: PHY device which has the LED.index: which LED of the PHY device.rules: the rules used to control the LED.
Returns 0, or an error code.
led_hw_control_getβ get how the HW is controlling the LED.dev: PHY device which has the LED.index: which LED of the PHY device.rules: pointer to the rules used to control the LED.
Set *rules to how the HW is currently blinking. Returns 0 on success, or an error code if the current blinking can't be represented in rules, or some other error happens. π
led_polarity_setβ set the LED polarity modes.dev: PHY device which has the LED.index: which LED of the PHY device.modes: bitmap of LED polarity modes.
Configure the LED with all the required polarity modes in modes so it correctly turns ON or OFF. π₯
Returns 0, or an error code.
get_next_update_timeβ get the time until the next update event.dev: PHY device.
Callback to determine the time (in jiffies) until the next update event for the PHY state machine. Lets PHY drivers dynamically adjust polling intervals based on link state or other conditions. β°
Returns the time in jiffies until the next update event.
attach_mii_portβ attach the given MII port to the PHY device.dev: PHY device to notify.port: the port being added.
Called when an MII port that needs to be driven by the PHY is found. π
The port being passed may or may not be initialized. If it is already initialized, it's by the generic port representation from devicetree β which supersedes any strapping or vendor-specific properties. no cap.
If the port isn't initialized, the port->mediums and port->lanes fields must be set, possibly according to strapping information.
The PHY driver must set the port->interfaces field to indicate the possible MII modes that this PHY can output on the port.
Returns 0, or an error code. π
attach_mdi_portβ attach the given MII port to the PHY device.dev: PHY device to notify.port: the port being added.
Called when a port that needs to be driven by the PHY is found. The number of times this will be called depends on phydev->max_n_ports, which the driver can change in .probe. π©Ί
The port being passed may or may not be initialized. If it is already initialized, it's by the generic port representation from devicetree β which supersedes any strapping or vendor-specific properties.
If the port isn't initialized, the port->mediums and port->lanes fields must be set, possibly according to strapping information.
Returns 0, or an error code. π«Ά
β¨ DESCRIPTION β¨
Okay so the vibes here: all of these functions are optional π
If config_aneg or read_status aren't implemented, the phy core just uses the genphy versions. Easy.
β οΈ Heads up bestie β none of these functions should be called from interrupt time. π¨
The goal is for the bus read/write functions to be able to block when the bus transaction is happening, and be freed up by an interrupt. (The MPC85xx has this ability, though it is not currently supported in the driver.) π¦
π SEE ALSO π
Kernel file ./include/linux/phy.h: enum phy_interface_t(9), phy_modes(9), rgmii_clock(9), struct mdio_bus_stats(9), struct mii_bus(9), mdiobus_alloc(9), enum phy_state(9), struct phy_c45_device_ids(9), struct phy_oatc14_sqi_capability(9), struct phy_device(9), struct phy_tdr_config(9), enum link_inband_signalling(9), struct phy_plca_cfg(9), struct phy_plca_status(9), struct phy_led(9), struct phy_mse_capability(9), struct phy_mse_snapshot(9), phy_id_compare(9), phy_id_compare_vendor(9), phy_id_compare_model(9), phydev_id_compare(9), phy_is_started(9), phy_driver_is_genphy(9), phy_disable_eee_mode(9), phy_can_wakeup(9), phy_may_wakeup(9), phy_read(9), __phy_read(9), phy_write(9), __phy_write(9), __phy_modify_changed(9), phy_read_mmd_poll_timeout(9), __phy_set_bits(9), __phy_clear_bits(9), phy_set_bits(9), phy_clear_bits(9), __phy_set_bits_mmd(9), __phy_clear_bits_mmd(9), phy_set_bits_mmd(9), phy_clear_bits_mmd(9), phy_interrupt_is_valid(9), phy_polling_mode(9), phy_has_hwtstamp(9), phy_has_rxtstamp(9), phy_has_tsinfo(9), phy_has_txtstamp(9), phy_is_default_hwtstamp(9), phy_on_sfp(9), phy_interface_mode_is_rgmii(9), phy_interface_mode_is_8023z(9), phy_interface_is_rgmii(9), phy_is_pseudo_fixed_link(9), phy_module_driver(9) π
That's a wrap, bestie! π This lil masterpiece lives in ./include/linux, and the version you're reading is the October 2026 drop of the struct phy_driver(9) page. Go forth and slay your PHY driver, you absolute icon πβ¨
π¦ where this page comes from
- nixpkgs unstable: linux-manual 7.3.1
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms