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 | 181 | /* We treat the "pause" and "asym-pause" terminology as |
| 182 | 182 | * defining the link partner's ability. */ |
| 183 | 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 | 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 | 190 | if (ret == 0) { |
| 189 | 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 | 217 | DUPLEX_FULL : DUPLEX_HALF; |
| 216 | 218 | pl->link_config.speed = prop[2]; |
| 217 | 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 | 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 | 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 | 374 | static void phylink_mac_config(struct phylink *pl, |
| 355 | 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 | 419 | /* The fixed state is... fixed except for the link state, |
| 400 | 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 | 425 | *state = pl->link_config; |
| 405 | 426 | if (pl->get_fixed_state) |
| 406 | 427 | pl->get_fixed_state(pl->netdev, state); |
| 407 | 428 | else if (pl->link_gpio) |
| 408 | 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 | |
| 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); | |
| 440 | 432 | } |
| 441 | 433 | |
| 442 | 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 | 1385 | !pause->autoneg && pause->rx_pause != pause->tx_pause) |
| 1394 | 1386 | return -EINVAL; |
| 1395 | 1387 | |
| 1396 | − config->pause &= ~(MLO_PAUSE_AN | MLO_PAUSE_TXRX_MASK); | |
| 1397 | − | |
| 1388 | + config->pause = 0; | |
| 1398 | 1389 | if (pause->autoneg) |
| 1399 | 1390 | config->pause |= MLO_PAUSE_AN; |
| 1400 | 1391 | if (pause->rx_pause) |
| @@ -1505,13 +1496,14 @@ static int phylink_mii_emul_read(unsigned int reg, · 104 unmodified lines | ||
| 1505 | 1496 | struct phylink_link_state *state) |
| 1506 | 1497 | { |
| 1507 | 1498 | struct fixed_phy_status fs; |
| 1499 | + unsigned long *lpa = state->lp_advertising; | |
| 1508 | 1500 | int val; |
| 1509 | 1501 | |
| 1510 | 1502 | fs.link = state->link; |
| 1511 | 1503 | fs.speed = state->speed; |
| 1512 | 1504 | 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); | |
| 1515 | 1507 | |
| 1516 | 1508 | val = swphy_read_reg(reg, &fs); |
| 1517 | 1509 | if (reg == MII_BMSR) { |
| @@ -12,12 +12,10 @@ struct net_device; · 11 unmodified lines | ||
| 12 | 12 | |
| 13 | 13 | enum { |
| 14 | 14 | 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), | |
| 19 | 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 | 20 | MLO_AN_PHY = 0, /* Conventional PHY */ |
| 23 | 21 | MLO_AN_FIXED, /* Fixed-link mode */ |