Skip to content

Commit 4e5aeb4

Browse files
Russell Kingdavem330
authored andcommitted
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>
1 parent 33faac8 commit 4e5aeb4

File tree

2 files changed

+34
-44
lines changed

2 files changed

+34
-44
lines changed

drivers/net/phy/phylink.c

Lines changed: 31 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,11 @@ static int phylink_parse_fixedlink(struct phylink *pl,
181181
/* We treat the "pause" and "asym-pause" terminology as
182182
* defining the link partner's ability. */
183183
if (fwnode_property_read_bool(fixed_node, "pause"))
184-
pl->link_config.pause |= MLO_PAUSE_SYM;
184+
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
185+
pl->link_config.lp_advertising);
185186
if (fwnode_property_read_bool(fixed_node, "asym-pause"))
186-
pl->link_config.pause |= MLO_PAUSE_ASYM;
187+
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
188+
pl->link_config.lp_advertising);
187189

188190
if (ret == 0) {
189191
desc = fwnode_gpiod_get_index(fixed_node, "link", 0,
@@ -215,9 +217,11 @@ static int phylink_parse_fixedlink(struct phylink *pl,
215217
DUPLEX_FULL : DUPLEX_HALF;
216218
pl->link_config.speed = prop[2];
217219
if (prop[3])
218-
pl->link_config.pause |= MLO_PAUSE_SYM;
220+
__set_bit(ETHTOOL_LINK_MODE_Pause_BIT,
221+
pl->link_config.lp_advertising);
219222
if (prop[4])
220-
pl->link_config.pause |= MLO_PAUSE_ASYM;
223+
__set_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT,
224+
pl->link_config.lp_advertising);
221225
}
222226
}
223227

@@ -351,6 +355,22 @@ static void phylink_apply_manual_flow(struct phylink *pl,
351355
state->pause = pl->link_config.pause;
352356
}
353357

358+
static void phylink_resolve_flow(struct phylink_link_state *state)
359+
{
360+
bool tx_pause, rx_pause;
361+
362+
state->pause = MLO_PAUSE_NONE;
363+
if (state->duplex == DUPLEX_FULL) {
364+
linkmode_resolve_pause(state->advertising,
365+
state->lp_advertising,
366+
&tx_pause, &rx_pause);
367+
if (tx_pause)
368+
state->pause |= MLO_PAUSE_TX;
369+
if (rx_pause)
370+
state->pause |= MLO_PAUSE_RX;
371+
}
372+
}
373+
354374
static void phylink_mac_config(struct phylink *pl,
355375
const struct phylink_link_state *state)
356376
{
@@ -399,44 +419,16 @@ static void phylink_mac_pcs_get_state(struct phylink *pl,
399419
/* The fixed state is... fixed except for the link state,
400420
* which may be determined by a GPIO or a callback.
401421
*/
402-
static void phylink_get_fixed_state(struct phylink *pl, struct phylink_link_state *state)
422+
static void phylink_get_fixed_state(struct phylink *pl,
423+
struct phylink_link_state *state)
403424
{
404425
*state = pl->link_config;
405426
if (pl->get_fixed_state)
406427
pl->get_fixed_state(pl->netdev, state);
407428
else if (pl->link_gpio)
408429
state->link = !!gpiod_get_value_cansleep(pl->link_gpio);
409-
}
410430

411-
/* Flow control is resolved according to our and the link partners
412-
* advertisements using the following drawn from the 802.3 specs:
413-
* Local device Link partner
414-
* Pause AsymDir Pause AsymDir Result
415-
* 1 X 1 X TX+RX
416-
* 0 1 1 1 TX
417-
* 1 1 0 1 RX
418-
*/
419-
static void phylink_resolve_flow(struct phylink *pl,
420-
struct phylink_link_state *state)
421-
{
422-
int new_pause = 0;
423-
int pause = 0;
424-
425-
if (phylink_test(pl->link_config.advertising, Pause))
426-
pause |= MLO_PAUSE_SYM;
427-
if (phylink_test(pl->link_config.advertising, Asym_Pause))
428-
pause |= MLO_PAUSE_ASYM;
429-
430-
pause &= state->pause;
431-
432-
if (pause & MLO_PAUSE_SYM)
433-
new_pause = MLO_PAUSE_TX | MLO_PAUSE_RX;
434-
else if (pause & MLO_PAUSE_ASYM)
435-
new_pause = state->pause & MLO_PAUSE_SYM ?
436-
MLO_PAUSE_TX : MLO_PAUSE_RX;
437-
438-
state->pause &= ~MLO_PAUSE_TXRX_MASK;
439-
state->pause |= new_pause;
431+
phylink_resolve_flow(state);
440432
}
441433

442434
static const char *phylink_pause_to_str(int pause)
@@ -1393,8 +1385,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl,
13931385
!pause->autoneg && pause->rx_pause != pause->tx_pause)
13941386
return -EINVAL;
13951387

1396-
config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK);
1397-
1388+
config->pause = 0;
13981389
if (pause->autoneg)
13991390
config->pause |= MLO_PAUSE_AN;
14001391
if (pause->rx_pause)
@@ -1505,13 +1496,14 @@ static int phylink_mii_emul_read(unsigned int reg,
15051496
struct phylink_link_state *state)
15061497
{
15071498
struct fixed_phy_status fs;
1499+
unsigned long *lpa = state->lp_advertising;
15081500
int val;
15091501

15101502
fs.link = state->link;
15111503
fs.speed = state->speed;
15121504
fs.duplex = state->duplex;
1513-
fs.pause = state->pause & MLO_PAUSE_SYM;
1514-
fs.asym_pause = state->pause & MLO_PAUSE_ASYM;
1505+
fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa);
1506+
fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa);
15151507

15161508
val = swphy_read_reg(reg, &fs);
15171509
if (reg == MII_BMSR) {

include/linux/phylink.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,10 @@ struct net_device;
1212

1313
enum {
1414
MLO_PAUSE_NONE,
15-
MLO_PAUSE_ASYM = BIT(0),
16-
MLO_PAUSE_SYM = BIT(1),
17-
MLO_PAUSE_RX = BIT(2),
18-
MLO_PAUSE_TX = BIT(3),
15+
MLO_PAUSE_RX = BIT(0),
16+
MLO_PAUSE_TX = BIT(1),
1917
MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX,
20-
MLO_PAUSE_AN = BIT(4),
18+
MLO_PAUSE_AN = BIT(2),
2119

2220
MLO_AN_PHY = 0, /* Conventional PHY */
2321
MLO_AN_FIXED, /* Fixed-link mode */

0 commit comments

Comments
 (0)