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: Ben Hutchings <bhutchings@solarflare.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
diff --git a/drivers/net/sfc/efx.c b/drivers/net/sfc/efx.c
index 90820d4..7214ea6 100644
--- a/drivers/net/sfc/efx.c
+++ b/drivers/net/sfc/efx.c
@@ -27,7 +27,6 @@
 #include "efx.h"
 #include "mdio_10g.h"
 #include "falcon.h"
-#include "mac.h"
 
 #define EFX_MAX_MTU (9 * 1024)
 
@@ -575,10 +574,28 @@
 		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 */
 	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
@@ -648,18 +665,25 @@
 
 	EFX_LOG(efx, "init port\n");
 
-	/* Initialise the MAC and PHY */
-	rc = falcon_init_xmac(efx);
+	rc = efx->phy_op->init(efx);
 	if (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->stats_enabled = true;
-
-	/* Reconfigure port to program MAC registers */
-	falcon_reconfigure_xmac(efx);
-
 	return 0;
+
+fail:
+	efx->phy_op->fini(efx);
+	return rc;
 }
 
 /* Allow efx_reconfigure_port() to be scheduled, and close the window
@@ -702,7 +726,7 @@
 	if (!efx->port_initialized)
 		return;
 
-	falcon_fini_xmac(efx);
+	efx->phy_op->fini(efx);
 	efx->port_initialized = false;
 
 	efx->link_up = false;
@@ -1179,7 +1203,6 @@
 {
 	struct efx_nic *efx = container_of(data, struct efx_nic,
 					   monitor_work.work);
-	int rc = 0;
 
 	EFX_TRACE(efx, "hardware monitor executing on CPU %d\n",
 		  raw_smp_processor_id());
@@ -1195,7 +1218,7 @@
 	}
 
 	if (efx->port_enabled)
-		rc = falcon_check_xmac(efx);
+		efx->mac_op->check_hw(efx);
 	mutex_unlock(&efx->mac_lock);
 
 	queue_delayed_work(efx->workqueue, &efx->monitor_work,
@@ -1331,7 +1354,7 @@
 	if (!spin_trylock(&efx->stats_lock))
 		return stats;
 	if (efx->stats_enabled) {
-		falcon_update_stats_xmac(efx);
+		efx->mac_op->update_stats(efx);
 		falcon_update_nic_stats(efx);
 	}
 	spin_unlock(&efx->stats_lock);
@@ -1519,7 +1542,7 @@
 	netif_carrier_off(efx->net_dev);
 
 	/* Clear MAC statistics */
-	falcon_update_stats_xmac(efx);
+	efx->mac_op->update_stats(efx);
 	memset(&efx->mac_stats, 0, sizeof(efx->mac_stats));
 
 	rc = register_netdev(net_dev);
@@ -1575,8 +1598,6 @@
  * before reset.  */
 void efx_reset_down(struct efx_nic *efx, struct ethtool_cmd *ecmd)
 {
-	int rc;
-
 	EFX_ASSERT_RESET_SERIALISED(efx);
 
 	/* The net_dev->get_stats handler is quite slow, and will fail
@@ -1589,9 +1610,7 @@
 	mutex_lock(&efx->mac_lock);
 	mutex_lock(&efx->spi_lock);
 
-	rc = falcon_xmac_get_settings(efx, ecmd);
-	if (rc)
-		EFX_ERR(efx, "could not back up PHY settings\n");
+	efx->phy_op->get_settings(efx, ecmd);
 
 	efx_fini_channels(efx);
 }
@@ -1616,7 +1635,7 @@
 	if (ok) {
 		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");
 	}
 
@@ -1779,6 +1798,10 @@
 void efx_port_dummy_op_void(struct efx_nic *efx) {}
 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 = {
 	.init		 = efx_port_dummy_op_int,
 	.reconfigure	 = efx_port_dummy_op_void,
@@ -1831,6 +1854,7 @@
 	spin_lock_init(&efx->netif_stop_lock);
 	spin_lock_init(&efx->stats_lock);
 	mutex_init(&efx->mac_lock);
+	efx->mac_op = &efx_dummy_mac_operations;
 	efx->phy_op = &efx_dummy_phy_operations;
 	efx->mii.dev = net_dev;
 	INIT_WORK(&efx->reconfigure_work, efx_reconfigure_work);