Subject: ethtool pause mode clarifications

From: Russell King - ARM Linux admin <[email-masked]>
Date: Fri, 13 Dec 2019 11:49:35 +0000

Hi,

Please can someone explain the ethtool pause mode settings?  The man
page isn't particularly clear, it says:

       -A --pause
              Changes the pause parameters of the specified Ethernet device.

           autoneg on|off
                  Specifies whether pause autonegotiation should be enabled.

           rx on|off
                  Specifies whether RX pause should be enabled.

           tx on|off
                  Specifies whether TX pause should be enabled.

"autoneg" states whether pause autonegotiation should be enabled, but
how is this possible, when pause autonegotiation happens as part of the
rest of the autonegotiation as a matter of course, and the only control
we have at the PHY is the value of the pause and asym pause bits?

The alternative interpretation is that "autoneg" controls whether the
local end interprets the result of the pause negotiation or not.  In
other words, if:

	autoneg off rx on tx on

that causes pause modes to still be advertised to the partner, but the
results of pause negotiation to be overridden by forcing enablement of
pause reception and transmission.

Then there's the whole issue of translating something like:

	autoneg on rx on tx off

to the pause mode advertisement.  phylib translates this to a local
advertisement of pause=1 asym pause=1.  Looking at the table in 802.3,

Local device  Link partner
Pause AsymDir Pause AsymDir Result
  1     1       1     X     TX + RX - but ethtool wanted RX only
  1     1       0     1     This would give RX only

however, ethtool has no control over the link partner's advertisement,
so despite requesting "autoneg on rx on tx off" this may be no
different from "autoneg on rx on tx on".

However, there's another way to handle that - which is to treat autoneg
as a mask for the autonegotiation result:

	if (!ethtool_pause_autoneg || (local_adv & partner_adv & PAUSE)) {
		tx_pause = 1;
		rx_pause = 1;
	} else if (local_adv & partner_adv & ASYM_PAUSE) {
		tx_pause = partner_adv & PAUSE;
		rx_pause = local_adv & PAUSE;
	} else {
		tx_pause = 0;
		rx_pause = 0;
	}

	tx_pause &= ethtool_pause_tx;
	rx_pause &= ethtool_pause_rx;

In other words, treating the ethtool rx/tx pause parameters as
permissive bits for the result of negotiation or force bits when
pause autoneg is disabled.

Then comes the pause advertisement.  phylib uses this:

	pause_advertisement = rx;
	asym_pause_advertisement = rx ^ tx;

So, if we were to request rx=1 tx=1, we end up advertising pause but
no asym pause.  That gives us only two possible resolutions to pause
negotiation: TX+RX pause enabled at both ends, or TX+RX pause disabled
at both ends.  There is no resolution that leads to symmetric pause.
If what I suggest above is adopted for pause mode resolution, then a
more correct implementation would be:

	pause_advertisement = rx;
	asym_pause_advertisement = rx | tx;

So, would it be possible to clarify what these settings mean in the
ethtool man page please?

Thanks.

-- 
RMK's Patch system: https://www.armlinux.org.uk/developer/patches/
FTTC broadband for 0.8mile line in suburbia: sync at 12.1Mbps down 622kbps up
According to speedtest.net: 11.9Mbps down 500kbps up