^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0+
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) #include <linux/linkmode.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * linkmode_resolve_pause - resolve the allowable pause modes
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * @local_adv: local advertisement in ethtool format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) * @partner_adv: partner advertisement in ethtool format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * @tx_pause: pointer to bool to indicate whether transmit pause should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * @rx_pause: pointer to bool to indicate whether receive pause should be
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) * enabled.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) * Flow control is resolved according to our and the link partners
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) * advertisements using the following drawn from the 802.3 specs:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) * Local device Link partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) * Pause AsymDir Pause AsymDir Result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) * 0 X 0 X Disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) * 0 1 1 0 Disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) * 0 1 1 1 TX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) * 1 0 0 X Disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) * 1 X 1 X TX+RX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) * 1 1 0 1 RX
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) void linkmode_resolve_pause(const unsigned long *local_adv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) const unsigned long *partner_adv,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) bool *tx_pause, bool *rx_pause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) __ETHTOOL_DECLARE_LINK_MODE_MASK(m);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) linkmode_and(m, local_adv, partner_adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) if (linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT, m)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) *tx_pause = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) *rx_pause = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) } else if (linkmode_test_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, m)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) *tx_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) partner_adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) *rx_pause = linkmode_test_bit(ETHTOOL_LINK_MODE_Pause_BIT,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) local_adv);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) } else {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) *tx_pause = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) *rx_pause = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) EXPORT_SYMBOL_GPL(linkmode_resolve_pause);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) /**
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) * linkmode_set_pause - set the pause mode advertisement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) * @advertisement: advertisement in ethtool format
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) * @tx: boolean from ethtool struct ethtool_pauseparam tx_pause member
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) * @rx: boolean from ethtool struct ethtool_pauseparam rx_pause member
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) * Configure the advertised Pause and Asym_Pause bits according to the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) * capabilities of provided in @tx and @rx.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * We convert as follows:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) * tx rx Pause AsymDir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) * 0 0 0 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) * 0 1 1 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) * 1 0 0 1
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) * 1 1 1 0
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * Note: this translation from ethtool tx/rx notation to the advertisement
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * is actually very problematical. Here are some examples:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) * For tx=0 rx=1, meaning transmit is unsupported, receive is supported:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) * Local device Link partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) * Pause AsymDir Pause AsymDir Result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) * 1 1 1 0 TX + RX - but we have no TX support.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) * 1 1 0 1 Only this gives RX only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) * For tx=1 rx=1, meaning we have the capability to transmit and receive
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) * pause frames:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) * Local device Link partner
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) * Pause AsymDir Pause AsymDir Result
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) * 1 0 0 1 Disabled - but since we do support tx and rx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) * this should resolve to RX only.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) * Hence, asking for:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) * rx=1 tx=0 gives Pause+AsymDir advertisement, but we may end up
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) * resolving to tx+rx pause or only rx pause depending on
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) * the partners advertisement.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) * rx=0 tx=1 gives AsymDir only, which will only give tx pause if
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) * the partners advertisement allows it.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) * rx=1 tx=1 gives Pause only, which will only allow tx+rx pause
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) * if the other end also advertises Pause.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) void linkmode_set_pause(unsigned long *advertisement, bool tx, bool rx)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) linkmode_mod_bit(ETHTOOL_LINK_MODE_Pause_BIT, advertisement, rx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) linkmode_mod_bit(ETHTOOL_LINK_MODE_Asym_Pause_BIT, advertisement,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) rx ^ tx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) EXPORT_SYMBOL_GPL(linkmode_set_pause);