Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 177dfcd8 authored by Ben Hutchings's avatar Ben Hutchings Committed by David S. Miller
Browse files

sfc: Add support for sub-10G speeds



The SFC4000 has a separate MAC for use at sub-10G speeds.  Introduce
an efx_mac_operations structure with implementations for the two MACs.
Switch between the MACs as necessary.

PHY settings are independent of the MAC, so add get_settings() and
set_settings() to efx_phy_operations.  Also add macs field to indicate
which MACs the PHY is connected to.

Signed-off-by: default avatarBen Hutchings <bhutchings@solarflare.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 356eebb2
Loading
Loading
Loading
Loading
+2 −2
Original line number Original line Diff line number Diff line
sfc-y			+= efx.o falcon.o tx.o rx.o falcon_xmac.o \
sfc-y			+= efx.o falcon.o tx.o rx.o falcon_gmac.o \
			   selftest.o ethtool.o xfp_phy.o \
			   falcon_xmac.o selftest.o ethtool.o xfp_phy.o \
			   mdio_10g.o tenxpress.o boards.o sfe4001.o
			   mdio_10g.o tenxpress.o boards.o sfe4001.o
sfc-$(CONFIG_SFC_MTD)	+= mtd.o
sfc-$(CONFIG_SFC_MTD)	+= mtd.o


+43 −19
Original line number Original line Diff line number Diff line
@@ -27,7 +27,6 @@
#include "efx.h"
#include "efx.h"
#include "mdio_10g.h"
#include "mdio_10g.h"
#include "falcon.h"
#include "falcon.h"
#include "mac.h"


#define EFX_MAX_MTU (9 * 1024)
#define EFX_MAX_MTU (9 * 1024)


@@ -575,10 +574,28 @@ void __efx_reconfigure_port(struct efx_nic *efx)
		netif_addr_unlock_bh(efx->net_dev);
		netif_addr_unlock_bh(efx->net_dev);
	}
	}


	falcon_reconfigure_xmac(efx);
	falcon_deconfigure_mac_wrapper(efx);

	/* Reconfigure the PHY, disabling transmit in mac level loopback. */
	if (LOOPBACK_INTERNAL(efx))
		efx->phy_mode |= PHY_MODE_TX_DISABLED;
	else
		efx->phy_mode &= ~PHY_MODE_TX_DISABLED;
	efx->phy_op->reconfigure(efx);

	if (falcon_switch_mac(efx))
		goto fail;

	efx->mac_op->reconfigure(efx);


	/* Inform kernel of loss/gain of carrier */
	/* Inform kernel of loss/gain of carrier */
	efx_link_status_changed(efx);
	efx_link_status_changed(efx);
	return;

fail:
	EFX_ERR(efx, "failed to reconfigure MAC\n");
	efx->phy_op->fini(efx);
	efx->port_initialized = false;
}
}


/* Reinitialise the MAC to pick up new PHY settings, even if the port is
/* Reinitialise the MAC to pick up new PHY settings, even if the port is
@@ -648,18 +665,25 @@ static int efx_init_port(struct efx_nic *efx)


	EFX_LOG(efx, "init port\n");
	EFX_LOG(efx, "init port\n");


	/* Initialise the MAC and PHY */
	rc = efx->phy_op->init(efx);
	rc = falcon_init_xmac(efx);
	if (rc)
	if (rc)
		return rc;
		return rc;
	efx->phy_op->reconfigure(efx);

	mutex_lock(&efx->mac_lock);
	rc = falcon_switch_mac(efx);
	mutex_unlock(&efx->mac_lock);
	if (rc)
		goto fail;
	efx->mac_op->reconfigure(efx);


	efx->port_initialized = true;
	efx->port_initialized = true;
	efx->stats_enabled = true;
	efx->stats_enabled = true;

	/* Reconfigure port to program MAC registers */
	falcon_reconfigure_xmac(efx);

	return 0;
	return 0;

fail:
	efx->phy_op->fini(efx);
	return rc;
}
}


/* Allow efx_reconfigure_port() to be scheduled, and close the window
/* Allow efx_reconfigure_port() to be scheduled, and close the window
@@ -702,7 +726,7 @@ static void efx_fini_port(struct efx_nic *efx)
	if (!efx->port_initialized)
	if (!efx->port_initialized)
		return;
		return;


	falcon_fini_xmac(efx);
	efx->phy_op->fini(efx);
	efx->port_initialized = false;
	efx->port_initialized = false;


	efx->link_up = false;
	efx->link_up = false;
@@ -1179,7 +1203,6 @@ static void efx_monitor(struct work_struct *data)
{
{
	struct efx_nic *efx = container_of(data, struct efx_nic,
	struct efx_nic *efx = container_of(data, struct efx_nic,
					   monitor_work.work);
					   monitor_work.work);
	int rc = 0;


	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
		  raw_smp_processor_id());
		  raw_smp_processor_id());
@@ -1195,7 +1218,7 @@ static void efx_monitor(struct work_struct *data)
	}
	}


	if (efx->port_enabled)
	if (efx->port_enabled)
		rc = falcon_check_xmac(efx);
		efx->mac_op->check_hw(efx);
	mutex_unlock(&efx->mac_lock);
	mutex_unlock(&efx->mac_lock);


	queue_delayed_work(efx->workqueue, &efx->monitor_work,
	queue_delayed_work(efx->workqueue, &efx->monitor_work,
@@ -1331,7 +1354,7 @@ static struct net_device_stats *efx_net_stats(struct net_device *net_dev)
	if (!spin_trylock(&efx->stats_lock))
	if (!spin_trylock(&efx->stats_lock))
		return stats;
		return stats;
	if (efx->stats_enabled) {
	if (efx->stats_enabled) {
		falcon_update_stats_xmac(efx);
		efx->mac_op->update_stats(efx);
		falcon_update_nic_stats(efx);
		falcon_update_nic_stats(efx);
	}
	}
	spin_unlock(&efx->stats_lock);
	spin_unlock(&efx->stats_lock);
@@ -1519,7 +1542,7 @@ static int efx_register_netdev(struct efx_nic *efx)
	netif_carrier_off(efx->net_dev);
	netif_carrier_off(efx->net_dev);


	/* Clear MAC statistics */
	/* Clear MAC statistics */
	falcon_update_stats_xmac(efx);
	efx->mac_op->update_stats(efx);
	memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
	memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));


	rc = register_netdev(net_dev);
	rc = register_netdev(net_dev);
@@ -1575,8 +1598,6 @@ static void efx_unregister_netdev(struct efx_nic *efx)
 * before reset.  */
 * before reset.  */
void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
{
{
	int rc;

	EFX_ASSERT_RESET_SERIALISED(efx);
	EFX_ASSERT_RESET_SERIALISED(efx);


	/* The net_dev->get_stats handler is quite slow, and will fail
	/* The net_dev->get_stats handler is quite slow, and will fail
@@ -1589,9 +1610,7 @@ void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
	mutex_lock(&efx->mac_lock);
	mutex_lock(&efx->mac_lock);
	mutex_lock(&efx->spi_lock);
	mutex_lock(&efx->spi_lock);


	rc = falcon_xmac_get_settings(efx, ecmd);
	efx->phy_op->get_settings(efx, ecmd);
	if (rc)
		EFX_ERR(efx, "could not back up PHY settings\n");


	efx_fini_channels(efx);
	efx_fini_channels(efx);
}
}
@@ -1616,7 +1635,7 @@ int efx_reset_up(struct efx_nic *efx, struct ethtool_cmd *ecmd, bool ok)
	if (ok) {
	if (ok) {
		efx_init_channels(efx);
		efx_init_channels(efx);


		if (falcon_xmac_set_settings(efx, ecmd))
		if (efx->phy_op->set_settings(efx, ecmd))
			EFX_ERR(efx, "could not restore PHY settings\n");
			EFX_ERR(efx, "could not restore PHY settings\n");
	}
	}


@@ -1779,6 +1798,10 @@ int efx_port_dummy_op_int(struct efx_nic *efx)
void efx_port_dummy_op_void(struct efx_nic *efx) {}
void efx_port_dummy_op_void(struct efx_nic *efx) {}
void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {}
void efx_port_dummy_op_blink(struct efx_nic *efx, bool blink) {}


static struct efx_mac_operations efx_dummy_mac_operations = {
	.reconfigure	= efx_port_dummy_op_void,
};

static struct efx_phy_operations efx_dummy_phy_operations = {
static struct efx_phy_operations efx_dummy_phy_operations = {
	.init		 = efx_port_dummy_op_int,
	.init		 = efx_port_dummy_op_int,
	.reconfigure	 = efx_port_dummy_op_void,
	.reconfigure	 = efx_port_dummy_op_void,
@@ -1831,6 +1854,7 @@ static int efx_init_struct(struct efx_nic *efx, struct efx_nic_type *type,
	spin_lock_init(&efx->netif_stop_lock);
	spin_lock_init(&efx->netif_stop_lock);
	spin_lock_init(&efx->stats_lock);
	spin_lock_init(&efx->stats_lock);
	mutex_init(&efx->mac_lock);
	mutex_init(&efx->mac_lock);
	efx->mac_op = &efx_dummy_mac_operations;
	efx->phy_op = &efx_dummy_phy_operations;
	efx->phy_op = &efx_dummy_phy_operations;
	efx->mii.dev = net_dev;
	efx->mii.dev = net_dev;
	INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
	INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);
+16 −13
Original line number Original line Diff line number Diff line
/****************************************************************************
/****************************************************************************
 * Driver for Solarflare Solarstorm network controllers and boards
 * Driver for Solarflare Solarstorm network controllers and boards
 * Copyright 2007 Solarflare Communications Inc.
 * Copyright 2007-2008 Solarflare Communications Inc.
 *
 *
 * This program is free software; you can redistribute it and/or modify it
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 as published
 * under the terms of the GNU General Public License version 2 as published
@@ -13,22 +13,24 @@
/**
/**
 * enum efx_loopback_mode - loopback modes
 * enum efx_loopback_mode - loopback modes
 * @LOOPBACK_NONE: no loopback
 * @LOOPBACK_NONE: no loopback
 * @LOOPBACK_XGMII: loopback within MAC at XGMII level
 * @LOOPBACK_GMAC: loopback within GMAC at unspecified level
 * @LOOPBACK_XGXS: loopback within MAC at XGXS level
 * @LOOPBACK_XGMII: loopback within XMAC at XGMII level
 * @LOOPBACK_XAUI: loopback within MAC at XAUI level
 * @LOOPBACK_XGXS: loopback within XMAC at XGXS level
 * @LOOPBACK_PHYXS: loopback within PHY at PHYXS level
 * @LOOPBACK_XAUI: loopback within XMAC at XAUI level
 * @LOOPBACK_PCS: loopback within PHY at PCS level
 * @LOOPBACK_GPHY: loopback within 1G PHY at unspecified level
 * @LOOPBACK_PMAPMD: loopback within PHY at PMAPMD level
 * @LOOPBACK_PHYXS: loopback within 10G PHY at PHYXS level
 * @LOOPBACK_PCS: loopback within 10G PHY at PCS level
 * @LOOPBACK_PMAPMD: loopback within 10G PHY at PMAPMD level
 * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
 * @LOOPBACK_NETWORK: reflecting loopback (even further than furthest!)
 */
 */
/* Please keep in order and up-to-date w.r.t the following two #defines */
/* Please keep in order and up-to-date w.r.t the following two #defines */
enum efx_loopback_mode {
enum efx_loopback_mode {
	LOOPBACK_NONE = 0,
	LOOPBACK_NONE = 0,
	LOOPBACK_MAC = 1,
	LOOPBACK_GMAC = 1,
	LOOPBACK_XGMII = 2,
	LOOPBACK_XGMII = 2,
	LOOPBACK_XGXS = 3,
	LOOPBACK_XGXS = 3,
	LOOPBACK_XAUI = 4,
	LOOPBACK_XAUI = 4,
	LOOPBACK_PHY = 5,
	LOOPBACK_GPHY = 5,
	LOOPBACK_PHYXS = 6,
	LOOPBACK_PHYXS = 6,
	LOOPBACK_PCS = 7,
	LOOPBACK_PCS = 7,
	LOOPBACK_PMAPMD = 8,
	LOOPBACK_PMAPMD = 8,
@@ -45,7 +47,8 @@ extern const char *efx_loopback_mode_names[];
	LOOPBACK_MODE_NAME(efx->loopback_mode)
	LOOPBACK_MODE_NAME(efx->loopback_mode)


/* These loopbacks occur within the controller */
/* These loopbacks occur within the controller */
#define LOOPBACKS_10G_INTERNAL ((1 << LOOPBACK_XGMII)| \
#define LOOPBACKS_INTERNAL ((1 << LOOPBACK_GMAC) |     \
			    (1 << LOOPBACK_XGMII)|     \
			    (1 << LOOPBACK_XGXS) |     \
			    (1 << LOOPBACK_XGXS) |     \
			    (1 << LOOPBACK_XAUI))
			    (1 << LOOPBACK_XAUI))


@@ -53,7 +56,7 @@ extern const char *efx_loopback_mode_names[];
	(1 << (_efx)->loopback_mode)
	(1 << (_efx)->loopback_mode)


#define LOOPBACK_INTERNAL(_efx)				\
#define LOOPBACK_INTERNAL(_efx)				\
	(!!(LOOPBACKS_10G_INTERNAL & LOOPBACK_MASK(_efx)))
	(!!(LOOPBACKS_INTERNAL & LOOPBACK_MASK(_efx)))


#define LOOPBACK_OUT_OF(_from, _to, _mask)				\
#define LOOPBACK_OUT_OF(_from, _to, _mask)				\
	((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
	((LOOPBACK_MASK(_from) & (_mask)) && !(LOOPBACK_MASK(_to) & (_mask)))
+17 −21
Original line number Original line Diff line number Diff line
@@ -17,15 +17,14 @@
#include "ethtool.h"
#include "ethtool.h"
#include "falcon.h"
#include "falcon.h"
#include "spi.h"
#include "spi.h"
#include "mac.h"


const char *efx_loopback_mode_names[] = {
const char *efx_loopback_mode_names[] = {
	[LOOPBACK_NONE]		= "NONE",
	[LOOPBACK_NONE]		= "NONE",
	[LOOPBACK_MAC]		= "MAC",
	[LOOPBACK_GMAC]		= "GMAC",
	[LOOPBACK_XGMII]	= "XGMII",
	[LOOPBACK_XGMII]	= "XGMII",
	[LOOPBACK_XGXS]		= "XGXS",
	[LOOPBACK_XGXS]		= "XGXS",
	[LOOPBACK_XAUI] 	= "XAUI",
	[LOOPBACK_XAUI] 	= "XAUI",
	[LOOPBACK_PHY]		= "PHY",
	[LOOPBACK_GPHY]		= "GPHY",
	[LOOPBACK_PHYXS]	= "PHYXS",
	[LOOPBACK_PHYXS]	= "PHYXS",
	[LOOPBACK_PCS]	 	= "PCS",
	[LOOPBACK_PCS]	 	= "PCS",
	[LOOPBACK_PMAPMD]	= "PMA/PMD",
	[LOOPBACK_PMAPMD]	= "PMA/PMD",
@@ -200,13 +199,15 @@ int efx_ethtool_get_settings(struct net_device *net_dev,
			     struct ethtool_cmd *ecmd)
			     struct ethtool_cmd *ecmd)
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	int rc;


	mutex_lock(&efx->mac_lock);
	mutex_lock(&efx->mac_lock);
	rc = falcon_xmac_get_settings(efx, ecmd);
	efx->phy_op->get_settings(efx, ecmd);
	mutex_unlock(&efx->mac_lock);
	mutex_unlock(&efx->mac_lock);


	return rc;
	/* Falcon GMAC does not support 1000Mbps HD */
	ecmd->supported &= ~SUPPORTED_1000baseT_Half;

	return 0;
}
}


/* This must be called with rtnl_lock held. */
/* This must be called with rtnl_lock held. */
@@ -216,8 +217,15 @@ int efx_ethtool_set_settings(struct net_device *net_dev,
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	int rc;
	int rc;


	/* Falcon GMAC does not support 1000Mbps HD */
	if (ecmd->speed == SPEED_1000 && ecmd->duplex != DUPLEX_FULL) {
		EFX_LOG(efx, "rejecting unsupported 1000Mbps HD"
			" setting\n");
		return -EINVAL;
	}

	mutex_lock(&efx->mac_lock);
	mutex_lock(&efx->mac_lock);
	rc = falcon_xmac_set_settings(efx, ecmd);
	rc = efx->phy_op->set_settings(efx, ecmd);
	mutex_unlock(&efx->mac_lock);
	mutex_unlock(&efx->mac_lock);
	if (!rc)
	if (!rc)
		efx_reconfigure_port(efx);
		efx_reconfigure_port(efx);
@@ -362,10 +370,6 @@ static int efx_ethtool_fill_self_tests(struct efx_nic *efx,
		      EFX_PORT_NAME, "phy", NULL);
		      EFX_PORT_NAME, "phy", NULL);


	/* Loopback tests */
	/* Loopback tests */
	efx_fill_test(n++, strings, data, &tests->loopback_speed,
		      EFX_PORT_NAME, "loopback.speed", NULL);
	efx_fill_test(n++, strings, data, &tests->loopback_full_duplex,
		      EFX_PORT_NAME, "loopback.full_duplex", NULL);
	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
	for (mode = LOOPBACK_NONE; mode <= LOOPBACK_TEST_MAX; mode++) {
		if (!(efx->loopback_modes & (1 << mode)))
		if (!(efx->loopback_modes & (1 << mode)))
			continue;
			continue;
@@ -671,22 +675,14 @@ static int efx_ethtool_set_pauseparam(struct net_device *net_dev,
{
{
	struct efx_nic *efx = netdev_priv(net_dev);
	struct efx_nic *efx = netdev_priv(net_dev);
	enum efx_fc_type flow_control = efx->flow_control;
	enum efx_fc_type flow_control = efx->flow_control;
	int rc;


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


	/* Try to push the pause parameters */
	mutex_lock(&efx->mac_lock);
	rc = falcon_xmac_set_pause(efx, flow_control);
	mutex_unlock(&efx->mac_lock);

	if (!rc)
	efx_reconfigure_port(efx);
	efx_reconfigure_port(efx);

	return 0;
	return rc;
}
}


static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
static void efx_ethtool_get_pauseparam(struct net_device *net_dev,
+141 −38
Original line number Original line Diff line number Diff line
@@ -1168,6 +1168,19 @@ void falcon_generate_test_event(struct efx_channel *channel, unsigned int magic)
	falcon_generate_event(channel, &test_event);
	falcon_generate_event(channel, &test_event);
}
}


void falcon_sim_phy_event(struct efx_nic *efx)
{
	efx_qword_t phy_event;

	EFX_POPULATE_QWORD_1(phy_event, EV_CODE, GLOBAL_EV_DECODE);
	if (EFX_IS10G(efx))
		EFX_SET_OWORD_FIELD(phy_event, XG_PHY_INTR, 1);
	else
		EFX_SET_OWORD_FIELD(phy_event, G_PHY0_INTR, 1);

	falcon_generate_event(&efx->channel[0], &phy_event);
}

/**************************************************************************
/**************************************************************************
 *
 *
 * Flush handling
 * Flush handling
@@ -1839,40 +1852,61 @@ int falcon_spi_write(const struct efx_spi_device *spi, loff_t start,
 *
 *
 **************************************************************************
 **************************************************************************
 */
 */
void falcon_drain_tx_fifo(struct efx_nic *efx)

static int falcon_reset_macs(struct efx_nic *efx)
{
{
	efx_oword_t temp;
	efx_oword_t reg;
	int count;
	int count;


	if ((falcon_rev(efx) < FALCON_REV_B0) ||
	if (falcon_rev(efx) < FALCON_REV_B0) {
	    (efx->loopback_mode != LOOPBACK_NONE))
		/* It's not safe to use GLB_CTL_REG to reset the
		return;
		 * macs, so instead use the internal MAC resets
		 */
		if (!EFX_IS10G(efx)) {
			EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 1);
			falcon_write(efx, &reg, GM_CFG1_REG);
			udelay(1000);

			EFX_POPULATE_OWORD_1(reg, GM_SW_RST, 0);
			falcon_write(efx, &reg, GM_CFG1_REG);
			udelay(1000);
			return 0;
		} else {
			EFX_POPULATE_OWORD_1(reg, XM_CORE_RST, 1);
			falcon_write(efx, &reg, XM_GLB_CFG_REG);


	falcon_read(efx, &temp, MAC0_CTRL_REG_KER);
			for (count = 0; count < 10000; count++) {
	/* There is no point in draining more than once */
				falcon_read(efx, &reg, XM_GLB_CFG_REG);
	if (EFX_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0))
				if (EFX_OWORD_FIELD(reg, XM_CORE_RST) == 0)
		return;
					return 0;
				udelay(10);
			}

			EFX_ERR(efx, "timed out waiting for XMAC core reset\n");
			return -ETIMEDOUT;
		}
	}


	/* MAC stats will fail whilst the TX fifo is draining. Serialise
	/* MAC stats will fail whilst the TX fifo is draining. Serialise
	 * the drain sequence with the statistics fetch */
	 * the drain sequence with the statistics fetch */
	spin_lock(&efx->stats_lock);
	spin_lock(&efx->stats_lock);


	EFX_SET_OWORD_FIELD(temp, TXFIFO_DRAIN_EN_B0, 1);
	falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
	falcon_write(efx, &temp, MAC0_CTRL_REG_KER);
	EFX_SET_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0, 1);
	falcon_write(efx, &reg, MAC0_CTRL_REG_KER);


	/* Reset the MAC and EM block. */
	falcon_read(efx, &reg, GLB_CTL_REG_KER);
	falcon_read(efx, &temp, GLB_CTL_REG_KER);
	EFX_SET_OWORD_FIELD(reg, RST_XGTX, 1);
	EFX_SET_OWORD_FIELD(temp, RST_XGTX, 1);
	EFX_SET_OWORD_FIELD(reg, RST_XGRX, 1);
	EFX_SET_OWORD_FIELD(temp, RST_XGRX, 1);
	EFX_SET_OWORD_FIELD(reg, RST_EM, 1);
	EFX_SET_OWORD_FIELD(temp, RST_EM, 1);
	falcon_write(efx, &reg, GLB_CTL_REG_KER);
	falcon_write(efx, &temp, GLB_CTL_REG_KER);


	count = 0;
	count = 0;
	while (1) {
	while (1) {
		falcon_read(efx, &temp, GLB_CTL_REG_KER);
		falcon_read(efx, &reg, GLB_CTL_REG_KER);
		if (!EFX_OWORD_FIELD(temp, RST_XGTX) &&
		if (!EFX_OWORD_FIELD(reg, RST_XGTX) &&
		    !EFX_OWORD_FIELD(temp, RST_XGRX) &&
		    !EFX_OWORD_FIELD(reg, RST_XGRX) &&
		    !EFX_OWORD_FIELD(temp, RST_EM)) {
		    !EFX_OWORD_FIELD(reg, RST_EM)) {
			EFX_LOG(efx, "Completed MAC reset after %d loops\n",
			EFX_LOG(efx, "Completed MAC reset after %d loops\n",
				count);
				count);
			break;
			break;
@@ -1889,21 +1923,39 @@ void falcon_drain_tx_fifo(struct efx_nic *efx)


	/* If we've reset the EM block and the link is up, then
	/* If we've reset the EM block and the link is up, then
	 * we'll have to kick the XAUI link so the PHY can recover */
	 * we'll have to kick the XAUI link so the PHY can recover */
	if (efx->link_up && EFX_WORKAROUND_5147(efx))
	if (efx->link_up && EFX_IS10G(efx) && EFX_WORKAROUND_5147(efx))
		falcon_reset_xaui(efx);
		falcon_reset_xaui(efx);

	return 0;
}

void falcon_drain_tx_fifo(struct efx_nic *efx)
{
	efx_oword_t reg;

	if ((falcon_rev(efx) < FALCON_REV_B0) ||
	    (efx->loopback_mode != LOOPBACK_NONE))
		return;

	falcon_read(efx, &reg, MAC0_CTRL_REG_KER);
	/* There is no point in draining more than once */
	if (EFX_OWORD_FIELD(reg, TXFIFO_DRAIN_EN_B0))
		return;

	falcon_reset_macs(efx);
}
}


void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
void falcon_deconfigure_mac_wrapper(struct efx_nic *efx)
{
{
	efx_oword_t temp;
	efx_oword_t reg;


	if (falcon_rev(efx) < FALCON_REV_B0)
	if (falcon_rev(efx) < FALCON_REV_B0)
		return;
		return;


	/* Isolate the MAC -> RX */
	/* Isolate the MAC -> RX */
	falcon_read(efx, &temp, RX_CFG_REG_KER);
	falcon_read(efx, &reg, RX_CFG_REG_KER);
	EFX_SET_OWORD_FIELD(temp, RX_INGR_EN_B0, 0);
	EFX_SET_OWORD_FIELD(reg, RX_INGR_EN_B0, 0);
	falcon_write(efx, &temp, RX_CFG_REG_KER);
	falcon_write(efx, &reg, RX_CFG_REG_KER);


	if (!efx->link_up)
	if (!efx->link_up)
		falcon_drain_tx_fifo(efx);
		falcon_drain_tx_fifo(efx);
@@ -2030,7 +2082,8 @@ static int falcon_gmii_wait(struct efx_nic *efx)
	efx_dword_t md_stat;
	efx_dword_t md_stat;
	int count;
	int count;


	for (count = 0; count < 1000; count++) {	/* wait upto 10ms */
	/* wait upto 50ms - taken max from datasheet */
	for (count = 0; count < 5000; count++) {
		falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
		falcon_readl(efx, &md_stat, MD_STAT_REG_KER);
		if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
		if (EFX_DWORD_FIELD(md_stat, MD_BSY) == 0) {
			if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
			if (EFX_DWORD_FIELD(md_stat, MD_LNFL) != 0 ||
@@ -2206,10 +2259,59 @@ static int falcon_probe_phy(struct efx_nic *efx)
		return -1;
		return -1;
	}
	}


	efx->loopback_modes = LOOPBACKS_10G_INTERNAL | efx->phy_op->loopbacks;
	if (efx->phy_op->macs & EFX_XMAC)
		efx->loopback_modes |= ((1 << LOOPBACK_XGMII) |
					(1 << LOOPBACK_XGXS) |
					(1 << LOOPBACK_XAUI));
	if (efx->phy_op->macs & EFX_GMAC)
		efx->loopback_modes |= (1 << LOOPBACK_GMAC);
	efx->loopback_modes |= efx->phy_op->loopbacks;

	return 0;
	return 0;
}
}


int falcon_switch_mac(struct efx_nic *efx)
{
	struct efx_mac_operations *old_mac_op = efx->mac_op;
	efx_oword_t nic_stat;
	unsigned strap_val;

	/* Internal loopbacks override the phy speed setting */
	if (efx->loopback_mode == LOOPBACK_GMAC) {
		efx->link_speed = 1000;
		efx->link_fd = true;
	} else if (LOOPBACK_INTERNAL(efx)) {
		efx->link_speed = 10000;
		efx->link_fd = true;
	}

	efx->mac_op = (EFX_IS10G(efx) ?
		       &falcon_xmac_operations : &falcon_gmac_operations);
	if (old_mac_op == efx->mac_op)
		return 0;

	WARN_ON(!mutex_is_locked(&efx->mac_lock));

	/* Not all macs support a mac-level link state */
	efx->mac_up = true;

	falcon_read(efx, &nic_stat, NIC_STAT_REG);
	strap_val = EFX_IS10G(efx) ? 5 : 3;
	if (falcon_rev(efx) >= FALCON_REV_B0) {
		EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_EN, 1);
		EFX_SET_OWORD_FIELD(nic_stat, EE_STRAP_OVR, strap_val);
		falcon_write(efx, &nic_stat, NIC_STAT_REG);
	} else {
		/* Falcon A1 does not support 1G/10G speed switching
		 * and must not be used with a PHY that does. */
		BUG_ON(EFX_OWORD_FIELD(nic_stat, STRAP_PINS) != strap_val);
	}


	EFX_LOG(efx, "selected %cMAC\n", EFX_IS10G(efx) ? 'X' : 'G');
	return falcon_reset_macs(efx);
}

/* This call is responsible for hooking in the MAC and PHY operations */
/* This call is responsible for hooking in the MAC and PHY operations */
int falcon_probe_port(struct efx_nic *efx)
int falcon_probe_port(struct efx_nic *efx)
{
{
@@ -2362,6 +2464,10 @@ static struct {
	  EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
	  EFX_OWORD32(0x000003FF, 0x00000000, 0x00000000, 0x00000000) },
	{ DP_CTRL_REG,
	{ DP_CTRL_REG,
	  EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
	  EFX_OWORD32(0x00000FFF, 0x00000000, 0x00000000, 0x00000000) },
	{ GM_CFG2_REG,
	  EFX_OWORD32(0x00007337, 0x00000000, 0x00000000, 0x00000000) },
	{ GMF_CFG0_REG,
	  EFX_OWORD32(0x00001F1F, 0x00000000, 0x00000000, 0x00000000) },
	{ XM_GLB_CFG_REG,
	{ XM_GLB_CFG_REG,
	  EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
	  EFX_OWORD32(0x00000C68, 0x00000000, 0x00000000, 0x00000000) },
	{ XM_TX_CFG_REG,
	{ XM_TX_CFG_REG,
@@ -2687,6 +2793,7 @@ static int falcon_probe_nvconfig(struct efx_nic *efx)
static int falcon_probe_nic_variant(struct efx_nic *efx)
static int falcon_probe_nic_variant(struct efx_nic *efx)
{
{
	efx_oword_t altera_build;
	efx_oword_t altera_build;
	efx_oword_t nic_stat;


	falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
	falcon_read(efx, &altera_build, ALTERA_BUILD_REG_KER);
	if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
	if (EFX_OWORD_FIELD(altera_build, VER_ALL)) {
@@ -2694,27 +2801,20 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
		return -ENODEV;
		return -ENODEV;
	}
	}


	falcon_read(efx, &nic_stat, NIC_STAT_REG);

	switch (falcon_rev(efx)) {
	switch (falcon_rev(efx)) {
	case FALCON_REV_A0:
	case FALCON_REV_A0:
	case 0xff:
	case 0xff:
		EFX_ERR(efx, "Falcon rev A0 not supported\n");
		EFX_ERR(efx, "Falcon rev A0 not supported\n");
		return -ENODEV;
		return -ENODEV;


	case FALCON_REV_A1:{
	case FALCON_REV_A1:
		efx_oword_t nic_stat;

		falcon_read(efx, &nic_stat, NIC_STAT_REG);

		if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
		if (EFX_OWORD_FIELD(nic_stat, STRAP_PCIE) == 0) {
			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
			EFX_ERR(efx, "Falcon rev A1 PCI-X not supported\n");
			return -ENODEV;
			return -ENODEV;
		}
		}
		if (!EFX_OWORD_FIELD(nic_stat, STRAP_10G)) {
			EFX_ERR(efx, "1G mode not supported\n");
			return -ENODEV;
		}
		break;
		break;
	}


	case FALCON_REV_B0:
	case FALCON_REV_B0:
		break;
		break;
@@ -2724,6 +2824,9 @@ static int falcon_probe_nic_variant(struct efx_nic *efx)
		return -ENODEV;
		return -ENODEV;
	}
	}


	/* Initial assumed speed */
	efx->link_speed = EFX_OWORD_FIELD(nic_stat, STRAP_10G) ? 10000 : 1000;

	return 0;
	return 0;
}
}


Loading