Skip to content

Commit

Permalink
sfc: Implement auto-negotiation
Browse files Browse the repository at this point in the history
Add infrastructure for auto-negotiation of speed, duplex and flow
control.

When using 10Xpress, auto-negotiate flow control.  While we're
at it, clean up the code to warn when partner is not 10GBASE-T
capable.

Signed-off-by: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Ben Hutchings authored and David S. Miller committed Dec 13, 2008
1 parent 177dfcd commit 04cc8ca
Show file tree
Hide file tree
Showing 9 changed files with 472 additions and 154 deletions.
57 changes: 48 additions & 9 deletions drivers/net/sfc/ethtool.c
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
#include <linux/ethtool.h>
#include <linux/rtnetlink.h>
#include "net_driver.h"
#include "workarounds.h"
#include "selftest.h"
#include "efx.h"
#include "ethtool.h"
#include "falcon.h"
#include "spi.h"
#include "mdio_10g.h"

const char *efx_loopback_mode_names[] = {
[LOOPBACK_NONE] = "NONE",
Expand Down Expand Up @@ -674,14 +676,51 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
struct ethtool_pauseparam *pause)
{
struct efx_nic *efx = netdev_priv(net_dev);
enum efx_fc_type flow_control = efx->flow_control;
enum efx_fc_type wanted_fc;
bool reset;

flow_control &= ~(EFX_FC_RX | EFX_FC_TX | EFX_FC_AUTO);
flow_control |= pause->rx_pause ? EFX_FC_RX : 0;
flow_control |= pause->tx_pause ? EFX_FC_TX : 0;
flow_control |= pause->autoneg ? EFX_FC_AUTO : 0;
wanted_fc = ((pause->rx_pause ? EFX_FC_RX : 0) |
(pause->tx_pause ? EFX_FC_TX : 0) |
(pause->autoneg ? EFX_FC_AUTO : 0));

if ((wanted_fc & EFX_FC_TX) && !(wanted_fc & EFX_FC_RX)) {
EFX_LOG(efx, "Flow control unsupported: tx ON rx OFF\n");
return -EINVAL;
}

if (!(efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) &&
(wanted_fc & EFX_FC_AUTO)) {
EFX_LOG(efx, "PHY does not support flow control "
"autonegotiation\n");
return -EINVAL;
}

/* TX flow control may automatically turn itself off if the
* link partner (intermittently) stops responding to pause
* frames. There isn't any indication that this has happened,
* so the best we do is leave it up to the user to spot this
* and fix it be cycling transmit flow control on this end. */
reset = (wanted_fc & EFX_FC_TX) && !(efx->wanted_fc & EFX_FC_TX);
if (EFX_WORKAROUND_11482(efx) && reset) {
if (falcon_rev(efx) >= FALCON_REV_B0) {
/* Recover by resetting the EM block */
if (efx->link_up)
falcon_drain_tx_fifo(efx);
} else {
/* Schedule a reset to recover */
efx_schedule_reset(efx, RESET_TYPE_INVISIBLE);
}
}

/* Try to push the pause parameters */
mutex_lock(&efx->mac_lock);

efx->wanted_fc = wanted_fc;
mdio_clause45_set_pause(efx);
__efx_reconfigure_port(efx);

mutex_unlock(&efx->mac_lock);

efx_reconfigure_port(efx);
return 0;
}

Expand All @@ -690,9 +729,9 @@ static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
{
struct efx_nic *efx = netdev_priv(net_dev);

pause->rx_pause = !!(efx->flow_control & EFX_FC_RX);
pause->tx_pause = !!(efx->flow_control & EFX_FC_TX);
pause->autoneg = !!(efx->flow_control & EFX_FC_AUTO);
pause->rx_pause = !!(efx->wanted_fc & EFX_FC_RX);
pause->tx_pause = !!(efx->wanted_fc & EFX_FC_TX);
pause->autoneg = !!(efx->wanted_fc & EFX_FC_AUTO);
}


Expand Down
6 changes: 3 additions & 3 deletions drivers/net/sfc/falcon.c
Original file line number Diff line number Diff line change
Expand Up @@ -1998,7 +1998,7 @@ void falcon_reconfigure_mac_wrapper(struct efx_nic *efx)
/* Transmission of pause frames when RX crosses the threshold is
* covered by RX_XOFF_MAC_EN and XM_TX_CFG_REG:XM_FCNTL.
* Action on receipt of pause frames is controller by XM_DIS_FCNTL */
tx_fc = !!(efx->flow_control & EFX_FC_TX);
tx_fc = !!(efx->link_fc & EFX_FC_TX);
falcon_read(efx, &reg, RX_CFG_REG_KER);
EFX_SET_OWORD_FIELD_VER(efx, reg, RX_XOFF_MAC_EN, tx_fc);

Expand Down Expand Up @@ -2328,9 +2328,9 @@ int falcon_probe_port(struct efx_nic *efx)

/* Hardware flow ctrl. FalconA RX FIFO too small for pause generation */
if (falcon_rev(efx) >= FALCON_REV_B0)
efx->flow_control = EFX_FC_RX | EFX_FC_TX;
efx->wanted_fc = EFX_FC_RX | EFX_FC_TX;
else
efx->flow_control = EFX_FC_RX;
efx->wanted_fc = EFX_FC_RX;

/* Allocate buffer for stats */
rc = falcon_alloc_buffer(efx, &efx->stats_buffer,
Expand Down
4 changes: 2 additions & 2 deletions drivers/net/sfc/falcon_gmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,8 @@ static void falcon_reconfigure_gmac(struct efx_nic *efx)
efx_oword_t reg;

/* Configuration register 1 */
tx_fc = (efx->flow_control & EFX_FC_TX) || !efx->link_fd;
rx_fc = !!(efx->flow_control & EFX_FC_RX);
tx_fc = (efx->link_fc & EFX_FC_TX) || !efx->link_fd;
rx_fc = !!(efx->link_fc & EFX_FC_RX);
loopback = (efx->loopback_mode == LOOPBACK_GMAC);
bytemode = (efx->link_speed == 1000);

Expand Down
2 changes: 1 addition & 1 deletion drivers/net/sfc/falcon_xmac.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static void falcon_reconfigure_xmac_core(struct efx_nic *efx)
{
unsigned int max_frame_len;
efx_oword_t reg;
bool rx_fc = !!(efx->flow_control & EFX_FC_RX);
bool rx_fc = !!(efx->link_fc & EFX_FC_RX);

/* Configure MAC - cut-thru mode is hard wired on */
EFX_POPULATE_DWORD_3(reg,
Expand Down
Loading

0 comments on commit 04cc8ca

Please sign in to comment.