Commit 2d39eab4 authored by David S. Miller's avatar David S. Miller

Merge branch 'split-phylink-PCS-operations'

Russell King says:

====================
split phylink PCS operations

This series splits the phylink_mac_ops structure so that PCS can be
supported separately with their own PCS operations, separating them
from the MAC layer.  This may need adaption later as more users come
along.

v2: change pcs_config() and associated called function prototypes to
only pass the information that is required, and add some documention.

v3: change phylink_create() prototype
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents b8447abc 4c0d6d3a
...@@ -40,7 +40,8 @@ enum { ...@@ -40,7 +40,8 @@ enum {
struct phylink { struct phylink {
/* private: */ /* private: */
struct net_device *netdev; struct net_device *netdev;
const struct phylink_mac_ops *ops; const struct phylink_mac_ops *mac_ops;
const struct phylink_pcs_ops *pcs_ops;
struct phylink_config *config; struct phylink_config *config;
struct device *dev; struct device *dev;
unsigned int old_link_state:1; unsigned int old_link_state:1;
...@@ -154,7 +155,7 @@ static const char *phylink_an_mode_str(unsigned int mode) ...@@ -154,7 +155,7 @@ static const char *phylink_an_mode_str(unsigned int mode)
static int phylink_validate(struct phylink *pl, unsigned long *supported, static int phylink_validate(struct phylink *pl, unsigned long *supported,
struct phylink_link_state *state) 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; return phylink_is_empty_linkmode(supported) ? -EINVAL : 0;
} }
...@@ -415,7 +416,7 @@ static void phylink_mac_config(struct phylink *pl, ...@@ -415,7 +416,7 @@ static void phylink_mac_config(struct phylink *pl,
__ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising, __ETHTOOL_LINK_MODE_MASK_NBITS, state->advertising,
state->pause, state->link, state->an_enabled); 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, static void phylink_mac_config_up(struct phylink *pl,
...@@ -425,11 +426,32 @@ static void phylink_mac_config_up(struct phylink *pl, ...@@ -425,11 +426,32 @@ static void phylink_mac_config_up(struct phylink *pl,
phylink_mac_config(pl, state); 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 && if (pl->link_config.an_enabled &&
phy_interface_mode_is_8023z(pl->link_config.interface)) phy_interface_mode_is_8023z(pl->link_config.interface)) {
pl->ops->mac_an_restart(pl->config); 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->interface,
state->advertising))
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, static void phylink_mac_pcs_get_state(struct phylink *pl,
...@@ -445,7 +467,10 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, ...@@ -445,7 +467,10 @@ static void phylink_mac_pcs_get_state(struct phylink *pl,
state->an_complete = 0; state->an_complete = 0;
state->link = 1; state->link = 1;
pl->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, /* The fixed state is... fixed except for the link state,
...@@ -463,7 +488,7 @@ static void phylink_get_fixed_state(struct phylink *pl, ...@@ -463,7 +488,7 @@ static void phylink_get_fixed_state(struct phylink *pl,
phylink_resolve_flow(state); 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; struct phylink_link_state link_state;
...@@ -489,7 +514,7 @@ static void phylink_mac_initial_config(struct phylink *pl) ...@@ -489,7 +514,7 @@ static void phylink_mac_initial_config(struct phylink *pl)
link_state.link = false; link_state.link = false;
phylink_apply_manual_flow(pl, &link_state); 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) static const char *phylink_pause_to_str(int pause)
...@@ -506,13 +531,19 @@ static const char *phylink_pause_to_str(int pause) ...@@ -506,13 +531,19 @@ static const char *phylink_pause_to_str(int pause)
} }
} }
static void phylink_mac_link_up(struct phylink *pl, static void phylink_link_up(struct phylink *pl,
struct phylink_link_state link_state) struct phylink_link_state link_state)
{ {
struct net_device *ndev = pl->netdev; struct net_device *ndev = pl->netdev;
pl->cur_interface = link_state.interface; pl->cur_interface = link_state.interface;
pl->ops->mac_link_up(pl->config, pl->phydev,
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, pl->cur_link_an_mode, pl->cur_interface,
link_state.speed, link_state.duplex, link_state.speed, link_state.duplex,
!!(link_state.pause & MLO_PAUSE_TX), !!(link_state.pause & MLO_PAUSE_TX),
...@@ -528,13 +559,13 @@ static void phylink_mac_link_up(struct phylink *pl, ...@@ -528,13 +559,13 @@ static void phylink_mac_link_up(struct phylink *pl,
phylink_pause_to_str(link_state.pause)); 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; struct net_device *ndev = pl->netdev;
if (ndev) if (ndev)
netif_carrier_off(ndev); netif_carrier_off(ndev);
pl->ops->mac_link_down(pl->config, pl->cur_link_an_mode, pl->mac_ops->mac_link_down(pl->config, pl->cur_link_an_mode,
pl->cur_interface); pl->cur_interface);
phylink_info(pl, "Link is Down\n"); phylink_info(pl, "Link is Down\n");
} }
...@@ -597,9 +628,9 @@ static void phylink_resolve(struct work_struct *w) ...@@ -597,9 +628,9 @@ static void phylink_resolve(struct work_struct *w)
if (link_changed) { if (link_changed) {
pl->old_link_state = link_state.link; pl->old_link_state = link_state.link;
if (!link_state.link) if (!link_state.link)
phylink_mac_link_down(pl); phylink_link_down(pl);
else else
phylink_mac_link_up(pl, link_state); phylink_link_up(pl, link_state);
} }
if (!link_state.link && pl->mac_link_dropped) { if (!link_state.link && pl->mac_link_dropped) {
pl->mac_link_dropped = false; pl->mac_link_dropped = false;
...@@ -666,7 +697,7 @@ static int phylink_register_sfp(struct phylink *pl, ...@@ -666,7 +697,7 @@ static int phylink_register_sfp(struct phylink *pl,
* @fwnode: a pointer to a &struct fwnode_handle describing the network * @fwnode: a pointer to a &struct fwnode_handle describing the network
* interface * interface
* @iface: the desired link mode defined by &typedef phy_interface_t * @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. * Create a new phylink instance, and parse the link parameters found in @np.
* This will parse in-band modes, fixed-link or SFP configuration. * This will parse in-band modes, fixed-link or SFP configuration.
...@@ -679,7 +710,7 @@ static int phylink_register_sfp(struct phylink *pl, ...@@ -679,7 +710,7 @@ static int phylink_register_sfp(struct phylink *pl,
struct phylink *phylink_create(struct phylink_config *config, struct phylink *phylink_create(struct phylink_config *config,
struct fwnode_handle *fwnode, struct fwnode_handle *fwnode,
phy_interface_t iface, phy_interface_t iface,
const struct phylink_mac_ops *ops) const struct phylink_mac_ops *mac_ops)
{ {
struct phylink *pl; struct phylink *pl;
int ret; int ret;
...@@ -712,7 +743,7 @@ struct phylink *phylink_create(struct phylink_config *config, ...@@ -712,7 +743,7 @@ struct phylink *phylink_create(struct phylink_config *config,
pl->link_config.speed = SPEED_UNKNOWN; pl->link_config.speed = SPEED_UNKNOWN;
pl->link_config.duplex = DUPLEX_UNKNOWN; pl->link_config.duplex = DUPLEX_UNKNOWN;
pl->link_config.an_enabled = true; pl->link_config.an_enabled = true;
pl->ops = ops; pl->mac_ops = mac_ops;
__set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state); __set_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
timer_setup(&pl->link_poll, phylink_fixed_poll, 0); timer_setup(&pl->link_poll, phylink_fixed_poll, 0);
...@@ -746,6 +777,12 @@ struct phylink *phylink_create(struct phylink_config *config, ...@@ -746,6 +777,12 @@ struct phylink *phylink_create(struct phylink_config *config,
} }
EXPORT_SYMBOL_GPL(phylink_create); 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 * phylink_destroy() - cleanup and destroy the phylink instance
* @pl: a pointer to a &struct phylink returned from phylink_create() * @pl: a pointer to a &struct phylink returned from phylink_create()
...@@ -1082,14 +1119,12 @@ void phylink_start(struct phylink *pl) ...@@ -1082,14 +1119,12 @@ void phylink_start(struct phylink *pl)
/* Apply the link configuration to the MAC when starting. This allows /* Apply the link configuration to the MAC when starting. This allows
* a fixed-link to start with the correct parameters, and also * a fixed-link to start with the correct parameters, and also
* ensures that we set the appropriate advertisement for Serdes links. * 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 * parameters are properly negotiated. This is necessary for DSA
* switches using 802.3z negotiation to ensure they see our modes. * 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); clear_bit(PHYLINK_DISABLE_STOPPED, &pl->phylink_disable_state);
phylink_run_resolve(pl); phylink_run_resolve(pl);
...@@ -1386,8 +1421,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl, ...@@ -1386,8 +1421,7 @@ int phylink_ethtool_ksettings_set(struct phylink *pl,
* advertisement; the only thing we have is the pause * advertisement; the only thing we have is the pause
* modes which can only come from a PHY. * modes which can only come from a PHY.
*/ */
phylink_mac_config(pl, &pl->link_config); phylink_pcs_config(pl, true, &pl->link_config);
phylink_mac_an_restart(pl);
} }
mutex_unlock(&pl->state_mutex); mutex_unlock(&pl->state_mutex);
} }
...@@ -1415,7 +1449,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl) ...@@ -1415,7 +1449,7 @@ int phylink_ethtool_nway_reset(struct phylink *pl)
if (pl->phydev) if (pl->phydev)
ret = phy_restart_aneg(pl->phydev); ret = phy_restart_aneg(pl->phydev);
phylink_mac_an_restart(pl); phylink_mac_pcs_an_restart(pl);
return ret; return ret;
} }
...@@ -1494,8 +1528,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, ...@@ -1494,8 +1528,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
pause->tx_pause); pause->tx_pause);
} else if (!test_bit(PHYLINK_DISABLE_STOPPED, } else if (!test_bit(PHYLINK_DISABLE_STOPPED,
&pl->phylink_disable_state)) { &pl->phylink_disable_state)) {
phylink_mac_config(pl, &pl->link_config); phylink_pcs_config(pl, true, &pl->link_config);
phylink_mac_an_restart(pl);
} }
mutex_unlock(&pl->state_mutex); mutex_unlock(&pl->state_mutex);
...@@ -1901,7 +1934,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode, ...@@ -1901,7 +1934,7 @@ static int phylink_sfp_config(struct phylink *pl, u8 mode,
if (changed && !test_bit(PHYLINK_DISABLE_STOPPED, if (changed && !test_bit(PHYLINK_DISABLE_STOPPED,
&pl->phylink_disable_state)) &pl->phylink_disable_state))
phylink_mac_initial_config(pl); phylink_mac_initial_config(pl, false);
return ret; return ret;
} }
...@@ -2184,7 +2217,8 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); ...@@ -2184,7 +2217,8 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state);
* phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS * phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS
* advertisement * advertisement
* @pcs: a pointer to a &struct mdio_device. * @pcs: a pointer to a &struct mdio_device.
* @state: a pointer to the state being configured. * @interface: the PHY interface mode being configured
* @advertising: the ethtool advertisement mask
* *
* Helper for MAC PCS supporting the 802.3 clause 22 register set for * Helper for MAC PCS supporting the 802.3 clause 22 register set for
* clause 37 negotiation and/or SGMII control. * clause 37 negotiation and/or SGMII control.
...@@ -2197,22 +2231,23 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); ...@@ -2197,22 +2231,23 @@ EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state);
* zero if no change has been made, or one if the advertisement has changed. * 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, int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,
const struct phylink_link_state *state) phy_interface_t interface,
const unsigned long *advertising)
{ {
struct mii_bus *bus = pcs->bus; struct mii_bus *bus = pcs->bus;
int addr = pcs->addr; int addr = pcs->addr;
int val, ret; int val, ret;
u16 adv; u16 adv;
switch (state->interface) { switch (interface) {
case PHY_INTERFACE_MODE_1000BASEX: case PHY_INTERFACE_MODE_1000BASEX:
case PHY_INTERFACE_MODE_2500BASEX: case PHY_INTERFACE_MODE_2500BASEX:
adv = ADVERTISE_1000XFULL; adv = ADVERTISE_1000XFULL;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
state->advertising)) advertising))
adv |= ADVERTISE_1000XPAUSE; adv |= ADVERTISE_1000XPAUSE;
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
state->advertising)) advertising))
adv |= ADVERTISE_1000XPSE_ASYM; adv |= ADVERTISE_1000XPSE_ASYM;
val = mdiobus_read(bus, addr, MII_ADVERTISE); val = mdiobus_read(bus, addr, MII_ADVERTISE);
......
...@@ -270,9 +270,97 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy, ...@@ -270,9 +270,97 @@ void mac_link_up(struct phylink_config *config, struct phy_device *phy,
int speed, int duplex, bool tx_pause, bool rx_pause); int speed, int duplex, bool tx_pause, bool rx_pause);
#endif #endif
/**
* struct phylink_pcs_ops - MAC PCS operations structure.
* @pcs_get_state: read the current MAC PCS link state from the hardware.
* @pcs_config: configure the MAC PCS for the selected mode and state.
* @pcs_an_restart: restart 802.3z BaseX autonegotiation.
* @pcs_link_up: program the PCS for the resolved link configuration
* (where necessary).
*/
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,
phy_interface_t interface,
const unsigned long *advertising);
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. */
/**
* pcs_get_state() - Read the current inband link state from the hardware
* @config: a pointer to a &struct phylink_config.
* @state: a pointer to a &struct phylink_link_state.
*
* Read the current inband link state from the MAC PCS, reporting the
* current speed in @state->speed, duplex mode in @state->duplex, pause
* mode in @state->pause using the %MLO_PAUSE_RX and %MLO_PAUSE_TX bits,
* negotiation completion state in @state->an_complete, and link up state
* in @state->link. If possible, @state->lp_advertising should also be
* populated.
*
* When present, this overrides mac_pcs_get_state() in &struct
* phylink_mac_ops.
*/
void pcs_get_state(struct phylink_config *config,
struct phylink_link_state *state);
/**
* pcs_config() - Configure the PCS mode and advertisement
* @config: a pointer to a &struct phylink_config.
* @mode: one of %MLO_AN_FIXED, %MLO_AN_PHY, %MLO_AN_INBAND.
* @interface: interface mode to be used
* @advertising: adertisement ethtool link mode mask
*
* Configure the PCS for the operating mode, the interface mode, and set
* the advertisement mask.
*
* When operating in %MLO_AN_INBAND, inband should always be enabled,
* otherwise inband should be disabled.
*
* For SGMII, there is no advertisement from the MAC side, the PCS should
* be programmed to acknowledge the inband word from the PHY.
*
* For 1000BASE-X, the advertisement should be programmed into the PCS.
*
* For most 10GBASE-R, there is no advertisement.
*/
int (*pcs_config)(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, const unsigned long *advertising);
/**
* pcs_an_restart() - restart 802.3z BaseX autonegotiation
* @config: a pointer to a &struct phylink_config.
*
* When PCS ops are present, this overrides mac_an_restart() in &struct
* phylink_mac_ops.
*/
void (*pcs_an_restart)(struct phylink_config *config);
/**
* pcs_link_up() - program the PCS for the resolved link configuration
* @config: a pointer to a &struct phylink_config.
* @mode: link autonegotiation mode
* @interface: link &typedef phy_interface_t mode
* @speed: link speed
* @duplex: link duplex
*
* This call will be made just before mac_link_up() to inform the PCS of
* the resolved link parameters. For example, a PCS operating in SGMII
* mode without in-band AN needs to be manually configured for the link
* and duplex setting. Otherwise, this should be a no-op.
*/
void (*pcs_link_up)(struct phylink_config *config, unsigned int mode,
phy_interface_t interface, int speed, int duplex);
#endif
struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *, struct phylink *phylink_create(struct phylink_config *, struct fwnode_handle *,
phy_interface_t iface, phy_interface_t iface,
const struct phylink_mac_ops *ops); const struct phylink_mac_ops *mac_ops);
void phylink_add_pcs(struct phylink *, const struct phylink_pcs_ops *ops);
void phylink_destroy(struct phylink *); void phylink_destroy(struct phylink *);
int phylink_connect_phy(struct phylink *, struct phy_device *); int phylink_connect_phy(struct phylink *, struct phy_device *);
...@@ -320,7 +408,8 @@ void phylink_helper_basex_speed(struct phylink_link_state *state); ...@@ -320,7 +408,8 @@ void phylink_helper_basex_speed(struct phylink_link_state *state);
void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
struct phylink_link_state *state); struct phylink_link_state *state);
int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,
const struct phylink_link_state *state); phy_interface_t interface,
const unsigned long *advertising);
void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs); void phylink_mii_c22_pcs_an_restart(struct mdio_device *pcs);
void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs, void phylink_mii_c45_pcs_get_state(struct mdio_device *pcs,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment