Commit 291dcae3 authored by Sean Anderson's avatar Sean Anderson Committed by David S. Miller

net: phylink: Add helpers for c22 registers without MDIO

Some devices expose memory-mapped c22-compliant PHYs. Because these
devices do not have an MDIO bus, we cannot use the existing helpers.
Refactor the existing helpers to allow supplying the values for c22
registers directly, instead of using MDIO to access them. Only get_state
and set_advertisement are converted, since they contain the most complex
logic. Because set_advertisement is never actually used outside
phylink_mii_c22_pcs_config, move the MDIO-writing part into that
function. Because some modes do not need the advertisement register set
at all, we use -EINVAL for this purpose.

Additionally, a new function phylink_pcs_enable_an is provided to
determine whether to enable autonegotiation.
Signed-off-by: default avatarSean Anderson <sean.anderson@seco.com>
Reviewed-by: default avatarRussell King (Oracle) <rmk+kernel@armlinux.org.uk>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 6d872df3
...@@ -2815,31 +2815,22 @@ void phylink_decode_usxgmii_word(struct phylink_link_state *state, ...@@ -2815,31 +2815,22 @@ void phylink_decode_usxgmii_word(struct phylink_link_state *state,
EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word); EXPORT_SYMBOL_GPL(phylink_decode_usxgmii_word);
/** /**
* phylink_mii_c22_pcs_get_state() - read the MAC PCS state * phylink_mii_c22_pcs_decode_state() - Decode MAC PCS state from MII registers
* @pcs: a pointer to a &struct mdio_device.
* @state: a pointer to a &struct phylink_link_state. * @state: a pointer to a &struct phylink_link_state.
* @bmsr: The value of the %MII_BMSR register
* @lpa: The value of the %MII_LPA register
* *
* 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.
* *
* 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
* parse the Clause 37 or Cisco SGMII link partner negotiation word into * the phylink @state structure. This is suitable to be used for implementing
* the phylink @state structure. This is suitable to be directly plugged * the mac_pcs_get_state() member of the struct phylink_mac_ops structure if
* into the mac_pcs_get_state() member of the struct phylink_mac_ops * accessing @bmsr and @lpa cannot be done with MDIO directly.
* structure.
*/ */
void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
struct phylink_link_state *state) u16 bmsr, u16 lpa)
{ {
int bmsr, lpa;
bmsr = mdiodev_read(pcs, MII_BMSR);
lpa = mdiodev_read(pcs, MII_LPA);
if (bmsr < 0 || lpa < 0) {
state->link = false;
return;
}
state->link = !!(bmsr & BMSR_LSTATUS); state->link = !!(bmsr & BMSR_LSTATUS);
state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE); state->an_complete = !!(bmsr & BMSR_ANEGCOMPLETE);
/* If there is no link or autonegotiation is disabled, the LP advertisement /* If there is no link or autonegotiation is disabled, the LP advertisement
...@@ -2867,28 +2858,54 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs, ...@@ -2867,28 +2858,54 @@ void phylink_mii_c22_pcs_get_state(struct mdio_device *pcs,
break; break;
} }
} }
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_decode_state);
/**
* 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)
{
int bmsr, lpa;
bmsr = mdiodev_read(pcs, MII_BMSR);
lpa = mdiodev_read(pcs, MII_LPA);
if (bmsr < 0 || lpa < 0) {
state->link = false;
return;
}
phylink_mii_c22_pcs_decode_state(state, bmsr, lpa);
}
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state); EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_get_state);
/** /**
* phylink_mii_c22_pcs_set_advertisement() - configure the clause 37 PCS * phylink_mii_c22_pcs_encode_advertisement() - configure the clause 37 PCS
* advertisement * advertisement
* @pcs: a pointer to a &struct mdio_device.
* @interface: the PHY interface mode being configured * @interface: the PHY interface mode being configured
* @advertising: the ethtool advertisement mask * @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.
* *
* Configure the clause 37 PCS advertisement as specified by @state. This * Encode the clause 37 PCS advertisement as specified by @interface and
* does not trigger a renegotiation; phylink will do that via the * @advertising.
* mac_an_restart() method of the struct phylink_mac_ops structure.
* *
* Returns negative error code on failure to configure the advertisement, * Return: The new value for @adv, or ``-EINVAL`` if it should not be 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_encode_advertisement(phy_interface_t interface,
phy_interface_t interface, const unsigned long *advertising)
const unsigned long *advertising)
{ {
u16 adv; u16 adv;
...@@ -2902,18 +2919,15 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs, ...@@ -2902,18 +2919,15 @@ int phylink_mii_c22_pcs_set_advertisement(struct mdio_device *pcs,
if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
advertising)) advertising))
adv |= ADVERTISE_1000XPSE_ASYM; adv |= ADVERTISE_1000XPSE_ASYM;
return adv;
return mdiodev_modify_changed(pcs, MII_ADVERTISE, 0xffff, adv);
case PHY_INTERFACE_MODE_SGMII: case PHY_INTERFACE_MODE_SGMII:
return mdiodev_modify_changed(pcs, MII_ADVERTISE, 0xffff, 0x0001); return 0x0001;
default: default:
/* Nothing to do for other modes */ /* Nothing to do for other modes */
return 0; return -EINVAL;
} }
} }
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_set_advertisement); EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_encode_advertisement);
/** /**
* phylink_mii_c22_pcs_config() - configure clause 22 PCS * phylink_mii_c22_pcs_config() - configure clause 22 PCS
...@@ -2931,16 +2945,18 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, ...@@ -2931,16 +2945,18 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode,
phy_interface_t interface, phy_interface_t interface,
const unsigned long *advertising) const unsigned long *advertising)
{ {
bool changed; bool changed = 0;
u16 bmcr; u16 bmcr;
int ret; int ret, adv;
ret = phylink_mii_c22_pcs_set_advertisement(pcs, interface, adv = phylink_mii_c22_pcs_encode_advertisement(interface, advertising);
advertising); if (adv >= 0) {
if (ret < 0) ret = mdiobus_modify_changed(pcs->bus, pcs->addr,
return ret; MII_ADVERTISE, 0xffff, adv);
if (ret < 0)
changed = ret > 0; return ret;
changed = ret;
}
/* Ensure ISOLATE bit is disabled */ /* Ensure ISOLATE bit is disabled */
if (mode == MLO_AN_INBAND && if (mode == MLO_AN_INBAND &&
...@@ -2953,7 +2969,7 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, ...@@ -2953,7 +2969,7 @@ int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode,
if (ret < 0) if (ret < 0)
return ret; return ret;
return changed ? 1 : 0; return changed;
} }
EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config); EXPORT_SYMBOL_GPL(phylink_mii_c22_pcs_config);
......
...@@ -527,11 +527,12 @@ void phylink_set_port_modes(unsigned long *bits); ...@@ -527,11 +527,12 @@ void phylink_set_port_modes(unsigned long *bits);
void phylink_set_10g_modes(unsigned long *mask); void phylink_set_10g_modes(unsigned long *mask);
void phylink_helper_basex_speed(struct phylink_link_state *state); void phylink_helper_basex_speed(struct phylink_link_state *state);
void phylink_mii_c22_pcs_decode_state(struct phylink_link_state *state,
u16 bmsr, u16 lpa);
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_encode_advertisement(phy_interface_t interface,
phy_interface_t interface, const unsigned long *advertising);
const unsigned long *advertising);
int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode, int phylink_mii_c22_pcs_config(struct mdio_device *pcs, unsigned int mode,
phy_interface_t interface, phy_interface_t interface,
const unsigned long *advertising); const unsigned long *advertising);
......
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