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.
Unified · Split
| @@ -181,9 +181,11 @@ static int phylink_parse_fixedlink(struct phylink *pl, · 180 unmodified lines | |||
| 181 | /* We treat the "pause" and "asym-pause" terminology as | 181 | /* We treat the "pause" and "asym-pause" terminology as |
| 182 | * defining the link partner's ability. */ | 182 | * defining the link partner's ability. */ |
| 183 | if (fwnode_property_read_bool(fixed_node, "pause")) | 183 | 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); | ||
| 185 | if (fwnode_property_read_bool(fixed_node, "asym-pause")) | 186 | 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); | ||
| 187 | 189 | ||
| 188 | if (ret == 0) { | 190 | if (ret == 0) { |
| 189 | desc = fwnode_gpiod_get_index(fixed_node, "link", 0, | 191 | desc = fwnode_gpiod_get_index(fixed_node, "link", 0, |
| @@ -215,9 +217,11 @@ static int phylink_parse_fixedlink(struct phylink *pl, · 25 unmodified lines | |||
| 215 | DUPLEX_FULL : DUPLEX_HALF; | 217 | DUPLEX_FULL : DUPLEX_HALF; |
| 216 | pl->link_config.speed = prop[2]; | 218 | pl->link_config.speed = prop[2]; |
| 217 | if (prop[3]) | 219 | 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); | ||
| 219 | if (prop[4]) | 222 | 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); | ||
| 221 | } | 225 | } |
| 222 | } | 226 | } |
| 223 | 227 | ||
| @@ -351,6 +355,22 @@ static void phylink_apply_manual_flow(struct phylink *pl, · 127 unmodified lines | |||
| 351 | state->pause = pl->link_config.pause; | 355 | state->pause = pl->link_config.pause; |
| 352 | } | 356 | } |
| 353 | 357 | ||
| 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 | |||
| 354 | static void phylink_mac_config(struct phylink *pl, | 374 | static void phylink_mac_config(struct phylink *pl, |
| 355 | const struct phylink_link_state *state) | 375 | const struct phylink_link_state *state) |
| 356 | { | 376 | { |
| @@ -399,44 +419,16 @@ static void phylink_mac_pcs_get_state(struct phylink *pl, · 42 unmodified lines | |||
| 399 | /* The fixed state is... fixed except for the link state, | 419 | /* The fixed state is... fixed except for the link state, |
| 400 | * which may be determined by a GPIO or a callback. | 420 | * which may be determined by a GPIO or a callback. |
| 401 | */ | 421 | */ |
| 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) | ||
| 403 | { | 424 | { |
| 404 | *state = pl->link_config; | 425 | *state = pl->link_config; |
| 405 | if (pl->get_fixed_state) | 426 | if (pl->get_fixed_state) |
| 406 | pl->get_fixed_state(pl->netdev, state); | 427 | pl->get_fixed_state(pl->netdev, state); |
| 407 | else if (pl->link_gpio) | 428 | else if (pl->link_gpio) |
| 408 | state->link = !!gpiod_get_value_cansleep(pl->link_gpio); | 429 | state->link = !!gpiod_get_value_cansleep(pl->link_gpio); |
| 409 | } | ||
| 410 | 430 | ||
| 411 | /* Flow control is resolved according to our and the link partners | 431 | phylink_resolve_flow(state); |
| 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; | ||
| 440 | } | 432 | } |
| 441 | 433 | ||
| 442 | static const char *phylink_pause_to_str(int pause) | 434 | static const char *phylink_pause_to_str(int pause) |
| @@ -1393,8 +1385,7 @@ int phylink_ethtool_set_pauseparam(struct phylink *pl, · 950 unmodified lines | |||
| 1393 | !pause->autoneg && pause->rx_pause != pause->tx_pause) | 1385 | !pause->autoneg && pause->rx_pause != pause->tx_pause) |
| 1394 | return -EINVAL; | 1386 | return -EINVAL; |
| 1395 | 1387 | ||
| 1396 | config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK); | 1388 | config->pause = 0; |
| 1397 | |||
| 1398 | if (pause->autoneg) | 1389 | if (pause->autoneg) |
| 1399 | config->pause |= MLO_PAUSE_AN; | 1390 | config->pause |= MLO_PAUSE_AN; |
| 1400 | if (pause->rx_pause) | 1391 | if (pause->rx_pause) |
| @@ -1505,13 +1496,14 @@ static int phylink_mii_emul_read(unsigned int reg, · 104 unmodified lines | |||
| 1505 | struct phylink_link_state *state) | 1496 | struct phylink_link_state *state) |
| 1506 | { | 1497 | { |
| 1507 | struct fixed_phy_status fs; | 1498 | struct fixed_phy_status fs; |
| 1499 | unsigned long *lpa = state->lp_advertising; | ||
| 1508 | int val; | 1500 | int val; |
| 1509 | 1501 | ||
| 1510 | fs.link = state->link; | 1502 | fs.link = state->link; |
| 1511 | fs.speed = state->speed; | 1503 | fs.speed = state->speed; |
| 1512 | fs.duplex = state->duplex; | 1504 | fs.duplex = state->duplex; |
| 1513 | fs.pause = state->pause & MLO_PAUSE_SYM; | 1505 | fs.pause = test_bit(ETHTOOL_LINK_MODE_Pause_BIT, lpa); |
| 1514 | fs.asym_pause = state->pause & MLO_PAUSE_ASYM; | 1506 | fs.asym_pause = test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, lpa); |
| 1515 | 1507 | ||
| 1516 | val = swphy_read_reg(reg, &fs); | 1508 | val = swphy_read_reg(reg, &fs); |
| 1517 | if (reg == MII_BMSR) { | 1509 | if (reg == MII_BMSR) { |
| @@ -12,12 +12,10 @@ struct net_device; · 11 unmodified lines | |||
| 12 | 12 | ||
| 13 | enum { | 13 | enum { |
| 14 | MLO_PAUSE_NONE, | 14 | MLO_PAUSE_NONE, |
| 15 | MLO_PAUSE_ASYM = BIT(0), | 15 | MLO_PAUSE_RX = BIT(0), |
| 16 | MLO_PAUSE_SYM = BIT(1), | 16 | MLO_PAUSE_TX = BIT(1), |
| 17 | MLO_PAUSE_RX = BIT(2), | ||
| 18 | MLO_PAUSE_TX = BIT(3), | ||
| 19 | MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX, | 17 | MLO_PAUSE_TXRX_MASK = MLO_PAUSE_TX | MLO_PAUSE_RX, |
| 20 | MLO_PAUSE_AN = BIT(4), | 18 | MLO_PAUSE_AN = BIT(2), |
| 21 | 19 | ||
| 22 | MLO_AN_PHY = 0, /* Conventional PHY */ | 20 | MLO_AN_PHY = 0, /* Conventional PHY */ |
| 23 | MLO_AN_FIXED, /* Fixed-link mode */ | 21 | MLO_AN_FIXED, /* Fixed-link mode */ |