net: add phylink support for PCS
Subsystems (4)
Russell King - ARM Linux admin
maintainercover net: add phylink support for PCS
In reply to Russell King - ARM Linux adminDepends on "net: mii clause 37 helpers".
This series adds support for IEEE 802.3 register set compliant PCS for phylink. In order to do this, we:
1. add accessors for modifying a MDIO device register, and use them in phylib, rather than duplicating the code from phylib.
2. add support for decoding the advertisement from clause 22 compatible register sets for clause 37 advertisements and SGMII advertisements.
3. add support for clause 45 register sets for 10GBASE-R PCS.
These have been tested on the LX2160A Clearfog-CX platform.
This is a re-post of the series previously sent, but with the first two patches separated out; the conclusion of the discussion with Vladimir seemed to be that there was no issue with the patches themselves.
drivers/net/phy/mdio_bus.c | 55 +++++++++++ drivers/net/phy/phy-core.c | 31 ------ drivers/net/phy/phylink.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mdio.h | 4 + include/linux/phy.h | 19 ++++ include/linux/phylink.h | 8 ++ include/uapi/linux/mii.h | 5 + 7 files changed, 327 insertions(+), 31 deletions(-)
Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 10.2Mbps down 587kbps up
Russell King - ARM Linux admin
maintainerPlease ignore this series entirely.
Quoted 29 lines · Russell King - ARM Linux admin
Depends on "net: mii clause 37 helpers".
This series adds support for IEEE 802.3 register set compliant PCS for phylink. In order to do this, we:
1. add accessors for modifying a MDIO device register, and use them in phylib, rather than duplicating the code from phylib.
2. add support for decoding the advertisement from clause 22 compatible register sets for clause 37 advertisements and SGMII advertisements.
3. add support for clause 45 register sets for 10GBASE-R PCS.These have been tested on the LX2160A Clearfog-CX platform.
This is a re-post of the series previously sent, but with the first two patches separated out; the conclusion of the discussion with Vladimir seemed to be that there was no issue with the patches themselves.
drivers/net/phy/mdio_bus.c | 55 +++++++++++ drivers/net/phy/phy-core.c | 31 ------ drivers/net/phy/phylink.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mdio.h | 4 + include/linux/phy.h | 19 ++++ include/linux/phylink.h | 8 ++ include/uapi/linux/mii.h | 5 + 7 files changed, 327 insertions(+), 31 deletions(-)Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 10.2Mbps down 587kbps up
Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 10.2Mbps down 587kbps up
Russell King - ARM Linux admin
maintainerRe: [PATCH net-next 4/5] net: phylink: rename 'ops' to 'mac_ops'
In reply to Russell KingKernel development is hard... neither this patch nor the following one is supposed to be part of this series.
Quoted 117 lines · Russell King
Rename the bland 'ops' member of struct phylink to be a more descriptive '
mac_ops' - this is necessary as we're about to introduce another set of operations.Signed-off-by Russell King <[email protected]>--- drivers/net/phy/phylink.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)drivers/net/phy/phylink.c +15
-15@@ -40,7 +40,7 @@ enum {struct phylink {/* private: */ struct net_device *netdev; -const struct phylink_mac_ops *ops; +const struct phylink_mac_ops *mac_ops;struct phylink_config *config;struct device *dev;unsigned int old_link_state:1 ;@@ -154,7 +154,7 @@ static const char *phylink_an_mode_str(unsigned int mode)static int phylink_validate (struct phylink *pl,unsigned long *supported,struct phylink_link_state *state) { - pl->ops->validate (pl->config, supported, state); + pl->mac_ops->validate (pl->config, supported, state);return phylink_is_empty_linkmode (supported) ? -EINVAL :0 ; }@@ -388,7 +388,7 @@ static void phylink_mac_config(struct phylink *pl, __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, state->pause, state->link, state->an_enabled); - pl->ops->mac_config (pl->config, pl->cur_link_an_mode, state); + pl->mac_ops->mac_config (pl->config, pl->cur_link_an_mode, state); } static void phylink_mac_config_up(struct phylink *pl,@@ -402,7 +402,7 @@ static void phylink_mac_an_restart(struct phylink *pl) {if (pl->link_config.an_enabled &&phy_interface_mode_is_8023z (pl->link_config.interface)) - pl->ops->mac_an_restart (pl->config); + pl->mac_ops->mac_an_restart (pl->config); } static void phylink_mac_pcs_get_state(struct phylink *pl,@@ -418,7 +418,7 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, state->an_complete =0 ; state->link =1 ; - pl->ops->mac_pcs_get_state (pl->config, state); + pl->mac_ops->mac_pcs_get_state (pl->config, state); }/* The fixed state is... fixed except for the link state, @@ -485,11 +485,11 @@ static void phylink_mac_link_up(struct phylink *pl,struct net_device *ndev = pl->netdev; pl->cur_interface = link_state.interface; - pl->ops->mac_link_up (pl->config, pl->phydev, - pl->cur_link_an_mode, pl->cur_interface, - link_state.speed, link_state.duplex, - !!(link_state.pause &MLO_PAUSE_TX ), - !!(link_state.pause &MLO_PAUSE_RX )); + pl->mac_ops->mac_link_up (pl->config, pl->phydev, + pl->cur_link_an_mode, pl->cur_interface, + link_state.speed, link_state.duplex, + !!(link_state.pause &MLO_PAUSE_TX ), + !!(link_state.pause &MLO_PAUSE_RX ));if (ndev)netif_carrier_on (ndev);@@ -507,8 +507,8 @@ static void phylink_mac_link_down(struct phylink *pl)if (ndev)netif_carrier_off (ndev); - pl->ops->mac_link_down (pl->config, pl->cur_link_an_mode, - pl->cur_interface); + pl->mac_ops->mac_link_down (pl->config, pl->cur_link_an_mode, + pl->cur_interface);phylink_info (pl,"Link is Down\n" ); }@@ -639,7 +639,7 @@ static int phylink_register_sfp(struct phylink *pl,* @fwnode: a pointer to a &struct fwnode_handle describing the network * interface * @iface: the desired link mode defined by &typedef phy_interface_t -* @ops: a pointer to a &struct phylink_mac_ops for the MAC. +* @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC. * * Create a new phylink instance, and parse the link parameters found in @np. * This will parse in-band modes, fixed-link or SFP configuration. @@ -652,7 +652,7 @@ static int phylink_register_sfp(struct phylink *pl,struct phylink *phylink_create (struct phylink_config *config,struct fwnode_handle *fwnode,phy_interface_t iface, -const struct phylink_mac_ops *ops) +const struct phylink_mac_ops *mac_ops) {struct phylink *pl;int ret;@@ -685,7 +685,7 @@ struct phylink *phylink_create(struct phylink_config *config, pl->link_config.speed =SPEED_UNKNOWN ; pl->link_config.duplex =DUPLEX_UNKNOWN ; pl->link_config.an_enabled = true; - pl->ops = ops; + pl->mac_ops = mac_ops;__set_bit (PHYLINK_DISABLE_STOPPED , &pl->phylink_disable_state);timer_setup (&pl->link_poll, phylink_fixed_poll,0 );Signature · 1 line
2.20.1
Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 10.2Mbps down 587kbps up
PATCH 5/5 net: phylink: add separate pcs operations structure
In reply to Russell King - ARM Linux adminAdd a separate set of PCS operations, which MAC drivers can use to couple phylink with their associated MAC PCS layer. The PCS operations include:
- pcs_get_state() - reads the link up/down, resolved speed, duplex and pause from the PCS.
- pcs_config() - configures the PCS for the specified mode, PHY interface type, and setting the advertisement.
- pcs_an_restart() - restarts 802.3 in-band negotiation with the link partner
- pcs_link_up() - informs the PCS that link has come up, and the parameters of the link. Link parameters are used to program the PCS for fixed speed and non-inband modes.
--- drivers/net/phy/phylink.c | 76 +++++++++++++++++++++++++++------------ include/linux/phylink.h | 11 ++++++ 2 files changed, 65 insertions(+), 22 deletions(-)
drivers/net/phy/phylink.c +54 -22
@@ -41,6 +41,7 @@ struct phylink {/* private: */ struct net_device *netdev;const struct phylink_mac_ops *mac_ops; +const struct phylink_pcs_ops *pcs_ops;struct phylink_config *config;struct device *dev; unsigned int old_link_state:1;
@@ -398,11 +399,31 @@ static void phylink_mac_config_up(struct phylink *pl,phylink_mac_config (pl, state); } -static void phylink_mac_an_restart (struct phylink *pl) +static void phylink_mac_pcs_an_restart (struct phylink *pl) {if (pl->link_config.an_enabled && -phy_interface_mode_is_8023z (pl->link_config.interface)) - pl->mac_ops->mac_an_restart (pl->config); +phy_interface_mode_is_8023z (pl->link_config.interface)) { +if (pl->pcs_ops) + pl->pcs_ops->pcs_an_restart (pl->config); +else + pl->mac_ops->mac_an_restart (pl->config); + } +} + +static void phylink_pcs_config (struct phylink *pl,bool force_restart, +const struct phylink_link_state *state) +{ +bool restart = force_restart; + +if (pl->pcs_ops && pl->pcs_ops->pcs_config (pl->config, + pl->cur_link_an_mode, + state)) + restart = true; + +phylink_mac_config (pl, state); + +if (restart) +phylink_mac_pcs_an_restart (pl); } static void phylink_mac_pcs_get_state(struct phylink *pl,
@@ -418,7 +439,10 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, state->an_complete =0 ; state->link =1 ; - pl->mac_ops->mac_pcs_get_state (pl->config, state); +if (pl->pcs_ops) + pl->pcs_ops->pcs_get_state (pl->config, state); +else + pl->mac_ops->mac_pcs_get_state (pl->config, state); }/* The fixed state is... fixed except for the link state,
@@ -436,7 +460,7 @@ static void phylink_get_fixed_state(struct phylink *pl,phylink_resolve_flow (state); } -static void phylink_mac_initial_config (struct phylink *pl) +static void phylink_mac_initial_config (struct phylink *pl,bool force_restart) {struct phylink_link_state link_state;
@@ -462,7 +486,7 @@ static void phylink_mac_initial_config(struct phylink *pl) link_state.link = false;phylink_apply_manual_flow (pl, &link_state); -phylink_mac_config (pl, &link_state); +phylink_pcs_config (pl, force_restart, &link_state); }static const char *phylink_pause_to_str (int pause)
@@ -479,12 +503,18 @@ static const char *phylink_pause_to_str(int pause) } } -static void phylink_mac_link_up (struct phylink *pl, -struct phylink_link_state link_state) +static void phylink_link_up (struct phylink *pl, +struct phylink_link_state link_state) {struct net_device *ndev = pl->netdev; pl->cur_interface = link_state.interface; + +if (pl->pcs_ops && pl->pcs_ops->pcs_link_up) + pl->pcs_ops->pcs_link_up (pl->config, pl->cur_link_an_mode, + pl->cur_interface, + link_state.speed, link_state.duplex); + pl->mac_ops->mac_link_up(pl->config, pl->phydev, pl->cur_link_an_mode, pl->cur_interface, link_state.speed, link_state.duplex,
@@ -501,7 +531,7 @@ static void phylink_mac_link_up(struct phylink *pl, phylink_pause_to_str(link_state.pause)); } -static void phylink_mac_link_down (struct phylink *pl) +static void phylink_link_down (struct phylink *pl) {struct net_device *ndev = pl->netdev;
@@ -570,9 +600,9 @@ static void phylink_resolve(struct work_struct *w)if (link_changed) { pl->old_link_state = link_state.link;if (!link_state.link) -phylink_mac_link_down (pl); +phylink_link_down (pl);else -phylink_mac_link_up (pl, link_state); +phylink_link_up (pl, link_state); }if (!link_state.link && pl->mac_link_dropped) { pl->mac_link_dropped = false;
@@ -719,6 +749,12 @@ struct phylink *phylink_create(struct phylink_config *config, }EXPORT_SYMBOL_GPL (phylink_create); +void phylink_add_pcs (struct phylink *pl,const struct phylink_pcs_ops *ops) +{ + pl->pcs_ops = ops; +} +EXPORT_SYMBOL_GPL (phylink_add_pcs); +/** * phylink_destroy() - cleanup and destroy the phylink instance * @pl: a pointer to a &struct phylink returned from phylink_create()
@@ -1055,14 +1091,12 @@ void phylink_start(struct phylink *pl)/* Apply the link configuration to the MAC when starting. This allows * a fixed-link to start with the correct parameters, and also * ensures that we set the appropriate advertisement for Serdes links. -*/ -phylink_mac_initial_config (pl); - -/* Restart autonegotiation if using 802.3z to ensure that the link +* +* Restart autonegotiation if using 802.3z to ensure that the link * parameters are properly negotiated. This is necessary for DSA * switches using 802.3z negotiation to ensure they see our modes. */ -phylink_mac_an_restart (pl); +phylink_mac_initial_config (pl, true);clear_bit (PHYLINK_DISABLE_STOPPED , &pl->phylink_disable_state);phylink_run_resolve (pl);
@@ -1359,8 +1393,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,* advertisement; the only thing we have is the pause * modes which can only come from a PHY. */ -phylink_mac_config (pl, &pl->link_config); -phylink_mac_an_restart (pl); +phylink_pcs_config (pl, true, &pl->link_config); }mutex_unlock (&pl->state_mutex); }
@@ -1388,7 +1421,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)if (pl->phydev) ret =phy_restart_aneg (pl->phydev); -phylink_mac_an_restart (pl); +phylink_mac_pcs_an_restart (pl);return ret; }
@@ -1467,8 +1500,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, pause->tx_pause); }else if (!test_bit (PHYLINK_DISABLE_STOPPED , &pl->phylink_disable_state)) { -phylink_mac_config (pl, &pl->link_config); -phylink_mac_an_restart (pl); +phylink_pcs_config (pl, true, &pl->link_config); }mutex_unlock (&pl->state_mutex);
@@ -1874,7 +1906,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,if (changed && !test_bit (PHYLINK_DISABLE_STOPPED , &pl->phylink_disable_state)) -phylink_mac_initial_config (pl); +phylink_mac_initial_config (pl, false);return ret; }
include/linux/phylink.h +11 -0
@@ -97,6 +97,16 @@ struct phylink_mac_ops { bool tx_pause, bool rx_pause); }; +struct phylink_pcs_ops { +void (*pcs_get_state)(struct phylink_config *config, +struct phylink_link_state *state); +int (*pcs_config)(struct phylink_config *config,unsigned int mode, +const struct phylink_link_state *state); +void (*pcs_an_restart)(struct phylink_config *config); +void (*pcs_link_up)(struct phylink_config *config,unsigned int mode, +phy_interface_t interface,int speed,int duplex); +}; +#if 0 /* For kernel-doc purposes only. */ /** * validate - Validate and update the link configuration
@@ -273,6 +283,7 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,struct phylink *phylink_create (struct phylink_config *,struct fwnode_handle *,phy_interface_t iface,const struct phylink_mac_ops *ops); +void phylink_add_pcs (struct phylink *,const struct phylink_pcs_ops *ops);void phylink_destroy (struct phylink *);int phylink_connect_phy (struct phylink *,struct phy_device *);
Signature · 1 line
2.20.1
PATCH 4/5 net: phylink: rename 'ops' to 'mac_ops'
In reply to Russell King - ARM Linux adminRename the bland 'ops' member of struct phylink to be a more descriptive 'mac_ops' - this is necessary as we're about to introduce another set of operations.
--- drivers/net/phy/phylink.c | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-)
drivers/net/phy/phylink.c +15 -15
@@ -40,7 +40,7 @@ enum {struct phylink {/* private: */ struct net_device *netdev; -const struct phylink_mac_ops *ops; +const struct phylink_mac_ops *mac_ops;struct phylink_config *config;struct device *dev;unsigned int old_link_state:1 ;
@@ -154,7 +154,7 @@ static const char *phylink_an_mode_str(unsigned int mode)static int phylink_validate (struct phylink *pl,unsigned long *supported,struct phylink_link_state *state) { - pl->ops->validate (pl->config, supported, state); + pl->mac_ops->validate (pl->config, supported, state);return phylink_is_empty_linkmode (supported) ? -EINVAL :0 ; }
@@ -388,7 +388,7 @@ static void phylink_mac_config(struct phylink *pl, __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, state->pause, state->link, state->an_enabled); - pl->ops->mac_config (pl->config, pl->cur_link_an_mode, state); + pl->mac_ops->mac_config (pl->config, pl->cur_link_an_mode, state); } static void phylink_mac_config_up(struct phylink *pl,
@@ -402,7 +402,7 @@ static void phylink_mac_an_restart(struct phylink *pl) {if (pl->link_config.an_enabled &&phy_interface_mode_is_8023z (pl->link_config.interface)) - pl->ops->mac_an_restart (pl->config); + pl->mac_ops->mac_an_restart (pl->config); } static void phylink_mac_pcs_get_state(struct phylink *pl,
@@ -418,7 +418,7 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, state->an_complete =0 ; state->link =1 ; - pl->ops->mac_pcs_get_state (pl->config, state); + pl->mac_ops->mac_pcs_get_state (pl->config, state); }/* The fixed state is... fixed except for the link state,
@@ -485,11 +485,11 @@ static void phylink_mac_link_up(struct phylink *pl,struct net_device *ndev = pl->netdev; pl->cur_interface = link_state.interface; - pl->ops->mac_link_up (pl->config, pl->phydev, - pl->cur_link_an_mode, pl->cur_interface, - link_state.speed, link_state.duplex, - !!(link_state.pause &MLO_PAUSE_TX ), - !!(link_state.pause &MLO_PAUSE_RX )); + pl->mac_ops->mac_link_up (pl->config, pl->phydev, + pl->cur_link_an_mode, pl->cur_interface, + link_state.speed, link_state.duplex, + !!(link_state.pause &MLO_PAUSE_TX ), + !!(link_state.pause &MLO_PAUSE_RX ));if (ndev)netif_carrier_on (ndev);
@@ -507,8 +507,8 @@ static void phylink_mac_link_down(struct phylink *pl)if (ndev)netif_carrier_off (ndev); - pl->ops->mac_link_down (pl->config, pl->cur_link_an_mode, - pl->cur_interface); + pl->mac_ops->mac_link_down (pl->config, pl->cur_link_an_mode, + pl->cur_interface);phylink_info (pl,"Link is Down\n" ); }
@@ -639,7 +639,7 @@ static int phylink_register_sfp(struct phylink *pl,* @fwnode: a pointer to a &struct fwnode_handle describing the network * interface * @iface: the desired link mode defined by &typedef phy_interface_t -* @ops: a pointer to a &struct phylink_mac_ops for the MAC. +* @mac_ops: a pointer to a &struct phylink_mac_ops for the MAC. * * Create a new phylink instance, and parse the link parameters found in @np. * This will parse in-band modes, fixed-link or SFP configuration.
@@ -652,7 +652,7 @@ static int phylink_register_sfp(struct phylink *pl,struct phylink *phylink_create (struct phylink_config *config,struct fwnode_handle *fwnode,phy_interface_t iface, -const struct phylink_mac_ops *ops) +const struct phylink_mac_ops *mac_ops) {struct phylink *pl;int ret;
@@ -685,7 +685,7 @@ struct phylink *phylink_create(struct phylink_config *config, pl->link_config.speed =SPEED_UNKNOWN ; pl->link_config.duplex =DUPLEX_UNKNOWN ; pl->link_config.an_enabled = true; - pl->ops = ops; + pl->mac_ops = mac_ops;__set_bit (PHYLINK_DISABLE_STOPPED , &pl->phylink_disable_state);timer_setup (&pl->link_poll, phylink_fixed_poll,0 );
Signature · 1 line
2.20.1
PATCH 3/5 net: phylink: pcs: add 802.3 clause 45 helpers
In reply to Russell King - ARM Linux adminImplement helpers for PCS accessed via the MII bus using 802.3 clause 45 cycles for 10GBASE-R. Only link up/down is supported, 10G full duplex is assumed.
--- drivers/net/phy/phylink.c | 30 ++++++++++++++++++++++++++++++ include/linux/phylink.h | 2 ++ 2 files changed, 32 insertions(+)
drivers/net/phy/phylink.c +30 -0
@@ -2247,4 +2247,34 @@ void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs) }EXPORT_SYMBOL_GPL (phylink_mii_c22_pcs_an_restart); +#define C45_ADDR (d,a) (MII_ADDR_C45 | (d) << 16 | (a)) +void phylink_mii_c45_pcs_get_state (struct mdio_device *pcs, +struct phylink_link_state *state) +{ +struct mii_bus *bus = pcs->bus; +int addr = pcs->addr; +int stat; + + stat =mdiobus_read (bus, addr,C45_ADDR (MDIO_MMD_PCS ,MDIO_STAT1 )); +if (stat <0 ) { + state->link = false; +return ; + } + + state->link = !!(stat &MDIO_STAT1_LSTATUS ); +if (!state->link) +return ; + +switch (state->interface) { +case PHY_INTERFACE_MODE_10GBASER : + state->speed =SPEED_10000 ; + state->duplex =DUPLEX_FULL ; +break ; + +default : +break ; + } +} +EXPORT_SYMBOL_GPL (phylink_mii_c45_pcs_get_state); +MODULE_LICENSE ("GPL v2" );
include/linux/phylink.h +2 -0
@@ -323,4 +323,6 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, const struct phylink_link_state *state);void phylink_mii_c22_pcs_an_restart (struct mdio_device *pcs); +void phylink_mii_c45_pcs_get_state (struct mdio_device *pcs, +struct phylink_link_state *state);#endif
Signature · 1 line
2.20.1
PATCH 1/5 net: mdiobus: add APIs for modifying a MDIO device register
In reply to Russell King - ARM Linux adminAdd APIs for modifying a MDIO device register, similar to the existing phy_modify() group of functions, but at mdiobus level instead. Adapt __phy_modify_changed() to use the new mdiobus level helper.
--- drivers/net/phy/mdio_bus.c | 55 ++++++++++++++++++++++++++++++++++++++ drivers/net/phy/phy-core.c | 31 --------------------- include/linux/mdio.h | 4 +++ include/linux/phy.h | 19 +++++++++++++ 4 files changed, 78 insertions(+), 31 deletions(-)
drivers/net/phy/mdio_bus.c +55 -0
@@ -824,6 +824,38 @@ int __mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) }EXPORT_SYMBOL (__mdiobus_write); +/** +* __mdiobus_modify_changed - Unlocked version of the mdiobus_modify function +* @bus: the mii_bus struct +* @addr: the phy address +* @regnum: register number to modify +* @mask: bit mask of bits to clear +* @set: bit mask of bits to set +* +* Read, modify, and if any change, write the register value back to the +* device. Any error returns a negative number. +* +* NOTE: MUST NOT be called from interrupt context. +*/ +int __mdiobus_modify_changed (struct mii_bus *bus,int addr,u32 regnum, +u16 mask,u16 set) +{ +int new, ret; + + ret =__mdiobus_read (bus, addr, regnum); +if (ret <0 ) +return ret; + + new = (ret & ~mask) | set; +if (new == ret) +return 0 ; + + ret =__mdiobus_write (bus, addr, regnum, new); + +return ret <0 ? ret :1 ; +} +EXPORT_SYMBOL_GPL (__mdiobus_modify_changed); +/** * mdiobus_read_nested - Nested version of the mdiobus_read function * @bus: the mii_bus struct
@@ -928,6 +960,29 @@ int mdiobus_write(struct mii_bus *bus, int addr, u32 regnum, u16 val) }EXPORT_SYMBOL (mdiobus_write); +/** +* mdiobus_modify - Convenience function for modifying a given mdio device +* register +* @bus: the mii_bus struct +* @addr: the phy address +* @regnum: register number to write +* @mask: bit mask of bits to clear +* @set: bit mask of bits to set +*/ +int mdiobus_modify (struct mii_bus *bus,int addr,u32 regnum,u16 mask,u16 set) +{ +int err; + +BUG_ON (in_interrupt ()); + +mutex_lock (&bus->mdio_lock); + err =__mdiobus_modify_changed (bus, addr, regnum, mask, set); +mutex_unlock (&bus->mdio_lock); + +return err <0 ? err :0 ; +} +EXPORT_SYMBOL_GPL (mdiobus_modify); +/** * mdio_bus_match - determine if given MDIO driver supports the given * MDIO device
drivers/net/phy/phy-core.c +0 -31
@@ -488,37 +488,6 @@ int phy_write_mmd(struct phy_device *phydev, int devad, u32 regnum, u16 val) }EXPORT_SYMBOL (phy_write_mmd); -/** -* __phy_modify_changed() - Convenience function for modifying a PHY register -* @phydev: a pointer to a &struct phy_device -* @regnum: register number -* @mask: bit mask of bits to clear -* @set: bit mask of bits to set -* -* Unlocked helper function which allows a PHY register to be modified as -* new register value = (old register value & ~mask) | set -* -* Returns negative errno, 0 if there was no change, and 1 in case of change -*/ -int __phy_modify_changed (struct phy_device *phydev,u32 regnum,u16 mask, -u16 set) -{ -int new, ret; - - ret =__phy_read (phydev, regnum); -if (ret <0 ) -return ret; - - new = (ret & ~mask) | set; -if (new == ret) -return 0 ; - - ret =__phy_write (phydev, regnum, new); - -return ret <0 ? ret :1 ; -} -EXPORT_SYMBOL_GPL (__phy_modify_changed); -/** * phy_modify_changed - Function for modifying a PHY register * @phydev: the phy_device struct
include/linux/mdio.h +4 -0
@@ -316,11 +316,15 @@ static inline void mii_10gbt_stat_mod_linkmode_lpa_t(unsigned long *advertising,int __mdiobus_read (struct mii_bus *bus,int addr,u32 regnum);int __mdiobus_write (struct mii_bus *bus,int addr,u32 regnum,u16 val); +int __mdiobus_modify_changed (struct mii_bus *bus,int addr,u32 regnum, +u16 mask,u16 set);int mdiobus_read (struct mii_bus *bus,int addr,u32 regnum);int mdiobus_read_nested (struct mii_bus *bus,int addr,u32 regnum);int mdiobus_write (struct mii_bus *bus,int addr,u32 regnum,u16 val);int mdiobus_write_nested (struct mii_bus *bus,int addr,u32 regnum,u16 val); +int mdiobus_modify (struct mii_bus *bus,int addr,u32 regnum,u16 mask, +u16 set);int mdiobus_register_device (struct mdio_device *mdiodev);int mdiobus_unregister_device (struct mdio_device *mdiodev);
include/linux/phy.h +19 -0
@@ -750,6 +750,25 @@ static inline int __phy_write(struct phy_device *phydev, u32 regnum, u16 val) val); } +/** +* __phy_modify_changed() - Convenience function for modifying a PHY register +* @phydev: a pointer to a &struct phy_device +* @regnum: register number +* @mask: bit mask of bits to clear +* @set: bit mask of bits to set +* +* Unlocked helper function which allows a PHY register to be modified as +* new register value = (old register value & ~mask) | set +* +* Returns negative errno, 0 if there was no change, and 1 in case of change +*/ +static inline int __phy_modify_changed (struct phy_device *phydev,u32 regnum, +u16 mask,u16 set) +{ +return __mdiobus_modify_changed (phydev->mdio.bus, phydev->mdio.addr, + regnum, mask, set); +} +/** * phy_read_mmd - Convenience function for reading a register * from an MMD on a given PHY.
Signature · 1 line
2.20.1
PATCH 2/5 net: phylink: pcs: add 802.3 clause 22 helpers
In reply to Russell King - ARM Linux adminImplement helpers for PCS accessed via the MII bus using 802.3 clause 22 cycles, conforming to 802.3 clause 37 and Cisco SGMII specifications for the advertisement word.
--- drivers/net/phy/phylink.c | 206 ++++++++++++++++++++++++++++++++++++++ include/linux/phylink.h | 6 ++ include/uapi/linux/mii.h | 5 + 3 files changed, 217 insertions(+)
drivers/net/phy/phylink.c +206 -0
@@ -2041,4 +2041,210 @@ void phylink_helper_basex_speed(struct phylink_link_state *state) }EXPORT_SYMBOL_GPL (phylink_helper_basex_speed); +static void phylink_decode_c37_word (struct phylink_link_state *state, +uint16_t config_reg,int speed) +{ +bool tx_pause, rx_pause; +int fd_bit; + +if (speed ==SPEED_2500 ) + fd_bit = ETHTOOL_LINK_MODE_2500baseX_Full_BIT; +else + fd_bit = ETHTOOL_LINK_MODE_1000baseX_Full_BIT; + +mii_lpa_mod_linkmode_x (state->lp_advertising, config_reg, fd_bit); + +if (linkmode_test_bit (fd_bit, state->advertising) && +linkmode_test_bit (fd_bit, state->lp_advertising)) { + state->speed = speed; + state->duplex =DUPLEX_FULL ; + }else { +/* negotiation failure */ + state->link = false; + } + +linkmode_resolve_pause (state->advertising, state->lp_advertising, + &tx_pause, &rx_pause); + +if (tx_pause) + state->pause |=MLO_PAUSE_TX ; +if (rx_pause) + state->pause |=MLO_PAUSE_RX ; +} + +static void phylink_decode_sgmii_word (struct phylink_link_state *state, +uint16_t config_reg) +{ +if (!(config_reg &LPA_SGMII_LINK )) { + state->link = false; +return ; + } + +switch (config_reg &LPA_SGMII_SPD_MASK ) { +case LPA_SGMII_10 : + state->speed =SPEED_10 ; +break ; +case LPA_SGMII_100 : + state->speed =SPEED_100 ; +break ; +case LPA_SGMII_1000 : + state->speed =SPEED_1000 ; +break ; +default : + state->link = false; +return ; + } +if (config_reg &LPA_SGMII_FULL_DUPLEX ) + state->duplex =DUPLEX_FULL ; +else + state->duplex =DUPLEX_HALF ; +} + +/** +* phylink_mii_c22_pcs_get_state() - read the MAC PCS state +* @pcs: a pointer to a &struct mdio_device. +* @state: a pointer to a &struct phylink_link_state. +* +* Helper for MAC PCS supporting the 802.3 clause 22 register set for +* clause 37 negotiation and/or SGMII control. +* +* Read the MAC PCS state from the MII device configured in @config and +* parse the Clause 37 or Cisco SGMII link partner negotiation word into +* the phylink @state structure. This is suitable to be directly plugged +* into the mac_pcs_get_state() member of the struct phylink_mac_ops +* structure. +*/ +void phylink_mii_c22_pcs_get_state (struct mdio_device *pcs, +struct phylink_link_state *state) +{ +struct mii_bus *bus = pcs->bus; +int addr = pcs->addr; +int bmsr, lpa; + + bmsr =mdiobus_read (bus, addr,MII_BMSR ); + lpa =mdiobus_read (bus, addr,MII_LPA ); +if (bmsr <0 || lpa <0 ) { + state->link = false; +return ; + } + + state->link = !!(bmsr &BMSR_LSTATUS ); + state->an_complete = !!(bmsr &BMSR_ANEGCOMPLETE ); +if (!state->link) +return ; + +switch (state->interface) { +case PHY_INTERFACE_MODE_1000BASEX : +phylink_decode_c37_word (state, lpa,SPEED_1000 ); +break ; + +case PHY_INTERFACE_MODE_2500BASEX : +phylink_decode_c37_word (state, lpa,SPEED_2500 ); +break ; + +case PHY_INTERFACE_MODE_SGMII : +phylink_decode_sgmii_word (state, lpa); +break ; + +default : + state->link = false; +break ; + } +} +EXPORT_SYMBOL_GPL (phylink_mii_c22_pcs_get_state); + +/** +* phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS +* advertisement +* @pcs: a pointer to a &struct mdio_device. +* @state: a pointer to the state being configured. +* +* Helper for MAC PCS supporting the 802.3 clause 22 register set for +* clause 37 negotiation and/or SGMII control. +* +* Configure the clause 37 PCS advertisement as specified by @state. This +* does not trigger a renegotiation; phylink will do that via the +* mac_an_restart() method of the struct phylink_mac_ops structure. +* +* Returns negative error code on failure to configure the advertisement, +* zero if no change has been made, or one if the advertisement has changed. +*/ +int phylink_mii_c22_pcs_set_advertisement (struct mdio_device *pcs, +const struct phylink_link_state *state) +{ +struct mii_bus *bus = pcs->bus; +int addr = pcs->addr; +int val, ret; +u16 adv; + +switch (state->interface) { +case PHY_INTERFACE_MODE_1000BASEX : +case PHY_INTERFACE_MODE_2500BASEX : + adv =ADVERTISE_1000XFULL ; +if (linkmode_test_bit (ETHTOOL_LINK_MODE_Pause_BIT, + state->advertising)) + adv |=ADVERTISE_1000XPAUSE ; +if (linkmode_test_bit (ETHTOOL_LINK_MODE_Asym_Pause_BIT, + state->advertising)) + adv |=ADVERTISE_1000XPSE_ASYM ; + + val =mdiobus_read (bus, addr,MII_ADVERTISE ); +if (val <0 ) +return val; + +if (val == adv) +return 0 ; + + ret =mdiobus_write (bus, addr,MII_ADVERTISE , adv); +if (ret <0 ) +return ret; + +return 1 ; + +case PHY_INTERFACE_MODE_SGMII : + val =mdiobus_read (bus, addr,MII_ADVERTISE ); +if (val <0 ) +return val; + +if (val ==0x0001 ) +return 0 ; + + ret =mdiobus_write (bus, addr,MII_ADVERTISE ,0x0001 ); +if (ret <0 ) +return ret; + +return 1 ; + +default : +/* Nothing to do for other modes */ +return 0 ; + } +} +EXPORT_SYMBOL_GPL (phylink_mii_c22_pcs_set_advertisement); + +/** +* phylink_mii_c22_pcs_an_restart() - restart 802.3z autonegotiation +* @pcs: a pointer to a &struct mdio_device. +* +* Helper for MAC PCS supporting the 802.3 clause 22 register set for +* clause 37 negotiation. +* +* Restart the clause 37 negotiation with the link partner. This is +* suitable to be directly plugged into the mac_pcs_get_state() member +* of the struct phylink_mac_ops structure. +*/ +void phylink_mii_c22_pcs_an_restart (struct mdio_device *pcs) +{ +struct mii_bus *bus = pcs->bus; +int val, addr = pcs->addr; + + val =mdiobus_read (bus, addr,MII_BMCR ); +if (val >=0 ) { + val |=BMCR_ANRESTART ; + +mdiobus_write (bus, addr,MII_BMCR , val); + } +} +EXPORT_SYMBOL_GPL (phylink_mii_c22_pcs_an_restart); +MODULE_LICENSE ("GPL v2" );
include/linux/phylink.h +6 -0
@@ -317,4 +317,10 @@ int phylink_mii_ioctl(struct phylink *, struct ifreq *, int);void phylink_set_port_modes (unsigned long *bits);void phylink_helper_basex_speed (struct phylink_link_state *state); +void phylink_mii_c22_pcs_get_state (struct mdio_device *pcs, +struct phylink_link_state *state); +int phylink_mii_c22_pcs_set_advertisement (struct mdio_device *pcs, +const struct phylink_link_state *state); +void phylink_mii_c22_pcs_an_restart (struct mdio_device *pcs); +#endif
include/uapi/linux/mii.h +5 -0
@@ -134,11 +134,16 @@/* MAC and PHY tx_config_Reg[15:0] for SGMII in-band auto-negotiation.*/ #define ADVERTISE_SGMII 0x0001/* MAC can do SGMII */ #define LPA_SGMII 0x0001/* PHY can do SGMII */ +#define LPA_SGMII_SPD_MASK 0x0c00/* SGMII speed mask */ +#define LPA_SGMII_FULL_DUPLEX 0x1000/* SGMII full duplex */ #define LPA_SGMII_DPX_SPD_MASK 0x1C00/* SGMII duplex and speed bits */ +#define LPA_SGMII_10 0x0000/* 10Mbps */ #define LPA_SGMII_10HALF 0x0000/* Can do 10mbps half-duplex */ #define LPA_SGMII_10FULL 0x1000/* Can do 10mbps full-duplex */ +#define LPA_SGMII_100 0x0400/* 100Mbps */ #define LPA_SGMII_100HALF 0x0400/* Can do 100mbps half-duplex */ #define LPA_SGMII_100FULL 0x1400/* Can do 100mbps full-duplex */ +#define LPA_SGMII_1000 0x0800/* 1000Mbps */ #define LPA_SGMII_1000HALF 0x0800/* Can do 1000mbps half-duplex */ #define LPA_SGMII_1000FULL 0x1800/* Can do 1000mbps full-duplex */ #define LPA_SGMII_LINK 0x8000/* PHY link with copper-side partner */
Signature · 1 line
2.20.1
Russell King - ARM Linux admin
maintainercover net: add phylink support for PCS
Depends on "net: mii clause 37 helpers".
This series adds support for IEEE 802.3 register set compliant PCS for phylink. In order to do this, we:
1. add accessors for modifying a MDIO device register, and use them in phylib, rather than duplicating the code from phylib.
2. add support for decoding the advertisement from clause 22 compatible register sets for clause 37 advertisements and SGMII advertisements.
3. add support for clause 45 register sets for 10GBASE-R PCS.
These have been tested on the LX2160A Clearfog-CX platform.
This is a re-post of the series previously sent, but with the first two patches separated out; the conclusion of the discussion with Vladimir seemed to be that there was no issue with the patches themselves.
drivers/net/phy/mdio_bus.c | 55 +++++++++++ drivers/net/phy/phy-core.c | 31 ------ drivers/net/phy/phylink.c | 236 +++++++++++++++++++++++++++++++++++++++++++++ include/linux/mdio.h | 4 + include/linux/phy.h | 19 ++++ include/linux/phylink.h | 8 ++ include/uapi/linux/mii.h | 5 + 7 files changed, 327 insertions(+), 31 deletions(-)
Signature · 2 lines
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/ FTTC broadband for 0.8mile line in suburbia: sync at 10.2Mbps down 587kbps up