net: phylink: resolve fixed link flow control
Resolve the fixed link flow control using the recently introduced linkmode_resolve_pause() helper, which we use in phylink_get_fixed_state() only when operating in full duplex mode. Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk> Reviewed-by: Andrew Lunn <andrew@lunn.ch> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: hongrongxuan <hongrongxuan@huawei.com>
This commit is contained in:
parent
9dce982e61
commit
6b1f64e2fd
|
@ -178,9 +178,11 @@ static int phylink_parse_fixedlink(struct phylink *pl,
|
||||||
/* We treat the "pause" and "asym-pause" terminology as
|
/* We treat the "pause" and "asym-pause" terminology as
|
||||||
* defining the link partner's ability. */
|
* defining the link partner's ability. */
|
||||||
if (fwnode_property_read_bool(fixed_node, "pause"))
|
if (fwnode_property_read_bool(fixed_node, "pause"))
|
||||||
pl->link_config.pause |= MLO_PAUSE_SYM;
|
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||||
|
pl->link_config.lp_advertising);
|
||||||
if (fwnode_property_read_bool(fixed_node, "asym-pause"))
|
if (fwnode_property_read_bool(fixed_node, "asym-pause"))
|
||||||
pl->link_config.pause |= MLO_PAUSE_ASYM;
|
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||||
|
pl->link_config.lp_advertising);
|
||||||
|
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
desc = fwnode_get_named_gpiod(fixed_node, "link-gpios",
|
desc = fwnode_get_named_gpiod(fixed_node, "link-gpios",
|
||||||
|
@ -212,9 +214,11 @@ static int phylink_parse_fixedlink(struct phylink *pl,
|
||||||
DUPLEX_FULL : DUPLEX_HALF;
|
DUPLEX_FULL : DUPLEX_HALF;
|
||||||
pl->link_config.speed = prop[2];
|
pl->link_config.speed = prop[2];
|
||||||
if (prop[3])
|
if (prop[3])
|
||||||
pl->link_config.pause |= MLO_PAUSE_SYM;
|
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
|
||||||
|
pl->link_config.lp_advertising);
|
||||||
if (prop[4])
|
if (prop[4])
|
||||||
pl->link_config.pause |= MLO_PAUSE_ASYM;
|
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
|
||||||
|
pl->link_config.lp_advertising);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -341,6 +345,22 @@ static void phylink_apply_manual_flow(struct phylink *pl,
|
||||||
state->pause = pl->link_config.pause;
|
state->pause = pl->link_config.pause;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void phylink_resolve_flow(struct phylink_link_state *state)
|
||||||
|
{
|
||||||
|
bool tx_pause, rx_pause;
|
||||||
|
|
||||||
|
state->pause = MLO_PAUSE_NONE;
|
||||||
|
if (state->duplex == DUPLEX_FULL) {
|
||||||
|
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_mac_config(struct phylink *pl,
|
static void phylink_mac_config(struct phylink *pl,
|
||||||
const struct phylink_link_state *state)
|
const struct phylink_link_state *state)
|
||||||
{
|
{
|
||||||
|
@ -389,44 +409,16 @@ static int phylink_get_mac_state(struct phylink *pl, struct phylink_link_state *
|
||||||
/* The fixed state is... fixed except for the link state,
|
/* The fixed state is... fixed except for the link state,
|
||||||
* which may be determined by a GPIO or a callback.
|
* which may be determined by a GPIO or a callback.
|
||||||
*/
|
*/
|
||||||
static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_state *state)
|
static void phylink_get_fixed_state(struct phylink *pl,
|
||||||
|
struct phylink_link_state *state)
|
||||||
{
|
{
|
||||||
*state = pl->link_config;
|
*state = pl->link_config;
|
||||||
if (pl->get_fixed_state)
|
if (pl->get_fixed_state)
|
||||||
pl->get_fixed_state(pl->netdev, state);
|
pl->get_fixed_state(pl->netdev, state);
|
||||||
else if (pl->link_gpio)
|
else if (pl->link_gpio)
|
||||||
state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
|
state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
|
||||||
}
|
|
||||||
|
|
||||||
/* Flow control is resolved according to our and the link partners
|
phylink_resolve_flow(state);
|
||||||
* advertisements using the following drawn from the 802.3 specs:
|
|
||||||
* Local device Link partner
|
|
||||||
* Pause AsymDir Pause AsymDir Result
|
|
||||||
* 1 X 1 X TX+RX
|
|
||||||
* 0 1 1 1 TX
|
|
||||||
* 1 1 0 1 RX
|
|
||||||
*/
|
|
||||||
static void phylink_resolve_flow(struct phylink *pl,
|
|
||||||
struct phylink_link_state *state)
|
|
||||||
{
|
|
||||||
int new_pause = 0;
|
|
||||||
int pause = 0;
|
|
||||||
|
|
||||||
if (phylink_test(pl->link_config.advertising, Pause))
|
|
||||||
pause |= MLO_PAUSE_SYM;
|
|
||||||
if (phylink_test(pl->link_config.advertising, Asym_Pause))
|
|
||||||
pause |= MLO_PAUSE_ASYM;
|
|
||||||
|
|
||||||
pause &= state->pause;
|
|
||||||
|
|
||||||
if (pause & MLO_PAUSE_SYM)
|
|
||||||
new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
|
|
||||||
else if (pause & MLO_PAUSE_ASYM)
|
|
||||||
new_pause = state->pause & MLO_PAUSE_SYM ?
|
|
||||||
MLO_PAUSE_TX : MLO_PAUSE_RX;
|
|
||||||
|
|
||||||
state->pause &= ~MLO_PAUSE_TXRX_MASK;
|
|
||||||
state->pause |= new_pause;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *phylink_pause_to_str(int pause)
|
static const char *phylink_pause_to_str(int pause)
|
||||||
|
@ -1352,8 +1344,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
|
||||||
pause->rx_pause != pause->tx_pause)
|
pause->rx_pause != pause->tx_pause)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK);
|
config->pause = 0;
|
||||||
|
|
||||||
if (pause->autoneg)
|
if (pause->autoneg)
|
||||||
config->pause |= MLO_PAUSE_AN;
|
config->pause |= MLO_PAUSE_AN;
|
||||||
if (pause->rx_pause)
|
if (pause->rx_pause)
|
||||||
|
@ -1464,13 +1455,14 @@ static int phylink_mii_emul_read(unsigned int reg,
|
||||||
struct phylink_link_state *state)
|
struct phylink_link_state *state)
|
||||||
{
|
{
|
||||||
struct fixed_phy_status fs;
|
struct fixed_phy_status fs;
|
||||||
|
unsigned long *lpa = state->lp_advertising;
|
||||||
int val;
|
int val;
|
||||||
|
|
||||||
fs.link = state->link;
|
fs.link = state->link;
|
||||||
fs.speed = state->speed;
|
fs.speed = state->speed;
|
||||||
fs.duplex = state->duplex;
|
fs.duplex = state->duplex;
|
||||||
fs.pause = state->pause & MLO_PAUSE_SYM;
|
fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa);
|
||||||
fs.asym_pause = state->pause & MLO_PAUSE_ASYM;
|
fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa);
|
||||||
|
|
||||||
val = swphy_read_reg(reg, &fs);
|
val = swphy_read_reg(reg, &fs);
|
||||||
if (reg == MII_BMSR) {
|
if (reg == MII_BMSR) {
|
||||||
|
|
|
@ -12,12 +12,10 @@ struct net_device;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MLO_PAUSE_NONE,
|
MLO_PAUSE_NONE,
|
||||||
MLO_PAUSE_ASYM = BIT(0),
|
MLO_PAUSE_RX = BIT(0),
|
||||||
MLO_PAUSE_SYM = BIT(1),
|
MLO_PAUSE_TX = BIT(1),
|
||||||
MLO_PAUSE_RX = BIT(2),
|
|
||||||
MLO_PAUSE_TX = BIT(3),
|
|
||||||
MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX,
|
MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX,
|
||||||
MLO_PAUSE_AN = BIT(4),
|
MLO_PAUSE_AN = BIT(2),
|
||||||
|
|
||||||
MLO_AN_PHY = 0, /* Conventional PHY */
|
MLO_AN_PHY = 0, /* Conventional PHY */
|
||||||
MLO_AN_FIXED, /* Fixed-link mode */
|
MLO_AN_FIXED, /* Fixed-link mode */
|
||||||
|
|
Loading…
Reference in New Issue